aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team
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
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')
-rw-r--r--drivers/net/team/Kconfig4
-rw-r--r--drivers/net/team/team.c89
-rw-r--r--drivers/net/team/team_mode_broadcast.c8
-rw-r--r--drivers/net/team/team_mode_roundrobin.c8
4 files changed, 77 insertions, 32 deletions
diff --git a/drivers/net/team/Kconfig b/drivers/net/team/Kconfig
index 6a7260b03a1e..6b08bd419fba 100644
--- a/drivers/net/team/Kconfig
+++ b/drivers/net/team/Kconfig
@@ -21,7 +21,7 @@ config NET_TEAM_MODE_BROADCAST
21 ---help--- 21 ---help---
22 Basic mode where packets are transmitted always by all suitable ports. 22 Basic mode where packets are transmitted always by all suitable ports.
23 23
24 All added ports are setup to have team's mac address. 24 All added ports are setup to have team's device address.
25 25
26 To compile this team mode as a module, choose M here: the module 26 To compile this team mode as a module, choose M here: the module
27 will be called team_mode_broadcast. 27 will be called team_mode_broadcast.
@@ -33,7 +33,7 @@ config NET_TEAM_MODE_ROUNDROBIN
33 Basic mode where port used for transmitting packets is selected in 33 Basic mode where port used for transmitting packets is selected in
34 round-robin fashion using packet counter. 34 round-robin fashion using packet counter.
35 35
36 All added ports are setup to have team's mac address. 36 All added ports are setup to have team's device address.
37 37
38 To compile this team mode as a module, choose M here: the module 38 To compile this team mode as a module, choose M here: the module
39 will be called team_mode_roundrobin. 39 will be called team_mode_roundrobin.
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);
diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c
index c96e4d2967f0..9db0171e9366 100644
--- a/drivers/net/team/team_mode_broadcast.c
+++ b/drivers/net/team/team_mode_broadcast.c
@@ -48,18 +48,18 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb)
48 48
49static int bc_port_enter(struct team *team, struct team_port *port) 49static int bc_port_enter(struct team *team, struct team_port *port)
50{ 50{
51 return team_port_set_team_mac(port); 51 return team_port_set_team_dev_addr(port);
52} 52}
53 53
54static void bc_port_change_mac(struct team *team, struct team_port *port) 54static void bc_port_change_dev_addr(struct team *team, struct team_port *port)
55{ 55{
56 team_port_set_team_mac(port); 56 team_port_set_team_dev_addr(port);
57} 57}
58 58
59static const struct team_mode_ops bc_mode_ops = { 59static const struct team_mode_ops bc_mode_ops = {
60 .transmit = bc_transmit, 60 .transmit = bc_transmit,
61 .port_enter = bc_port_enter, 61 .port_enter = bc_port_enter,
62 .port_change_mac = bc_port_change_mac, 62 .port_change_dev_addr = bc_port_change_dev_addr,
63}; 63};
64 64
65static const struct team_mode bc_mode = { 65static const struct team_mode bc_mode = {
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
index ad7ed0ec544c..105135aa8f05 100644
--- a/drivers/net/team/team_mode_roundrobin.c
+++ b/drivers/net/team/team_mode_roundrobin.c
@@ -66,18 +66,18 @@ drop:
66 66
67static int rr_port_enter(struct team *team, struct team_port *port) 67static int rr_port_enter(struct team *team, struct team_port *port)
68{ 68{
69 return team_port_set_team_mac(port); 69 return team_port_set_team_dev_addr(port);
70} 70}
71 71
72static void rr_port_change_mac(struct team *team, struct team_port *port) 72static void rr_port_change_dev_addr(struct team *team, struct team_port *port)
73{ 73{
74 team_port_set_team_mac(port); 74 team_port_set_team_dev_addr(port);
75} 75}
76 76
77static const struct team_mode_ops rr_mode_ops = { 77static const struct team_mode_ops rr_mode_ops = {
78 .transmit = rr_transmit, 78 .transmit = rr_transmit,
79 .port_enter = rr_port_enter, 79 .port_enter = rr_port_enter,
80 .port_change_mac = rr_port_change_mac, 80 .port_change_dev_addr = rr_port_change_dev_addr,
81}; 81};
82 82
83static const struct team_mode rr_mode = { 83static const struct team_mode rr_mode = {