Currently, switchdev users of br_fdb_replay pass a pointer to their atomic notifier block for the bridge to replay the FDB entries on the port and local to the bridge, and the bridge whispers those FDB entries to that driver only, and not publicly on the switchdev atomic notifier call chain. Going forward we would like to introduce push-mode FDB replays for all switchdev drivers, and there are at least two reasons why the current setup is not ideal. First and most obvious, every driver would have to be changed to pass its atomic notifier block to the switchdev_bridge_port_offload() and switchdev_bridge_port_unoffload() calls, which gets a bit cumbersome. The second is that it wasn't a good idea in the first place for the other switchdev drivers to not hear anything about the FDB entries on foreign interfaces. For example, DSA treats these FDB entries in a special way since commit 3068d466a67e ("net: dsa: sync static FDB entries on foreign interfaces to hardware"). With the static FDB entry addition being public on everybody's notifier block but the deletion being whispered only to the driver whose port leaves the bridge, DSA would have a lingering static FDB entry pointing towards the host. Making br_fdb_replay() use the atomic switchdev call chain solves both problems. Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx> --- include/linux/if_bridge.h | 4 ++-- net/bridge/br_fdb.c | 43 +++++++-------------------------------- net/dsa/dsa_priv.h | 1 - net/dsa/port.c | 10 ++++----- net/dsa/slave.c | 2 +- 5 files changed, 14 insertions(+), 46 deletions(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 13acc1ff476c..8d4a157d249d 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -168,7 +168,7 @@ bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag); u8 br_port_get_stp_state(const struct net_device *dev); clock_t br_get_ageing_time(const struct net_device *br_dev); int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev, - bool adding, struct notifier_block *nb); + bool adding); #else static inline struct net_device * br_fdb_find_port(const struct net_device *br_dev, @@ -200,7 +200,7 @@ static inline clock_t br_get_ageing_time(const struct net_device *br_dev) static inline int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev, - bool adding, struct notifier_block *nb) + bool adding) { return -EOPNOTSUPP; } diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index c93a2b3a0ad8..4434aee4cfbc 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -732,31 +732,12 @@ static inline size_t fdb_nlmsg_size(void) + nla_total_size(sizeof(u8)); /* NFEA_ACTIVITY_NOTIFY */ } -static int br_fdb_replay_one(struct notifier_block *nb, - const struct net_bridge_fdb_entry *fdb, - struct net_device *dev, unsigned long action) -{ - struct switchdev_notifier_fdb_info item; - int err; - - item.addr = fdb->key.addr.addr; - item.vid = fdb->key.vlan_id; - item.added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags); - item.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags); - item.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags); - item.info.dev = dev; - - err = nb->notifier_call(nb, action, &item); - return notifier_to_errno(err); -} - int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev, - bool adding, struct notifier_block *nb) + bool adding) { struct net_bridge_fdb_entry *fdb; struct net_bridge *br; - unsigned long action; - int err = 0; + int type; if (!netif_is_bridge_master(br_dev)) return -EINVAL; @@ -767,28 +748,18 @@ int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev, br = netdev_priv(br_dev); if (adding) - action = SWITCHDEV_FDB_ADD_TO_DEVICE; + type = RTM_NEWNEIGH; else - action = SWITCHDEV_FDB_DEL_TO_DEVICE; + type = RTM_DELNEIGH; rcu_read_lock(); - hlist_for_each_entry_rcu(fdb, &br->fdb_list, fdb_node) { - const struct net_bridge_port *dst = READ_ONCE(fdb->dst); - struct net_device *dst_dev; - - dst_dev = dst ? dst->dev : br->dev; - if (dst_dev != br_dev && dst_dev != dev) - continue; - - err = br_fdb_replay_one(nb, fdb, dst_dev, action); - if (err) - break; - } + hlist_for_each_entry_rcu(fdb, &br->fdb_list, fdb_node) + br_switchdev_fdb_notify(br, fdb, type); rcu_read_unlock(); - return err; + return 0; } EXPORT_SYMBOL_GPL(br_fdb_replay); diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index f201c33980bf..20003512d8f8 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -285,7 +285,6 @@ static inline bool dsa_tree_offloads_bridge_port(struct dsa_switch_tree *dst, /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; -extern struct notifier_block dsa_slave_switchdev_notifier; extern struct notifier_block dsa_slave_switchdev_blocking_notifier; void dsa_slave_mii_bus_init(struct dsa_switch *ds); diff --git a/net/dsa/port.c b/net/dsa/port.c index 34b7f64348c2..ccf11bc518fe 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -200,13 +200,12 @@ static int dsa_port_switchdev_sync(struct dsa_port *dp, return err; /* Forwarding and termination FDB entries on the port */ - err = br_fdb_replay(br, brport_dev, true, - &dsa_slave_switchdev_notifier); + err = br_fdb_replay(br, brport_dev, true); if (err && err != -EOPNOTSUPP) return err; /* Termination FDB entries on the bridge itself */ - err = br_fdb_replay(br, br, true, &dsa_slave_switchdev_notifier); + err = br_fdb_replay(br, br, true); if (err && err != -EOPNOTSUPP) return err; @@ -232,13 +231,12 @@ static int dsa_port_switchdev_unsync_objs(struct dsa_port *dp, return err; /* Forwarding and termination FDB entries on the port */ - err = br_fdb_replay(br, brport_dev, false, - &dsa_slave_switchdev_notifier); + err = br_fdb_replay(br, brport_dev, false); if (err && err != -EOPNOTSUPP) return err; /* Termination FDB entries on the bridge itself */ - err = br_fdb_replay(br, br, false, &dsa_slave_switchdev_notifier); + err = br_fdb_replay(br, br, false); if (err && err != -EOPNOTSUPP) return err; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index ffbba1e71551..461c80bc066a 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2517,7 +2517,7 @@ static struct notifier_block dsa_slave_nb __read_mostly = { .notifier_call = dsa_slave_netdevice_event, }; -struct notifier_block dsa_slave_switchdev_notifier = { +static struct notifier_block dsa_slave_switchdev_notifier = { .notifier_call = dsa_slave_switchdev_event, }; -- 2.25.1