Skip to content

Commit 7f4e5c5

Browse files
committed
Merge branch 'dsa-rx-filtering'
Vladimir Oltean says: ==================== RX filtering in DSA This is my fourth stab (identical to the third one except sent as non-RFC) at creating a list of unicast and multicast addresses that the DSA CPU ports must trap. I am reusing a lot of Tobias's work which he submitted here: https://patchwork.kernel.org/project/netdevbpf/cover/[email protected]/ My additions to Tobias' work come in the form of taking some care that additions and removals of host addresses are properly balanced, so that we can do reference counting on them for cross-chip setups and multiple bridges spanning the same switch (I am working on an NXP board where both are real requirements). During the last attempted submission of multiple CPU ports for DSA: https://patchwork.kernel.org/project/netdevbpf/cover/[email protected]/ it became clear that the concept of multiple CPU ports would not be compatible with the idea of address learning on those CPU ports (when those CPU ports are statically assigned to user ports, not in a LAG) unless the switch supports complete FDB isolation, which most switches do not. So DSA needs to manage in software all addresses that are installed on the CPU port(s), which is what this patch set does. Compared to all earlier attempts, this series does not fiddle with how DSA operates the ports in standalone mode at all, just when bridged. We need to sort that out properly, then any optimization that comes in standalone mode (i.e. IFF_UNICAST_FLT) can come later. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 84fe739 + 63c5145 commit 7f4e5c5

File tree

10 files changed

+573
-79
lines changed

10 files changed

+573
-79
lines changed

Documentation/networking/dsa/configuration.rst

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,3 +292,71 @@ configuration.
292292
293293
# bring up the bridge devices
294294
ip link set br0 up
295+
296+
Forwarding database (FDB) management
297+
------------------------------------
298+
299+
The existing DSA switches do not have the necessary hardware support to keep
300+
the software FDB of the bridge in sync with the hardware tables, so the two
301+
tables are managed separately (``bridge fdb show`` queries both, and depending
302+
on whether the ``self`` or ``master`` flags are being used, a ``bridge fdb
303+
add`` or ``bridge fdb del`` command acts upon entries from one or both tables).
304+
305+
Up until kernel v4.14, DSA only supported user space management of bridge FDB
306+
entries using the bridge bypass operations (which do not update the software
307+
FDB, just the hardware one) using the ``self`` flag (which is optional and can
308+
be omitted).
309+
310+
.. code-block:: sh
311+
312+
bridge fdb add dev swp0 00:01:02:03:04:05 self static
313+
# or shorthand
314+
bridge fdb add dev swp0 00:01:02:03:04:05 static
315+
316+
Due to a bug, the bridge bypass FDB implementation provided by DSA did not
317+
distinguish between ``static`` and ``local`` FDB entries (``static`` are meant
318+
to be forwarded, while ``local`` are meant to be locally terminated, i.e. sent
319+
to the host port). Instead, all FDB entries with the ``self`` flag (implicit or
320+
explicit) are treated by DSA as ``static`` even if they are ``local``.
321+
322+
.. code-block:: sh
323+
324+
# This command:
325+
bridge fdb add dev swp0 00:01:02:03:04:05 static
326+
# behaves the same for DSA as this command:
327+
bridge fdb add dev swp0 00:01:02:03:04:05 local
328+
# or shorthand, because the 'local' flag is implicit if 'static' is not
329+
# specified, it also behaves the same as:
330+
bridge fdb add dev swp0 00:01:02:03:04:05
331+
332+
The last command is an incorrect way of adding a static bridge FDB entry to a
333+
DSA switch using the bridge bypass operations, and works by mistake. Other
334+
drivers will treat an FDB entry added by the same command as ``local`` and as
335+
such, will not forward it, as opposed to DSA.
336+
337+
Between kernel v4.14 and v5.14, DSA has supported in parallel two modes of
338+
adding a bridge FDB entry to the switch: the bridge bypass discussed above, as
339+
well as a new mode using the ``master`` flag which installs FDB entries in the
340+
software bridge too.
341+
342+
.. code-block:: sh
343+
344+
bridge fdb add dev swp0 00:01:02:03:04:05 master static
345+
346+
Since kernel v5.14, DSA has gained stronger integration with the bridge's
347+
software FDB, and the support for its bridge bypass FDB implementation (using
348+
the ``self`` flag) has been removed. This results in the following changes:
349+
350+
.. code-block:: sh
351+
352+
# This is the only valid way of adding an FDB entry that is supported,
353+
# compatible with v4.14 kernels and later:
354+
bridge fdb add dev swp0 00:01:02:03:04:05 master static
355+
# This command is no longer buggy and the entry is properly treated as
356+
# 'local' instead of being forwarded:
357+
bridge fdb add dev swp0 00:01:02:03:04:05
358+
# This command no longer installs a static FDB entry to hardware:
359+
bridge fdb add dev swp0 00:01:02:03:04:05 static
360+
361+
Script writers are therefore encouraged to use the ``master static`` set of
362+
flags when working with bridge FDB entries on DSA switch interfaces.

include/net/dsa.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@ struct dsa_port {
285285
*/
286286
const struct dsa_netdevice_ops *netdev_ops;
287287

288+
/* List of MAC addresses that must be forwarded on this port.
289+
* These are only valid on CPU ports and DSA links.
290+
*/
291+
struct list_head fdbs;
292+
struct list_head mdbs;
293+
288294
bool setup;
289295
};
290296

@@ -299,6 +305,13 @@ struct dsa_link {
299305
struct list_head list;
300306
};
301307

308+
struct dsa_mac_addr {
309+
unsigned char addr[ETH_ALEN];
310+
u16 vid;
311+
refcount_t refcount;
312+
struct list_head list;
313+
};
314+
302315
struct dsa_switch {
303316
bool setup;
304317

@@ -491,6 +504,32 @@ static inline unsigned int dsa_upstream_port(struct dsa_switch *ds, int port)
491504
return dsa_towards_port(ds, cpu_dp->ds->index, cpu_dp->index);
492505
}
493506

507+
/* Return true if this is the local port used to reach the CPU port */
508+
static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int port)
509+
{
510+
if (dsa_is_unused_port(ds, port))
511+
return false;
512+
513+
return port == dsa_upstream_port(ds, port);
514+
}
515+
516+
/* Return true if @upstream_ds is an upstream switch of @downstream_ds, meaning
517+
* that the routing port from @downstream_ds to @upstream_ds is also the port
518+
* which @downstream_ds uses to reach its dedicated CPU.
519+
*/
520+
static inline bool dsa_switch_is_upstream_of(struct dsa_switch *upstream_ds,
521+
struct dsa_switch *downstream_ds)
522+
{
523+
int routing_port;
524+
525+
if (upstream_ds == downstream_ds)
526+
return true;
527+
528+
routing_port = dsa_routing_port(downstream_ds, upstream_ds->index);
529+
530+
return dsa_is_upstream_port(downstream_ds, routing_port);
531+
}
532+
494533
static inline bool dsa_port_is_vlan_filtering(const struct dsa_port *dp)
495534
{
496535
const struct dsa_switch *ds = dp->ds;

net/bridge/br_fdb.c

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,14 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
440440
if (!port)
441441
ret = 0;
442442
else {
443+
const struct net_bridge_port *dst = NULL;
444+
443445
fdb = br_fdb_find_rcu(port->br, addr, 0);
444-
ret = fdb && fdb->dst && fdb->dst->dev != dev &&
445-
fdb->dst->state == BR_STATE_FORWARDING;
446+
if (fdb)
447+
dst = READ_ONCE(fdb->dst);
448+
449+
ret = dst && dst->dev != dev &&
450+
dst->state == BR_STATE_FORWARDING;
446451
}
447452
rcu_read_unlock();
448453

@@ -509,7 +514,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br,
509514
fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
510515
if (fdb) {
511516
memcpy(fdb->key.addr.addr, addr, ETH_ALEN);
512-
fdb->dst = source;
517+
WRITE_ONCE(fdb->dst, source);
513518
fdb->key.vlan_id = vid;
514519
fdb->flags = flags;
515520
fdb->updated = fdb->used = jiffies;
@@ -600,10 +605,10 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
600605
}
601606

602607
/* fastpath: update of existing entry */
603-
if (unlikely(source != fdb->dst &&
608+
if (unlikely(source != READ_ONCE(fdb->dst) &&
604609
!test_bit(BR_FDB_STICKY, &fdb->flags))) {
605-
br_switchdev_fdb_notify(fdb, RTM_DELNEIGH);
606-
fdb->dst = source;
610+
br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH);
611+
WRITE_ONCE(fdb->dst, source);
607612
fdb_modified = true;
608613
/* Take over HW learned entry */
609614
if (unlikely(test_bit(BR_FDB_ADDED_BY_EXT_LEARN,
@@ -650,6 +655,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
650655
const struct net_bridge_fdb_entry *fdb,
651656
u32 portid, u32 seq, int type, unsigned int flags)
652657
{
658+
const struct net_bridge_port *dst = READ_ONCE(fdb->dst);
653659
unsigned long now = jiffies;
654660
struct nda_cacheinfo ci;
655661
struct nlmsghdr *nlh;
@@ -665,7 +671,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
665671
ndm->ndm_pad2 = 0;
666672
ndm->ndm_flags = 0;
667673
ndm->ndm_type = 0;
668-
ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex;
674+
ndm->ndm_ifindex = dst ? dst->dev->ifindex : br->dev->ifindex;
669675
ndm->ndm_state = fdb_to_nud(br, fdb);
670676

671677
if (test_bit(BR_FDB_OFFLOADED, &fdb->flags))
@@ -754,7 +760,10 @@ int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev,
754760
unsigned long action;
755761
int err = 0;
756762

757-
if (!netif_is_bridge_master(br_dev) || !netif_is_bridge_port(dev))
763+
if (!netif_is_bridge_master(br_dev))
764+
return -EINVAL;
765+
766+
if (!netif_is_bridge_port(dev) && !netif_is_bridge_master(dev))
758767
return -EINVAL;
759768

760769
br = netdev_priv(br_dev);
@@ -794,7 +803,7 @@ static void fdb_notify(struct net_bridge *br,
794803
int err = -ENOBUFS;
795804

796805
if (swdev_notify)
797-
br_switchdev_fdb_notify(fdb, type);
806+
br_switchdev_fdb_notify(br, fdb, type);
798807

799808
skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
800809
if (skb == NULL)
@@ -964,8 +973,8 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
964973
if (flags & NLM_F_EXCL)
965974
return -EEXIST;
966975

967-
if (fdb->dst != source) {
968-
fdb->dst = source;
976+
if (READ_ONCE(fdb->dst) != source) {
977+
WRITE_ONCE(fdb->dst, source);
969978
modified = true;
970979
}
971980
}
@@ -1132,7 +1141,7 @@ static int fdb_delete_by_addr_and_port(struct net_bridge *br,
11321141
struct net_bridge_fdb_entry *fdb;
11331142

11341143
fdb = br_fdb_find(br, addr, vlan);
1135-
if (!fdb || fdb->dst != p)
1144+
if (!fdb || READ_ONCE(fdb->dst) != p)
11361145
return -ENOENT;
11371146

11381147
fdb_delete(br, fdb, true);
@@ -1281,8 +1290,8 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
12811290
} else {
12821291
fdb->updated = jiffies;
12831292

1284-
if (fdb->dst != p) {
1285-
fdb->dst = p;
1293+
if (READ_ONCE(fdb->dst) != p) {
1294+
WRITE_ONCE(fdb->dst, p);
12861295
modified = true;
12871296
}
12881297

net/bridge/br_private.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,8 +1654,8 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p,
16541654
unsigned long flags,
16551655
unsigned long mask,
16561656
struct netlink_ext_ack *extack);
1657-
void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb,
1658-
int type);
1657+
void br_switchdev_fdb_notify(struct net_bridge *br,
1658+
const struct net_bridge_fdb_entry *fdb, int type);
16591659
int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
16601660
struct netlink_ext_ack *extack);
16611661
int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid);
@@ -1702,7 +1702,8 @@ static inline int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
17021702
}
17031703

17041704
static inline void
1705-
br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
1705+
br_switchdev_fdb_notify(struct net_bridge *br,
1706+
const struct net_bridge_fdb_entry *fdb, int type)
17061707
{
17071708
}
17081709

net/bridge/br_switchdev.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,11 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p,
108108
}
109109

110110
void
111-
br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
111+
br_switchdev_fdb_notify(struct net_bridge *br,
112+
const struct net_bridge_fdb_entry *fdb, int type)
112113
{
114+
const struct net_bridge_port *dst = READ_ONCE(fdb->dst);
115+
struct net_device *dev = dst ? dst->dev : br->dev;
113116
struct switchdev_notifier_fdb_info info = {
114117
.addr = fdb->key.addr.addr,
115118
.vid = fdb->key.vlan_id,
@@ -118,17 +121,14 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
118121
.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags),
119122
};
120123

121-
if (!fdb->dst)
122-
return;
123-
124124
switch (type) {
125125
case RTM_DELNEIGH:
126126
call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE,
127-
fdb->dst->dev, &info.info, NULL);
127+
dev, &info.info, NULL);
128128
break;
129129
case RTM_NEWNEIGH:
130130
call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE,
131-
fdb->dst->dev, &info.info, NULL);
131+
dev, &info.info, NULL);
132132
break;
133133
}
134134
}

net/dsa/dsa2.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,9 @@ static int dsa_port_setup(struct dsa_port *dp)
348348
if (dp->setup)
349349
return 0;
350350

351+
INIT_LIST_HEAD(&dp->fdbs);
352+
INIT_LIST_HEAD(&dp->mdbs);
353+
351354
switch (dp->type) {
352355
case DSA_PORT_TYPE_UNUSED:
353356
dsa_port_disable(dp);
@@ -443,6 +446,7 @@ static int dsa_port_devlink_setup(struct dsa_port *dp)
443446
static void dsa_port_teardown(struct dsa_port *dp)
444447
{
445448
struct devlink_port *dlp = &dp->devlink_port;
449+
struct dsa_mac_addr *a, *tmp;
446450

447451
if (!dp->setup)
448452
return;
@@ -468,6 +472,16 @@ static void dsa_port_teardown(struct dsa_port *dp)
468472
break;
469473
}
470474

475+
list_for_each_entry_safe(a, tmp, &dp->fdbs, list) {
476+
list_del(&a->list);
477+
kfree(a);
478+
}
479+
480+
list_for_each_entry_safe(a, tmp, &dp->mdbs, list) {
481+
list_del(&a->list);
482+
kfree(a);
483+
}
484+
471485
dp->setup = false;
472486
}
473487

net/dsa/dsa_priv.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,17 @@ enum {
2020
DSA_NOTIFIER_BRIDGE_LEAVE,
2121
DSA_NOTIFIER_FDB_ADD,
2222
DSA_NOTIFIER_FDB_DEL,
23+
DSA_NOTIFIER_HOST_FDB_ADD,
24+
DSA_NOTIFIER_HOST_FDB_DEL,
2325
DSA_NOTIFIER_HSR_JOIN,
2426
DSA_NOTIFIER_HSR_LEAVE,
2527
DSA_NOTIFIER_LAG_CHANGE,
2628
DSA_NOTIFIER_LAG_JOIN,
2729
DSA_NOTIFIER_LAG_LEAVE,
2830
DSA_NOTIFIER_MDB_ADD,
2931
DSA_NOTIFIER_MDB_DEL,
32+
DSA_NOTIFIER_HOST_MDB_ADD,
33+
DSA_NOTIFIER_HOST_MDB_DEL,
3034
DSA_NOTIFIER_VLAN_ADD,
3135
DSA_NOTIFIER_VLAN_DEL,
3236
DSA_NOTIFIER_MTU,
@@ -112,13 +116,15 @@ struct dsa_notifier_mrp_ring_role_info {
112116
struct dsa_switchdev_event_work {
113117
struct dsa_switch *ds;
114118
int port;
119+
struct net_device *dev;
115120
struct work_struct work;
116121
unsigned long event;
117122
/* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and
118123
* SWITCHDEV_FDB_DEL_TO_DEVICE
119124
*/
120125
unsigned char addr[ETH_ALEN];
121126
u16 vid;
127+
bool host_addr;
122128
};
123129

124130
/* DSA_NOTIFIER_HSR_* */
@@ -209,11 +215,19 @@ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
209215
u16 vid);
210216
int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
211217
u16 vid);
218+
int dsa_port_host_fdb_add(struct dsa_port *dp, const unsigned char *addr,
219+
u16 vid);
220+
int dsa_port_host_fdb_del(struct dsa_port *dp, const unsigned char *addr,
221+
u16 vid);
212222
int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data);
213223
int dsa_port_mdb_add(const struct dsa_port *dp,
214224
const struct switchdev_obj_port_mdb *mdb);
215225
int dsa_port_mdb_del(const struct dsa_port *dp,
216226
const struct switchdev_obj_port_mdb *mdb);
227+
int dsa_port_host_mdb_add(const struct dsa_port *dp,
228+
const struct switchdev_obj_port_mdb *mdb);
229+
int dsa_port_host_mdb_del(const struct dsa_port *dp,
230+
const struct switchdev_obj_port_mdb *mdb);
217231
int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
218232
struct switchdev_brport_flags flags,
219233
struct netlink_ext_ack *extack);

0 commit comments

Comments
 (0)