diff options
| author | Jiri Pirko <jiri@resnulli.us> | 2012-08-17 00:00:48 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2012-08-20 05:40:48 -0400 |
| commit | 1d76efe1577b4323609b1bcbfafa8b731eda071a (patch) | |
| tree | ddf6fddeee02ad33f304dd5479f57208245a3f88 | |
| parent | 4c6de2fedc321e17487b74547ad9f73f248faaac (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>
| -rw-r--r-- | drivers/net/team/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/net/team/team.c | 89 | ||||
| -rw-r--r-- | drivers/net/team/team_mode_broadcast.c | 8 | ||||
| -rw-r--r-- | drivers/net/team/team_mode_roundrobin.c | 8 | ||||
| -rw-r--r-- | include/linux/if_team.h | 4 |
5 files changed, 79 insertions, 34 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 | */ |
| 60 | static int __set_port_mac(struct net_device *port_dev, | 60 | static 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 | ||
| 70 | static int team_port_set_orig_mac(struct team_port *port) | 70 | static 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 | ||
| 75 | int team_port_set_team_mac(struct team_port *port) | 75 | int 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 | } |
| 79 | EXPORT_SYMBOL(team_port_set_team_mac); | 79 | EXPORT_SYMBOL(team_port_set_team_dev_addr); |
| 80 | 80 | ||
| 81 | static void team_refresh_port_linkup(struct team_port *port) | 81 | static 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 | ||
| 967 | static void __team_port_change_check(struct team_port *port, bool linkup); | 967 | static void __team_port_change_check(struct team_port *port, bool linkup); |
| 968 | static int team_dev_type_check_change(struct net_device *dev, | ||
| 969 | struct net_device *port_dev); | ||
| 968 | 970 | ||
| 969 | static int team_port_add(struct team *team, struct net_device *port_dev) | 971 | static 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 | ||
| 1090 | err_dev_open: | 1095 | err_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 | ||
| 1094 | err_port_enter: | 1099 | err_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 | ||
| 1478 | static int team_set_mac_address(struct net_device *dev, void *p) | 1483 | static 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 | ||
| 1727 | static 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; | ||
