Skip to content

Commit 7491894

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: replay a deletion of switchdev objects for ports leaving a bridged LAG
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. We add this hook to the NETDEV_PRECHANGEUPPER event handler, because we are calling into switchdev (and the __switchdev_handle_port_obj_del fanout helpers expect the upper/lower adjacency lists to still be valid) and PRECHANGEUPPER is the last moment in time when they still are. Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4ede74e commit 7491894

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed

net/dsa/dsa_priv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,16 @@ void dsa_port_disable_rt(struct dsa_port *dp);
188188
void dsa_port_disable(struct dsa_port *dp);
189189
int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
190190
struct netlink_ext_ack *extack);
191+
int dsa_port_pre_bridge_leave(struct dsa_port *dp, struct net_device *br,
192+
struct netlink_ext_ack *extack);
191193
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
192194
int dsa_port_lag_change(struct dsa_port *dp,
193195
struct netdev_lag_lower_state_info *linfo);
194196
int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev,
195197
struct netdev_lag_upper_info *uinfo,
196198
struct netlink_ext_ack *extack);
199+
int dsa_port_pre_lag_leave(struct dsa_port *dp, struct net_device *lag_dev,
200+
struct netlink_ext_ack *extack);
197201
void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag_dev);
198202
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
199203
struct netlink_ext_ack *extack);

net/dsa/port.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,33 @@ static int dsa_port_switchdev_sync(struct dsa_port *dp,
212212
return 0;
213213
}
214214

215-
static void dsa_port_switchdev_unsync(struct dsa_port *dp)
215+
static int dsa_port_switchdev_unsync_objs(struct dsa_port *dp,
216+
struct net_device *br,
217+
struct netlink_ext_ack *extack)
218+
{
219+
struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
220+
int err;
221+
222+
/* Delete the switchdev objects left on this port */
223+
err = br_mdb_replay(br, brport_dev, dp, false,
224+
&dsa_slave_switchdev_blocking_notifier, extack);
225+
if (err && err != -EOPNOTSUPP)
226+
return err;
227+
228+
err = br_fdb_replay(br, brport_dev, dp, false,
229+
&dsa_slave_switchdev_notifier);
230+
if (err && err != -EOPNOTSUPP)
231+
return err;
232+
233+
err = br_vlan_replay(br, brport_dev, dp, false,
234+
&dsa_slave_switchdev_blocking_notifier, extack);
235+
if (err && err != -EOPNOTSUPP)
236+
return err;
237+
238+
return 0;
239+
}
240+
241+
static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
216242
{
217243
/* Configure the port for standalone mode (no address learning,
218244
* flood everything).
@@ -278,6 +304,12 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
278304
return err;
279305
}
280306

307+
int dsa_port_pre_bridge_leave(struct dsa_port *dp, struct net_device *br,
308+
struct netlink_ext_ack *extack)
309+
{
310+
return dsa_port_switchdev_unsync_objs(dp, br, extack);
311+
}
312+
281313
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
282314
{
283315
struct dsa_notifier_bridge_info info = {
@@ -297,7 +329,7 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
297329
if (err)
298330
pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
299331

300-
dsa_port_switchdev_unsync(dp);
332+
dsa_port_switchdev_unsync_attrs(dp);
301333
}
302334

303335
int dsa_port_lag_change(struct dsa_port *dp,
@@ -365,6 +397,15 @@ int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag,
365397
return err;
366398
}
367399

400+
int dsa_port_pre_lag_leave(struct dsa_port *dp, struct net_device *lag,
401+
struct netlink_ext_ack *extack)
402+
{
403+
if (dp->bridge_dev)
404+
return dsa_port_pre_bridge_leave(dp, dp->bridge_dev, extack);
405+
406+
return 0;
407+
}
408+
368409
void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag)
369410
{
370411
struct dsa_notifier_lag_info info = {

net/dsa/slave.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,26 @@ static int dsa_slave_changeupper(struct net_device *dev,
20772077
return err;
20782078
}
20792079

2080+
static int dsa_slave_prechangeupper(struct net_device *dev,
2081+
struct netdev_notifier_changeupper_info *info)
2082+
{
2083+
struct dsa_port *dp = dsa_slave_to_port(dev);
2084+
struct netlink_ext_ack *extack;
2085+
int err = 0;
2086+
2087+
extack = netdev_notifier_info_to_extack(&info->info);
2088+
2089+
if (netif_is_bridge_master(info->upper_dev) && !info->linking)
2090+
err = dsa_port_pre_bridge_leave(dp, info->upper_dev, extack);
2091+
else if (netif_is_lag_master(info->upper_dev) && !info->linking)
2092+
err = dsa_port_pre_lag_leave(dp, info->upper_dev, extack);
2093+
/* dsa_port_pre_hsr_leave is not yet necessary since hsr cannot be
2094+
* meaningfully enslaved to a bridge yet
2095+
*/
2096+
2097+
return notifier_from_errno(err);
2098+
}
2099+
20802100
static int
20812101
dsa_slave_lag_changeupper(struct net_device *dev,
20822102
struct netdev_notifier_changeupper_info *info)
@@ -2103,6 +2123,35 @@ dsa_slave_lag_changeupper(struct net_device *dev,
21032123
return err;
21042124
}
21052125

2126+
/* Same as dsa_slave_lag_changeupper() except that it calls
2127+
* dsa_slave_prechangeupper()
2128+
*/
2129+
static int
2130+
dsa_slave_lag_prechangeupper(struct net_device *dev,
2131+
struct netdev_notifier_changeupper_info *info)
2132+
{
2133+
struct net_device *lower;
2134+
struct list_head *iter;
2135+
int err = NOTIFY_DONE;
2136+
struct dsa_port *dp;
2137+
2138+
netdev_for_each_lower_dev(dev, lower, iter) {
2139+
if (!dsa_slave_dev_check(lower))
2140+
continue;
2141+
2142+
dp = dsa_slave_to_port(lower);
2143+
if (!dp->lag_dev)
2144+
/* Software LAG */
2145+
continue;
2146+
2147+
err = dsa_slave_prechangeupper(lower, info);
2148+
if (notifier_to_errno(err))
2149+
break;
2150+
}
2151+
2152+
return err;
2153+
}
2154+
21062155
static int
21072156
dsa_prevent_bridging_8021q_upper(struct net_device *dev,
21082157
struct netdev_notifier_changeupper_info *info)
@@ -2206,6 +2255,12 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
22062255
if (err != NOTIFY_DONE)
22072256
return err;
22082257

2258+
if (dsa_slave_dev_check(dev))
2259+
return dsa_slave_prechangeupper(dev, ptr);
2260+
2261+
if (netif_is_lag_master(dev))
2262+
return dsa_slave_lag_prechangeupper(dev, ptr);
2263+
22092264
break;
22102265
}
22112266
case NETDEV_CHANGEUPPER:

0 commit comments

Comments
 (0)