aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team/team.c
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2012-08-17 00:00:48 -0400
committerDavid S. Miller <davem@davemloft.net>2012-08-20 05:40:48 -0400
commit1d76efe1577b4323609b1bcbfafa8b731eda071a (patch)
treeddf6fddeee02ad33f304dd5479f57208245a3f88 /drivers/net/team/team.c
parent4c6de2fedc321e17487b74547ad9f73f248faaac (diff)
team: add support for non-ethernet devices
This is resolved by two things: 1) allow dev_addr of different length than ETH_ALEN 2) during port add, check for dev->type and change it if necessary Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/team/team.c')
-rw-r--r--drivers/net/team/team.c89
1 files changed, 67 insertions, 22 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index ba10c469b02b..bc36d13c2675 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -54,29 +54,29 @@ static struct team_port *team_port_get_rtnl(const struct net_device *dev)
54} 54}
55 55
56/* 56/*
57 * Since the ability to change mac address for open port device is tested in 57 * Since the ability to change device address for open port device is tested in
58 * team_port_add, this function can be called without control of return value 58 * team_port_add, this function can be called without control of return value
59 */ 59 */
60static int __set_port_mac(struct net_device *port_dev, 60static int __set_port_dev_addr(struct net_device *port_dev,
61 const unsigned char *dev_addr) 61 const unsigned char *dev_addr)
62{ 62{
63 struct sockaddr addr; 63 struct sockaddr addr;
64 64
65 memcpy(addr.sa_data, dev_addr, ETH_ALEN); 65 memcpy(addr.sa_data, dev_addr, port_dev->addr_len);
66 addr.sa_family = ARPHRD_ETHER; 66 addr.sa_family = port_dev->type;
67 return dev_set_mac_address(port_dev, &addr); 67 return dev_set_mac_address(port_dev, &addr);
68} 68}
69 69
70static int team_port_set_orig_mac(struct team_port *port) 70static int team_port_set_orig_dev_addr(struct team_port *port)
71{ 71{
72 return __set_port_mac(port->dev, port->orig.dev_addr); 72 return __set_port_dev_addr(port->dev, port->orig.dev_addr);
73} 73}
74 74
75int team_port_set_team_mac(struct team_port *port) 75int team_port_set_team_dev_addr(struct team_port *port)
76{ 76{
77 return __set_port_mac(port->dev, port->team->dev->dev_addr); 77 return __set_port_dev_addr(port->dev, port->team->dev->dev_addr);
78} 78}
79EXPORT_SYMBOL(team_port_set_team_mac); 79EXPORT_SYMBOL(team_port_set_team_dev_addr);
80 80
81static void team_refresh_port_linkup(struct team_port *port) 81static void team_refresh_port_linkup(struct team_port *port)
82{ 82{
@@ -965,6 +965,8 @@ static struct netpoll_info *team_netpoll_info(struct team *team)
965#endif 965#endif
966 966
967static void __team_port_change_check(struct team_port *port, bool linkup); 967static void __team_port_change_check(struct team_port *port, bool linkup);
968static int team_dev_type_check_change(struct net_device *dev,
969 struct net_device *port_dev);
968 970
969static int team_port_add(struct team *team, struct net_device *port_dev) 971static int team_port_add(struct team *team, struct net_device *port_dev)
970{ 972{
@@ -973,9 +975,8 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
973 char *portname = port_dev->name; 975 char *portname = port_dev->name;
974 int err; 976 int err;
975 977
976 if (port_dev->flags & IFF_LOOPBACK || 978 if (port_dev->flags & IFF_LOOPBACK) {
977 port_dev->type != ARPHRD_ETHER) { 979 netdev_err(dev, "Device %s is loopback device. Loopback devices can't be added as a team port\n",
978 netdev_err(dev, "Device %s is of an unsupported type\n",
979 portname); 980 portname);
980 return -EINVAL; 981 return -EINVAL;
981 } 982 }
@@ -986,6 +987,10 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
986 return -EBUSY; 987 return -EBUSY;
987 } 988 }
988 989
990 err = team_dev_type_check_change(dev, port_dev);
991 if (err)
992 return err;
993
989 if (port_dev->flags & IFF_UP) { 994 if (port_dev->flags & IFF_UP) {
990 netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n", 995 netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n",
991 portname); 996 portname);
@@ -1008,7 +1013,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
1008 goto err_set_mtu; 1013 goto err_set_mtu;
1009 } 1014 }
1010 1015
1011 memcpy(port->orig.dev_addr, port_dev->dev_addr, ETH_ALEN); 1016 memcpy(port->orig.dev_addr, port_dev->dev_addr, port_dev->addr_len);
1012 1017
1013 err = team_port_enter(team, port); 1018 err = team_port_enter(team, port);
1014 if (err) { 1019 if (err) {
@@ -1089,7 +1094,7 @@ err_vids_add:
1089 1094
1090err_dev_open: 1095err_dev_open:
1091 team_port_leave(team, port); 1096 team_port_leave(team, port);
1092 team_port_set_orig_mac(port); 1097 team_port_set_orig_dev_addr(port);
1093 1098
1094err_port_enter: 1099err_port_enter:
1095 dev_set_mtu(port_dev, port->orig.mtu); 1100 dev_set_mtu(port_dev, port->orig.mtu);
@@ -1126,7 +1131,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
1126 vlan_vids_del_by_dev(port_dev, dev); 1131 vlan_vids_del_by_dev(port_dev, dev);
1127 dev_close(port_dev); 1132 dev_close(port_dev);
1128 team_port_leave(team, port); 1133 team_port_leave(team, port);
1129 team_port_set_orig_mac(port); 1134 team_port_set_orig_dev_addr(port);
1130 dev_set_mtu(port_dev, port->orig.mtu); 1135 dev_set_mtu(port_dev, port->orig.mtu);
1131 synchronize_rcu(); 1136 synchronize_rcu();
1132 kfree(port); 1137 kfree(port);
@@ -1477,17 +1482,18 @@ static void team_set_rx_mode(struct net_device *dev)
1477 1482
1478static int team_set_mac_address(struct net_device *dev, void *p) 1483static int team_set_mac_address(struct net_device *dev, void *p)
1479{ 1484{
1485 struct sockaddr *addr = p;
1480 struct team *team = netdev_priv(dev); 1486 struct team *team = netdev_priv(dev);
1481 struct team_port *port; 1487 struct team_port *port;
1482 int err;
1483 1488
1484 err = eth_mac_addr(dev, p); 1489 if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
1485 if (err) 1490 return -EADDRNOTAVAIL;
1486 return err; 1491 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
1492 dev->addr_assign_type &= ~NET_ADDR_RANDOM;
1487 rcu_read_lock(); 1493 rcu_read_lock();
1488 list_for_each_entry_rcu(port, &team->port_list, list) 1494 list_for_each_entry_rcu(port, &team->port_list, list)
1489 if (team->ops.port_change_mac) 1495 if (team->ops.port_change_dev_addr)
1490 team->ops.port_change_mac(team, port); 1496 team->ops.port_change_dev_addr(team, port);
1491 rcu_read_unlock(); 1497 rcu_read_unlock();
1492 return 0; 1498 return 0;
1493} 1499}
@@ -1718,6 +1724,45 @@ static const struct net_device_ops team_netdev_ops = {
1718 * rt netlink interface 1724 * rt netlink interface
1719 ***********************/ 1725 ***********************/
1720 1726
1727static void team_setup_by_port(struct net_device *dev,
1728 struct net_device *port_dev)
1729{
1730 dev->header_ops = port_dev->header_ops;
1731 dev->type = port_dev->type;
1732 dev->hard_header_len = port_dev->hard_header_len;
1733 dev->addr_len = port_dev->addr_len;
1734 dev->mtu = port_dev->mtu;
1735 memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
1736 memcpy(dev->dev_addr, port_dev->dev_addr, port_dev->addr_len);
1737 dev->addr_assign_type &= ~NET_ADDR_RANDOM;
1738}
1739
1740static int team_dev_type_check_change(struct net_device *dev,
1741 struct net_device *port_dev)
1742{
1743 struct team *team = netdev_priv(dev);
1744 char *portname = port_dev->name;
1745 int err;
1746
1747 if (dev->type == port_dev->type)
1748 return 0;
1749 if (!list_empty(&team->port_list)) {
1750 netdev_err(dev, "Device %s is of different type\n", portname);
1751 return -EBUSY;
1752 }
1753 err = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev);
1754 err = notifier_to_errno(err);
1755 if (err) {
1756 netdev_err(dev, "Refused to change device type\n");
1757 return err;
1758 }
1759 dev_uc_flush(dev);
1760 dev_mc_flush(dev);
1761 team_setup_by_port(dev, port_dev);
1762 call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);
1763 return 0;
1764}
1765
1721static void team_setup(struct net_device *dev) 1766static void team_setup(struct net_device *dev)
1722{ 1767{
1723 ether_setup(dev); 1768 ether_setup(dev);