Commit b0fdb999 authored by David S. Miller's avatar David S. Miller

Merge branch 'switchdev-notifiers'

Vladimir Oltean says:

====================
Plug the last 2 holes in the switchdev notifiers for local FDB entries

The work for trapping local FDB entries to the CPU in switchdev/DSA
started with the "RX filtering in DSA" series:
https://patchwork.kernel.org/project/netdevbpf/cover/20210629140658.2510288-1-olteanv@gmail.com/
and was continued with further improvements such as "Fan out FDB entries
pointing towards the bridge to all switchdev member ports":
https://patchwork.kernel.org/project/netdevbpf/cover/20210719135140.278938-1-vladimir.oltean@nxp.com/
https://patchwork.kernel.org/project/netdevbpf/cover/20210720173557.999534-1-vladimir.oltean@nxp.com/

There are only 2 more issues left to be addressed (famous last words),
and these are:
- dynamically learned FDB entries towards interfaces foreign to DSA need
  to be replayed too
- adding/deleting a VLAN on a port causes the local FDB entries in that
  VLAN to be prematurely deleted

This patch series addresses both, and patch 2 depends on 1 to work properly.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1159da64 52e4bec1
...@@ -732,11 +732,11 @@ static inline size_t fdb_nlmsg_size(void) ...@@ -732,11 +732,11 @@ static inline size_t fdb_nlmsg_size(void)
+ nla_total_size(sizeof(u8)); /* NFEA_ACTIVITY_NOTIFY */ + nla_total_size(sizeof(u8)); /* NFEA_ACTIVITY_NOTIFY */
} }
static int br_fdb_replay_one(struct notifier_block *nb, static int br_fdb_replay_one(struct net_bridge *br, struct notifier_block *nb,
const struct net_bridge_fdb_entry *fdb, const struct net_bridge_fdb_entry *fdb,
struct net_device *dev, unsigned long action, unsigned long action, const void *ctx)
const void *ctx)
{ {
const struct net_bridge_port *p = READ_ONCE(fdb->dst);
struct switchdev_notifier_fdb_info item; struct switchdev_notifier_fdb_info item;
int err; int err;
...@@ -745,15 +745,15 @@ static int br_fdb_replay_one(struct notifier_block *nb, ...@@ -745,15 +745,15 @@ static int br_fdb_replay_one(struct notifier_block *nb,
item.added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags); item.added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
item.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags); item.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags);
item.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags); item.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags);
item.info.dev = dev; item.info.dev = item.is_local ? br->dev : p->dev;
item.info.ctx = ctx; item.info.ctx = ctx;
err = nb->notifier_call(nb, action, &item); err = nb->notifier_call(nb, action, &item);
return notifier_to_errno(err); return notifier_to_errno(err);
} }
int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev, int br_fdb_replay(const struct net_device *br_dev, const void *ctx, bool adding,
const void *ctx, bool adding, struct notifier_block *nb) struct notifier_block *nb)
{ {
struct net_bridge_fdb_entry *fdb; struct net_bridge_fdb_entry *fdb;
struct net_bridge *br; struct net_bridge *br;
...@@ -766,9 +766,6 @@ int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev, ...@@ -766,9 +766,6 @@ int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev,
if (!netif_is_bridge_master(br_dev)) if (!netif_is_bridge_master(br_dev))
return -EINVAL; return -EINVAL;
if (!netif_is_bridge_port(dev) && !netif_is_bridge_master(dev))
return -EINVAL;
br = netdev_priv(br_dev); br = netdev_priv(br_dev);
if (adding) if (adding)
...@@ -779,14 +776,7 @@ int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev, ...@@ -779,14 +776,7 @@ int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev,
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(fdb, &br->fdb_list, fdb_node) { hlist_for_each_entry_rcu(fdb, &br->fdb_list, fdb_node) {
const struct net_bridge_port *dst = READ_ONCE(fdb->dst); err = br_fdb_replay_one(br, nb, fdb, action, ctx);
struct net_device *dst_dev;
dst_dev = dst ? dst->dev : br->dev;
if (dst_dev && dst_dev != dev)
continue;
err = br_fdb_replay_one(nb, fdb, dst_dev, action, ctx);
if (err) if (err)
break; break;
} }
......
...@@ -777,8 +777,8 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, ...@@ -777,8 +777,8 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
bool swdev_notify); bool swdev_notify);
void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p, void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid, bool offloaded); const unsigned char *addr, u16 vid, bool offloaded);
int br_fdb_replay(const struct net_device *br_dev, const struct net_device *dev, int br_fdb_replay(const struct net_device *br_dev, const void *ctx, bool adding,
const void *ctx, bool adding, struct notifier_block *nb); struct notifier_block *nb);
/* br_forward.c */ /* br_forward.c */
enum br_pkt_type { enum br_pkt_type {
......
...@@ -127,7 +127,6 @@ br_switchdev_fdb_notify(struct net_bridge *br, ...@@ -127,7 +127,6 @@ br_switchdev_fdb_notify(struct net_bridge *br,
const struct net_bridge_fdb_entry *fdb, int type) const struct net_bridge_fdb_entry *fdb, int type)
{ {
const struct net_bridge_port *dst = READ_ONCE(fdb->dst); const struct net_bridge_port *dst = READ_ONCE(fdb->dst);
struct net_device *dev = dst ? dst->dev : br->dev;
struct switchdev_notifier_fdb_info info = { struct switchdev_notifier_fdb_info info = {
.addr = fdb->key.addr.addr, .addr = fdb->key.addr.addr,
.vid = fdb->key.vlan_id, .vid = fdb->key.vlan_id,
...@@ -135,6 +134,7 @@ br_switchdev_fdb_notify(struct net_bridge *br, ...@@ -135,6 +134,7 @@ br_switchdev_fdb_notify(struct net_bridge *br,
.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags), .is_local = test_bit(BR_FDB_LOCAL, &fdb->flags),
.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags), .offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags),
}; };
struct net_device *dev = info.is_local ? br->dev : dst->dev;
switch (type) { switch (type) {
case RTM_DELNEIGH: case RTM_DELNEIGH:
...@@ -287,13 +287,7 @@ static int nbp_switchdev_sync_objs(struct net_bridge_port *p, const void *ctx, ...@@ -287,13 +287,7 @@ static int nbp_switchdev_sync_objs(struct net_bridge_port *p, const void *ctx,
if (err && err != -EOPNOTSUPP) if (err && err != -EOPNOTSUPP)
return err; return err;
/* Forwarding and termination FDB entries on the port */ err = br_fdb_replay(br_dev, ctx, true, atomic_nb);
err = br_fdb_replay(br_dev, dev, ctx, true, atomic_nb);
if (err && err != -EOPNOTSUPP)
return err;
/* Termination FDB entries on the bridge itself */
err = br_fdb_replay(br_dev, br_dev, ctx, true, atomic_nb);
if (err && err != -EOPNOTSUPP) if (err && err != -EOPNOTSUPP)
return err; return err;
...@@ -312,11 +306,7 @@ static void nbp_switchdev_unsync_objs(struct net_bridge_port *p, ...@@ -312,11 +306,7 @@ static void nbp_switchdev_unsync_objs(struct net_bridge_port *p,
br_mdb_replay(br_dev, dev, ctx, false, blocking_nb, NULL); br_mdb_replay(br_dev, dev, ctx, false, blocking_nb, NULL);
/* Forwarding and termination FDB entries on the port */ br_fdb_replay(br_dev, ctx, false, atomic_nb);
br_fdb_replay(br_dev, dev, ctx, false, atomic_nb);
/* Termination FDB entries on the bridge itself */
br_fdb_replay(br_dev, br_dev, ctx, false, atomic_nb);
} }
/* Let the bridge know that this port is offloaded, so that it can assign a /* Let the bridge know that this port is offloaded, so that it can assign a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment