Skip to content

Commit b8e997c

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: introduce a separate cross-chip notifier type for host MDBs
Commit abd4953 ("net: dsa: execute dsa_switch_mdb_add only for routing port in cross-chip topologies") does a surprisingly good job even for the SWITCHDEV_OBJ_ID_HOST_MDB use case, where DSA simply translates a switchdev object received on dp into a cross-chip notifier for dp->cpu_dp. To visualize how that works, imagine the daisy chain topology below and consider a SWITCHDEV_OBJ_ID_HOST_MDB object emitted on sw2p0. How does the cross-chip notifier know to match on all the right ports (sw0p4, the dedicated CPU port, sw1p4, an upstream DSA link, and sw2p4, another upstream DSA link)? | sw0p0 sw0p1 sw0p2 sw0p3 sw0p4 [ user ] [ user ] [ user ] [ dsa ] [ cpu ] [ ] [ ] [ ] [ ] [ x ] | +---------+ | sw1p0 sw1p1 sw1p2 sw1p3 sw1p4 [ user ] [ user ] [ user ] [ dsa ] [ dsa ] [ ] [ ] [ ] [ ] [ x ] | +---------+ | sw2p0 sw2p1 sw2p2 sw2p3 sw2p4 [ user ] [ user ] [ user ] [ user ] [ dsa ] [ ] [ ] [ ] [ ] [ x ] The answer is simple: the dedicated CPU port of sw2p0 is sw0p4, and dsa_routing_port returns the upstream port for all switches. That is fine, but there are other topologies where this does not work as well. There are trees with "H" topologies in the wild, where there are 2 or more switches with DSA links between them, but every switch has its dedicated CPU port. For these topologies, it seems stupid for the neighbor switches to install an MDB entry on the routing port, since these multicast addresses are fundamentally different than the usual ones we support (and that is the justification for this patch, to introduce the concept of a termination plane multicast MAC address, as opposed to a forwarding plane multicast MAC address). For example, when a SWITCHDEV_OBJ_ID_HOST_MDB would get added to sw0p0, without this patch, it would get treated as a regular port MDB on sw0p2 and it would match on the ports below (including the sw1p3 routing port). | | sw0p0 sw0p1 sw0p2 sw0p3 sw1p3 sw1p2 sw1p1 sw1p0 [ user ] [ user ] [ cpu ] [ dsa ] [ dsa ] [ cpu ] [ user ] [ user ] [ ] [ ] [ x ] [ ] ---- [ x ] [ ] [ ] [ ] With the patch, the host MDB notifier on sw0p0 matches only on the local switch, which is what we want for a termination plane address. | | sw0p0 sw0p1 sw0p2 sw0p3 sw1p3 sw1p2 sw1p1 sw1p0 [ user ] [ user ] [ cpu ] [ dsa ] [ dsa ] [ cpu ] [ user ] [ user ] [ ] [ ] [ x ] [ ] ---- [ ] [ ] [ ] [ ] Name this new matching function "dsa_switch_host_address_match" since we will be reusing it soon for host FDB entries as well. Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 63609c8 commit b8e997c

File tree

4 files changed

+92
-8
lines changed

4 files changed

+92
-8
lines changed

net/dsa/dsa_priv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ enum {
2727
DSA_NOTIFIER_LAG_LEAVE,
2828
DSA_NOTIFIER_MDB_ADD,
2929
DSA_NOTIFIER_MDB_DEL,
30+
DSA_NOTIFIER_HOST_MDB_ADD,
31+
DSA_NOTIFIER_HOST_MDB_DEL,
3032
DSA_NOTIFIER_VLAN_ADD,
3133
DSA_NOTIFIER_VLAN_DEL,
3234
DSA_NOTIFIER_MTU,
@@ -214,6 +216,10 @@ int dsa_port_mdb_add(const struct dsa_port *dp,
214216
const struct switchdev_obj_port_mdb *mdb);
215217
int dsa_port_mdb_del(const struct dsa_port *dp,
216218
const struct switchdev_obj_port_mdb *mdb);
219+
int dsa_port_host_mdb_add(const struct dsa_port *dp,
220+
const struct switchdev_obj_port_mdb *mdb);
221+
int dsa_port_host_mdb_del(const struct dsa_port *dp,
222+
const struct switchdev_obj_port_mdb *mdb);
217223
int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
218224
struct switchdev_brport_flags flags,
219225
struct netlink_ext_ack *extack);

net/dsa/port.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,30 @@ int dsa_port_mdb_del(const struct dsa_port *dp,
681681
return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info);
682682
}
683683

684+
int dsa_port_host_mdb_add(const struct dsa_port *dp,
685+
const struct switchdev_obj_port_mdb *mdb)
686+
{
687+
struct dsa_notifier_mdb_info info = {
688+
.sw_index = dp->ds->index,
689+
.port = dp->index,
690+
.mdb = mdb,
691+
};
692+
693+
return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_ADD, &info);
694+
}
695+
696+
int dsa_port_host_mdb_del(const struct dsa_port *dp,
697+
const struct switchdev_obj_port_mdb *mdb)
698+
{
699+
struct dsa_notifier_mdb_info info = {
700+
.sw_index = dp->ds->index,
701+
.port = dp->index,
702+
.mdb = mdb,
703+
};
704+
705+
return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_DEL, &info);
706+
}
707+
684708
int dsa_port_vlan_add(struct dsa_port *dp,
685709
const struct switchdev_obj_port_vlan *vlan,
686710
struct netlink_ext_ack *extack)

net/dsa/slave.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -418,10 +418,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev, const void *ctx,
418418
if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
419419
return -EOPNOTSUPP;
420420

421-
/* DSA can directly translate this to a normal MDB add,
422-
* but on the CPU port.
423-
*/
424-
err = dsa_port_mdb_add(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj));
421+
err = dsa_port_host_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
425422
break;
426423
case SWITCHDEV_OBJ_ID_PORT_VLAN:
427424
if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
@@ -495,10 +492,7 @@ static int dsa_slave_port_obj_del(struct net_device *dev, const void *ctx,
495492
if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
496493
return -EOPNOTSUPP;
497494

498-
/* DSA can directly translate this to a normal MDB add,
499-
* but on the CPU port.
500-
*/
501-
err = dsa_port_mdb_del(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj));
495+
err = dsa_port_host_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
502496
break;
503497
case SWITCHDEV_OBJ_ID_PORT_VLAN:
504498
if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))

net/dsa/switch.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,27 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
154154
return 0;
155155
}
156156

157+
/* Matches for all upstream-facing ports (the CPU port and all upstream-facing
158+
* DSA links) that sit between the targeted port on which the notifier was
159+
* emitted and its dedicated CPU port.
160+
*/
161+
static bool dsa_switch_host_address_match(struct dsa_switch *ds, int port,
162+
int info_sw_index, int info_port)
163+
{
164+
struct dsa_port *targeted_dp, *cpu_dp;
165+
struct dsa_switch *targeted_ds;
166+
167+
targeted_ds = dsa_switch_find(ds->dst->index, info_sw_index);
168+
targeted_dp = dsa_to_port(targeted_ds, info_port);
169+
cpu_dp = targeted_dp->cpu_dp;
170+
171+
if (dsa_switch_is_upstream_of(ds, targeted_ds))
172+
return port == dsa_towards_port(ds, cpu_dp->ds->index,
173+
cpu_dp->index);
174+
175+
return false;
176+
}
177+
157178
static int dsa_switch_fdb_add(struct dsa_switch *ds,
158179
struct dsa_notifier_fdb_info *info)
159180
{
@@ -258,6 +279,39 @@ static int dsa_switch_mdb_del(struct dsa_switch *ds,
258279
return 0;
259280
}
260281

282+
static int dsa_switch_host_mdb_add(struct dsa_switch *ds,
283+
struct dsa_notifier_mdb_info *info)
284+
{
285+
int err = 0;
286+
int port;
287+
288+
if (!ds->ops->port_mdb_add)
289+
return -EOPNOTSUPP;
290+
291+
for (port = 0; port < ds->num_ports; port++) {
292+
if (dsa_switch_host_address_match(ds, port, info->sw_index,
293+
info->port)) {
294+
err = ds->ops->port_mdb_add(ds, port, info->mdb);
295+
if (err)
296+
break;
297+
}
298+
}
299+
300+
return err;
301+
}
302+
303+
static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
304+
struct dsa_notifier_mdb_info *info)
305+
{
306+
if (!ds->ops->port_mdb_del)
307+
return -EOPNOTSUPP;
308+
309+
if (ds->index == info->sw_index)
310+
return ds->ops->port_mdb_del(ds, info->port, info->mdb);
311+
312+
return 0;
313+
}
314+
261315
static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port,
262316
struct dsa_notifier_vlan_info *info)
263317
{
@@ -441,6 +495,12 @@ static int dsa_switch_event(struct notifier_block *nb,
441495
case DSA_NOTIFIER_MDB_DEL:
442496
err = dsa_switch_mdb_del(ds, info);
443497
break;
498+
case DSA_NOTIFIER_HOST_MDB_ADD:
499+
err = dsa_switch_host_mdb_add(ds, info);
500+
break;
501+
case DSA_NOTIFIER_HOST_MDB_DEL:
502+
err = dsa_switch_host_mdb_del(ds, info);
503+
break;
444504
case DSA_NOTIFIER_VLAN_ADD:
445505
err = dsa_switch_vlan_add(ds, info);
446506
break;

0 commit comments

Comments
 (0)