Skip to content

Commit 03cbb87

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: fix switchdev objects on bridge master mistakenly being applied on ports
Tobias reports that after the blamed patch, VLAN objects being added to a bridge device are being added to all slave ports instead (swp2, swp3). ip link add br0 type bridge vlan_filtering 1 ip link set swp2 master br0 ip link set swp3 master br0 bridge vlan add dev br0 vid 100 self This is because the fix was too broad: we made dsa_port_offloads_netdev say "yes, I offload the br0 bridge" for all slave ports, but we didn't add the checks whether the switchdev object was in fact meant for the physical port or for the bridge itself. So we are reacting on events in a way in which we shouldn't. The reason why the fix was too broad is because the question itself, "does this DSA port offload this netdev", was too broad in the first place. The solution is to disambiguate the question and separate it into two different functions, one to be called for each switchdev attribute / object that has an orig_dev == net_bridge (dsa_port_offloads_bridge), and the other for orig_dev == net_bridge_port (*_offloads_bridge_port). In the case of VLAN objects on the bridge interface, this solves the problem because we know that VLAN objects are per bridge port and not per bridge. And when orig_dev is equal to the net_bridge, we offload it as a bridge, but not as a bridge port; that's how we are able to skip reacting on those events. Note that this is compatible with future plans to have explicit offloading of VLAN objects on the bridge interface as a bridge port (in DSA, this signifies that we should add that VLAN towards the CPU port). Fixes: 99b8202 ("net: dsa: fix SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING getting ignored") Reported-by: Tobias Waldekranz <[email protected]> Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Tobias Waldekranz <[email protected]> Tested-by: Tobias Waldekranz <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 62765d3 commit 03cbb87

File tree

2 files changed

+57
-27
lines changed

2 files changed

+57
-27
lines changed

net/dsa/dsa_priv.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr);
230230
void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr);
231231
extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
232232

233-
static inline bool dsa_port_offloads_netdev(struct dsa_port *dp,
234-
struct net_device *dev)
233+
static inline bool dsa_port_offloads_bridge_port(struct dsa_port *dp,
234+
struct net_device *dev)
235235
{
236236
/* Switchdev offloading can be configured on: */
237237

@@ -241,27 +241,30 @@ static inline bool dsa_port_offloads_netdev(struct dsa_port *dp,
241241
*/
242242
return true;
243243

244-
if (dp->bridge_dev == dev)
245-
/* DSA ports connected to a bridge, and event was emitted
246-
* for the bridge.
247-
*/
248-
return true;
249-
250244
if (dp->lag_dev == dev)
251245
/* DSA ports connected to a bridge via a LAG */
252246
return true;
253247

254248
return false;
255249
}
256250

251+
static inline bool dsa_port_offloads_bridge(struct dsa_port *dp,
252+
struct net_device *bridge_dev)
253+
{
254+
/* DSA ports connected to a bridge, and event was emitted
255+
* for the bridge.
256+
*/
257+
return dp->bridge_dev == bridge_dev;
258+
}
259+
257260
/* Returns true if any port of this tree offloads the given net_device */
258-
static inline bool dsa_tree_offloads_netdev(struct dsa_switch_tree *dst,
259-
struct net_device *dev)
261+
static inline bool dsa_tree_offloads_bridge_port(struct dsa_switch_tree *dst,
262+
struct net_device *dev)
260263
{
261264
struct dsa_port *dp;
262265

263266
list_for_each_entry(dp, &dst->ports, list)
264-
if (dsa_port_offloads_netdev(dp, dev))
267+
if (dsa_port_offloads_bridge_port(dp, dev))
265268
return true;
266269

267270
return false;

net/dsa/slave.c

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -278,28 +278,43 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
278278
struct dsa_port *dp = dsa_slave_to_port(dev);
279279
int ret;
280280

281-
if (!dsa_port_offloads_netdev(dp, attr->orig_dev))
282-
return -EOPNOTSUPP;
283-
284281
switch (attr->id) {
285282
case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
283+
if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev))
284+
return -EOPNOTSUPP;
285+
286286
ret = dsa_port_set_state(dp, attr->u.stp_state);
287287
break;
288288
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
289+
if (!dsa_port_offloads_bridge(dp, attr->orig_dev))
290+
return -EOPNOTSUPP;
291+
289292
ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering,
290293
extack);
291294
break;
292295
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
296+
if (!dsa_port_offloads_bridge(dp, attr->orig_dev))
297+
return -EOPNOTSUPP;
298+
293299
ret = dsa_port_ageing_time(dp, attr->u.ageing_time);
294300
break;
295301
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
302+
if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev))
303+
return -EOPNOTSUPP;
304+
296305
ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags,
297306
extack);
298307
break;
299308
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
309+
if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev))
310+
return -EOPNOTSUPP;
311+
300312
ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, extack);
301313
break;
302314
case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER:
315+
if (!dsa_port_offloads_bridge(dp, attr->orig_dev))
316+
return -EOPNOTSUPP;
317+
303318
ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter, extack);
304319
break;
305320
default:
@@ -341,9 +356,6 @@ static int dsa_slave_vlan_add(struct net_device *dev,
341356
struct switchdev_obj_port_vlan vlan;
342357
int err;
343358

344-
if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
345-
return -EOPNOTSUPP;
346-
347359
if (dsa_port_skip_vlan_configuration(dp)) {
348360
NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN");
349361
return 0;
@@ -391,27 +403,36 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
391403

392404
switch (obj->id) {
393405
case SWITCHDEV_OBJ_ID_PORT_MDB:
394-
if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
406+
if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
395407
return -EOPNOTSUPP;
408+
396409
err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
397410
break;
398411
case SWITCHDEV_OBJ_ID_HOST_MDB:
412+
if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
413+
return -EOPNOTSUPP;
414+
399415
/* DSA can directly translate this to a normal MDB add,
400416
* but on the CPU port.
401417
*/
402418
err = dsa_port_mdb_add(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj));
403419
break;
404420
case SWITCHDEV_OBJ_ID_PORT_VLAN:
421+
if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
422+
return -EOPNOTSUPP;
423+
405424
err = dsa_slave_vlan_add(dev, obj, extack);
406425
break;
407426
case SWITCHDEV_OBJ_ID_MRP:
408-
if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
427+
if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
409428
return -EOPNOTSUPP;
429+
410430
err = dsa_port_mrp_add(dp, SWITCHDEV_OBJ_MRP(obj));
411431
break;
412432
case SWITCHDEV_OBJ_ID_RING_ROLE_MRP:
413-
if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
433+
if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
414434
return -EOPNOTSUPP;
435+
415436
err = dsa_port_mrp_add_ring_role(dp,
416437
SWITCHDEV_OBJ_RING_ROLE_MRP(obj));
417438
break;
@@ -431,9 +452,6 @@ static int dsa_slave_vlan_del(struct net_device *dev,
431452
struct switchdev_obj_port_vlan *vlan;
432453
int err;
433454

434-
if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
435-
return -EOPNOTSUPP;
436-
437455
if (dsa_port_skip_vlan_configuration(dp))
438456
return 0;
439457

@@ -459,27 +477,36 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
459477

460478
switch (obj->id) {
461479
case SWITCHDEV_OBJ_ID_PORT_MDB:
462-
if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
480+
if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
463481
return -EOPNOTSUPP;
482+
464483
err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
465484
break;
466485
case SWITCHDEV_OBJ_ID_HOST_MDB:
486+
if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
487+
return -EOPNOTSUPP;
488+
467489
/* DSA can directly translate this to a normal MDB add,
468490
* but on the CPU port.
469491
*/
470492
err = dsa_port_mdb_del(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj));
471493
break;
472494
case SWITCHDEV_OBJ_ID_PORT_VLAN:
495+
if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
496+
return -EOPNOTSUPP;
497+
473498
err = dsa_slave_vlan_del(dev, obj);
474499
break;
475500
case SWITCHDEV_OBJ_ID_MRP:
476-
if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
501+
if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
477502
return -EOPNOTSUPP;
503+
478504
err = dsa_port_mrp_del(dp, SWITCHDEV_OBJ_MRP(obj));
479505
break;
480506
case SWITCHDEV_OBJ_ID_RING_ROLE_MRP:
481-
if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
507+
if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
482508
return -EOPNOTSUPP;
509+
483510
err = dsa_port_mrp_del_ring_role(dp,
484511
SWITCHDEV_OBJ_RING_ROLE_MRP(obj));
485512
break;
@@ -2298,7 +2325,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
22982325
* other ports bridged with the LAG should be able to
22992326
* autonomously forward towards it.
23002327
*/
2301-
if (dsa_tree_offloads_netdev(dp->ds->dst, dev))
2328+
if (dsa_tree_offloads_bridge_port(dp->ds->dst, dev))
23022329
return NOTIFY_DONE;
23032330
}
23042331

0 commit comments

Comments
 (0)