Commit d7d3c05135f37d8fdf73f9966d27155cada36e56
Committed by
David S. Miller
1 parent
72b603ee8c
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
team: set IFF_TEAM_PORT priv_flag after rx_handler is registered
When one tries to add eth as a port into team and that eth is already in use by other rx_handler device (macvlan, bond, bridge, ...) a bug in team_port_add() causes that IFF_TEAM_PORT flag is set before rx_handler is registered. In between, netdev nofifier is called and team_device_event() sees IFF_TEAM_PORT and thinks that rx_handler_data pointer is set to team_port. But it isn't. Fix this by reordering rx_handler register and IFF_TEAM_PORT priv flag set so it is very similar to how bonding does this. Reported-by: Erik Hugne <erik.hugne@ericsson.com> Fixes: 3d249d4ca7 "net: introduce ethernet teaming device" Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 30 additions and 14 deletions Side-by-side Diff
drivers/net/team/team.c
... | ... | @@ -1003,7 +1003,6 @@ |
1003 | 1003 | int err = 0; |
1004 | 1004 | |
1005 | 1005 | dev_hold(team->dev); |
1006 | - port->dev->priv_flags |= IFF_TEAM_PORT; | |
1007 | 1006 | if (team->ops.port_enter) { |
1008 | 1007 | err = team->ops.port_enter(team, port); |
1009 | 1008 | if (err) { |
... | ... | @@ -1016,7 +1015,6 @@ |
1016 | 1015 | return 0; |
1017 | 1016 | |
1018 | 1017 | err_port_enter: |
1019 | - port->dev->priv_flags &= ~IFF_TEAM_PORT; | |
1020 | 1018 | dev_put(team->dev); |
1021 | 1019 | |
1022 | 1020 | return err; |
... | ... | @@ -1026,7 +1024,6 @@ |
1026 | 1024 | { |
1027 | 1025 | if (team->ops.port_leave) |
1028 | 1026 | team->ops.port_leave(team, port); |
1029 | - port->dev->priv_flags &= ~IFF_TEAM_PORT; | |
1030 | 1027 | dev_put(team->dev); |
1031 | 1028 | } |
1032 | 1029 | |
... | ... | @@ -1075,6 +1072,25 @@ |
1075 | 1072 | } |
1076 | 1073 | #endif |
1077 | 1074 | |
1075 | +static int team_upper_dev_link(struct net_device *dev, | |
1076 | + struct net_device *port_dev) | |
1077 | +{ | |
1078 | + int err; | |
1079 | + | |
1080 | + err = netdev_master_upper_dev_link(port_dev, dev); | |
1081 | + if (err) | |
1082 | + return err; | |
1083 | + port_dev->priv_flags |= IFF_TEAM_PORT; | |
1084 | + return 0; | |
1085 | +} | |
1086 | + | |
1087 | +static void team_upper_dev_unlink(struct net_device *dev, | |
1088 | + struct net_device *port_dev) | |
1089 | +{ | |
1090 | + netdev_upper_dev_unlink(port_dev, dev); | |
1091 | + port_dev->priv_flags &= ~IFF_TEAM_PORT; | |
1092 | +} | |
1093 | + | |
1078 | 1094 | static void __team_port_change_port_added(struct team_port *port, bool linkup); |
1079 | 1095 | static int team_dev_type_check_change(struct net_device *dev, |
1080 | 1096 | struct net_device *port_dev); |
... | ... | @@ -1161,13 +1177,6 @@ |
1161 | 1177 | goto err_enable_netpoll; |
1162 | 1178 | } |
1163 | 1179 | |
1164 | - err = netdev_master_upper_dev_link(port_dev, dev); | |
1165 | - if (err) { | |
1166 | - netdev_err(dev, "Device %s failed to set upper link\n", | |
1167 | - portname); | |
1168 | - goto err_set_upper_link; | |
1169 | - } | |
1170 | - | |
1171 | 1180 | err = netdev_rx_handler_register(port_dev, team_handle_frame, |
1172 | 1181 | port); |
1173 | 1182 | if (err) { |
... | ... | @@ -1176,6 +1185,13 @@ |
1176 | 1185 | goto err_handler_register; |
1177 | 1186 | } |
1178 | 1187 | |
1188 | + err = team_upper_dev_link(dev, port_dev); | |
1189 | + if (err) { | |
1190 | + netdev_err(dev, "Device %s failed to set upper link\n", | |
1191 | + portname); | |
1192 | + goto err_set_upper_link; | |
1193 | + } | |
1194 | + | |
1179 | 1195 | err = __team_option_inst_add_port(team, port); |
1180 | 1196 | if (err) { |
1181 | 1197 | netdev_err(dev, "Device %s failed to add per-port options\n", |
1182 | 1198 | |
... | ... | @@ -1195,12 +1211,12 @@ |
1195 | 1211 | return 0; |
1196 | 1212 | |
1197 | 1213 | err_option_port_add: |
1214 | + team_upper_dev_unlink(dev, port_dev); | |
1215 | + | |
1216 | +err_set_upper_link: | |
1198 | 1217 | netdev_rx_handler_unregister(port_dev); |
1199 | 1218 | |
1200 | 1219 | err_handler_register: |
1201 | - netdev_upper_dev_unlink(port_dev, dev); | |
1202 | - | |
1203 | -err_set_upper_link: | |
1204 | 1220 | team_port_disable_netpoll(port); |
1205 | 1221 | |
1206 | 1222 | err_enable_netpoll: |
1207 | 1223 | |
... | ... | @@ -1239,8 +1255,8 @@ |
1239 | 1255 | |
1240 | 1256 | team_port_disable(team, port); |
1241 | 1257 | list_del_rcu(&port->list); |
1258 | + team_upper_dev_unlink(dev, port_dev); | |
1242 | 1259 | netdev_rx_handler_unregister(port_dev); |
1243 | - netdev_upper_dev_unlink(port_dev, dev); | |
1244 | 1260 | team_port_disable_netpoll(port); |
1245 | 1261 | vlan_vids_del_by_dev(port_dev, dev); |
1246 | 1262 | dev_uc_unsync(port_dev, dev); |