Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: sync up switchdev objects and port attributes when joining the bridge

If we join an already-created bridge port, such as a bond master
interface, then we can miss the initial switchdev notifications emitted
by the bridge for this port, while it wasn't offloaded by anybody.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vladimir Oltean and committed by
David S. Miller
010e269f 5961d6a1

+51 -2
+3
net/dsa/dsa_priv.h
··· 262 262 263 263 /* slave.c */ 264 264 extern const struct dsa_device_ops notag_netdev_ops; 265 + extern struct notifier_block dsa_slave_switchdev_notifier; 266 + extern struct notifier_block dsa_slave_switchdev_blocking_notifier; 267 + 265 268 void dsa_slave_mii_bus_init(struct dsa_switch *ds); 266 269 int dsa_slave_create(struct dsa_port *dp); 267 270 void dsa_slave_destroy(struct net_device *slave_dev);
+46
net/dsa/port.c
··· 170 170 static int dsa_port_switchdev_sync(struct dsa_port *dp, 171 171 struct netlink_ext_ack *extack) 172 172 { 173 + struct net_device *brport_dev = dsa_port_to_bridge_port(dp); 174 + struct net_device *br = dp->bridge_dev; 173 175 int err; 174 176 175 177 err = dsa_port_inherit_brport_flags(dp, extack); 176 178 if (err) 179 + return err; 180 + 181 + err = dsa_port_set_state(dp, br_port_get_stp_state(brport_dev)); 182 + if (err && err != -EOPNOTSUPP) 183 + return err; 184 + 185 + err = dsa_port_vlan_filtering(dp, br_vlan_enabled(br), extack); 186 + if (err && err != -EOPNOTSUPP) 187 + return err; 188 + 189 + err = dsa_port_mrouter(dp->cpu_dp, br_multicast_router(br), extack); 190 + if (err && err != -EOPNOTSUPP) 191 + return err; 192 + 193 + err = dsa_port_ageing_time(dp, br_get_ageing_time(br)); 194 + if (err && err != -EOPNOTSUPP) 195 + return err; 196 + 197 + err = br_mdb_replay(br, brport_dev, 198 + &dsa_slave_switchdev_blocking_notifier, 199 + extack); 200 + if (err && err != -EOPNOTSUPP) 201 + return err; 202 + 203 + err = br_fdb_replay(br, brport_dev, &dsa_slave_switchdev_notifier); 204 + if (err && err != -EOPNOTSUPP) 205 + return err; 206 + 207 + err = br_vlan_replay(br, brport_dev, 208 + &dsa_slave_switchdev_blocking_notifier, 209 + extack); 210 + if (err && err != -EOPNOTSUPP) 177 211 return err; 178 212 179 213 return 0; ··· 232 198 * so allow it to be in BR_STATE_FORWARDING to be kept functional 233 199 */ 234 200 dsa_port_set_state_now(dp, BR_STATE_FORWARDING); 201 + 202 + /* VLAN filtering is handled by dsa_switch_bridge_leave */ 203 + 204 + /* Some drivers treat the notification for having a local multicast 205 + * router by allowing multicast to be flooded to the CPU, so we should 206 + * allow this in standalone mode too. 207 + */ 208 + dsa_port_mrouter(dp->cpu_dp, true, NULL); 209 + 210 + /* Ageing time may be global to the switch chip, so don't change it 211 + * here because we have no good reason (or value) to change it to. 212 + */ 235 213 } 236 214 237 215 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
+2 -2
net/dsa/slave.c
··· 2392 2392 .notifier_call = dsa_slave_netdevice_event, 2393 2393 }; 2394 2394 2395 - static struct notifier_block dsa_slave_switchdev_notifier = { 2395 + struct notifier_block dsa_slave_switchdev_notifier = { 2396 2396 .notifier_call = dsa_slave_switchdev_event, 2397 2397 }; 2398 2398 2399 - static struct notifier_block dsa_slave_switchdev_blocking_notifier = { 2399 + struct notifier_block dsa_slave_switchdev_blocking_notifier = { 2400 2400 .notifier_call = dsa_slave_switchdev_blocking_event, 2401 2401 }; 2402 2402