From 9264e4ad26112a496398159d200af017e37d97e3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 8 Aug 2021 17:35:25 +0300 Subject: [PATCH] net: dsa: flush the dynamic FDB of the software bridge when fast ageing a port Currently, when DSA performs fast ageing on a port, 'bridge fdb' shows us that the 'self' entries (corresponding to the hardware bridge, as printed by dsa_slave_fdb_dump) are deleted, but the 'master' entries (corresponding to the software bridge) aren't. Indeed, searching through the bridge driver, neither the brport_attr_learning handler nor the IFLA_BRPORT_LEARNING handler call br_fdb_delete_by_port. However, br_stp_disable_port does, which is one of the paths which DSA uses to trigger a fast ageing process anyway. There is, however, one other very promising caller of br_fdb_delete_by_port, and that is the bridge driver's handler of the SWITCHDEV_FDB_FLUSH_TO_BRIDGE atomic notifier. Currently the s390/qeth HiperSockets card driver is the only user of this. I can't say I understand that driver's architecture or interaction with the bridge, but it appears to not be a switchdev driver in the traditional sense of the word. Nonetheless, the mechanism it provides is a useful way for DSA to express the fact that it performs fast ageing too, in a way that does not change the existing behavior for other drivers. Cc: Alexandra Winter Cc: Julian Wiedmann Cc: Roopa Prabhu Cc: Nikolay Aleksandrov Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- net/dsa/port.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/net/dsa/port.c b/net/dsa/port.c index a4c8d19a76e2..96a4de67eccb 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -30,6 +30,24 @@ static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v) return dsa_tree_notify(dp->ds->dst, e, v); } +static void dsa_port_notify_bridge_fdb_flush(const struct dsa_port *dp) +{ + struct net_device *brport_dev = dsa_port_to_bridge_port(dp); + struct switchdev_notifier_fdb_info info = { + /* flush all VLANs */ + .vid = 0, + }; + + /* When the port becomes standalone it has already left the bridge. + * Don't notify the bridge in that case. + */ + if (!brport_dev) + return; + + call_switchdev_notifiers(SWITCHDEV_FDB_FLUSH_TO_BRIDGE, + brport_dev, &info.info, NULL); +} + static void dsa_port_fast_age(const struct dsa_port *dp) { struct dsa_switch *ds = dp->ds; @@ -38,6 +56,8 @@ static void dsa_port_fast_age(const struct dsa_port *dp) return; ds->ops->port_fast_age(ds, dp->index); + + dsa_port_notify_bridge_fdb_flush(dp); } int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age) -- 2.11.0