From bee7c577e6d7b51fa0d2b30747c2cd3499ef778e Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 9 Aug 2021 01:56:49 +0300 Subject: [PATCH] net: dsa: avoid fast ageing twice when port leaves a bridge Drivers that support both the toggling of address learning and dynamic FDB flushing (mv88e6xxx, b53, sja1105) currently need to fast-age a port twice when it leaves a bridge: - once, when del_nbp() calls br_stp_disable_port() which puts the port in the BLOCKING state - twice, when dsa_port_switchdev_unsync_attrs() calls dsa_port_clear_brport_flags() which disables address learning The knee-jerk reaction might be to say "dsa_port_clear_brport_flags does not need to fast-age the port at all", but the thing is, we still need both code paths to flush the dynamic FDB entries in different situations. When a DSA switch port leaves a bonding/team interface that is (still) a bridge port, no del_nbp() will be called, so we rely on dsa_port_clear_brport_flags() function to restore proper standalone port functionality with address learning disabled. So the solution is just to avoid double the work when both code paths are called in series. Luckily, DSA already caches the STP port state, so we can skip flushing the dynamic FDB when we disable address learning and the STP state is one where no address learning takes place at all. Under that condition, not flushing the FDB is safe because there is supposed to not be any dynamic FDB entry at all (they were flushed during the transition towards that state, and none were learned in the meanwhile). Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- net/dsa/port.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/dsa/port.c b/net/dsa/port.c index aac87ac989ed..831d50d28d59 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -699,7 +699,9 @@ int dsa_port_bridge_flags(struct dsa_port *dp, if (learning == dp->learning) return 0; - if (dp->learning && !learning) + if ((dp->learning && !learning) && + (dp->stp_state == BR_STATE_LEARNING || + dp->stp_state == BR_STATE_FORWARDING)) dsa_port_fast_age(dp); dp->learning = learning;