diff mbox series

[net-next,7/7] net: dsa: replay a deletion of switchdev objects for ports leaving a bridged LAG

Message ID 20210625185321.626325-8-olteanv@gmail.com
State New
Headers show
Series Cleanup for the bridge replay helpers | expand

Commit Message

Vladimir Oltean June 25, 2021, 6:53 p.m. UTC
From: Vladimir Oltean <vladimir.oltean@nxp.com>

When a DSA switch port leaves a bonding interface that is under a
bridge, there might be dangling switchdev objects on that port left
behind, because the bridge is not aware that its lower interface (the
bond) changed state in any way.

Call the bridge replay helpers with adding=false before changing
dp->bridge_dev to NULL, because we need to simulate to
dsa_slave_port_obj_del() that these notifications were emitted by the
bridge.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/port.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

Comments

Florian Fainelli June 27, 2021, 3:01 a.m. UTC | #1
On 6/25/2021 11:53 AM, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>

> 

> When a DSA switch port leaves a bonding interface that is under a

> bridge, there might be dangling switchdev objects on that port left

> behind, because the bridge is not aware that its lower interface (the

> bond) changed state in any way.

> 

> Call the bridge replay helpers with adding=false before changing

> dp->bridge_dev to NULL, because we need to simulate to

> dsa_slave_port_obj_del() that these notifications were emitted by the

> bridge.

> 

> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>


Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>

-- 
Florian
diff mbox series

Patch

diff --git a/net/dsa/port.c b/net/dsa/port.c
index 4e58d07ececd..787c0454f9bd 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -212,7 +212,22 @@  static int dsa_port_switchdev_sync(struct dsa_port *dp,
 	return 0;
 }
 
-static void dsa_port_switchdev_unsync(struct dsa_port *dp)
+static void dsa_port_switchdev_unsync_objs(struct dsa_port *dp)
+{
+	struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
+	struct net_device *br = dp->bridge_dev;
+
+	/* Delete the switchdev objects left on this port */
+	br_mdb_replay(br, brport_dev, dp, false,
+		      &dsa_slave_switchdev_blocking_notifier, NULL);
+
+	br_fdb_replay(br, brport_dev, dp, false, &dsa_slave_switchdev_notifier);
+
+	br_vlan_replay(br, brport_dev, dp, false,
+		       &dsa_slave_switchdev_blocking_notifier, NULL);
+}
+
+static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
 {
 	/* Configure the port for standalone mode (no address learning,
 	 * flood everything).
@@ -288,6 +303,8 @@  void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
 	};
 	int err;
 
+	dsa_port_switchdev_unsync_objs(dp);
+
 	/* Here the port is already unbridged. Reflect the current configuration
 	 * so that drivers can program their chips accordingly.
 	 */
@@ -297,7 +314,7 @@  void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
 	if (err)
 		pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
 
-	dsa_port_switchdev_unsync(dp);
+	dsa_port_switchdev_unsync_attrs(dp);
 }
 
 int dsa_port_lag_change(struct dsa_port *dp,