Notify user space on offload flag(s) change. This behavior is controlled by the new knob mdb_notify_on_flag_change:
0 - the bridge will not notify user space about MDB flag change 1 - the bridge will notify user space about flag change if either MDB_PG_FLAGS_OFFLOAD or MDB_PG_FLAGS_OFFLOAD_FAILED has changed 2 - the bridge will notify user space about flag change only if MDB_PG_FLAGS_OFFLOAD_FAILED has changed The default value is 0. Signed-off-by: Joseph Huang <joseph.hu...@garmin.com> --- net/bridge/br_mdb.c | 28 +++++++++++++++++++++++----- net/bridge/br_multicast.c | 25 +++++++++++++++++++++++++ net/bridge/br_private.h | 15 +++++++++++++++ net/bridge/br_switchdev.c | 25 +++++++++++++++++++++++-- 4 files changed, 86 insertions(+), 7 deletions(-) diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 0639691cd19b..d206b5a160f3 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -519,16 +519,17 @@ static size_t rtnl_mdb_nlmsg_size(const struct net_bridge_port_group *pg) rtnl_mdb_nlmsg_pg_size(pg); } -void br_mdb_notify(struct net_device *dev, - struct net_bridge_mdb_entry *mp, - struct net_bridge_port_group *pg, - int type) +static void _br_mdb_notify(struct net_device *dev, + struct net_bridge_mdb_entry *mp, + struct net_bridge_port_group *pg, + int type, bool notify_switchdev) { struct net *net = dev_net(dev); struct sk_buff *skb; int err = -ENOBUFS; - br_switchdev_mdb_notify(dev, mp, pg, type); + if (notify_switchdev) + br_switchdev_mdb_notify(dev, mp, pg, type); skb = nlmsg_new(rtnl_mdb_nlmsg_size(pg), GFP_ATOMIC); if (!skb) @@ -546,6 +547,23 @@ void br_mdb_notify(struct net_device *dev, rtnl_set_sk_err(net, RTNLGRP_MDB, err); } +void br_mdb_notify(struct net_device *dev, + struct net_bridge_mdb_entry *mp, + struct net_bridge_port_group *pg, + int type) +{ + _br_mdb_notify(dev, mp, pg, type, true); +} + +#ifdef CONFIG_NET_SWITCHDEV +void br_mdb_flag_change_notify(struct net_device *dev, + struct net_bridge_mdb_entry *mp, + struct net_bridge_port_group *pg) +{ + _br_mdb_notify(dev, mp, pg, RTM_NEWMDB, false); +} +#endif + static int nlmsg_populate_rtr_fill(struct sk_buff *skb, struct net_device *dev, int ifindex, u16 vid, u32 pid, diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index b2ae0d2434d2..8d583caecd40 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -4051,6 +4051,10 @@ void br_multicast_ctx_init(struct net_bridge *br, brmctx->ip6_querier.port_ifidx = 0; seqcount_spinlock_init(&brmctx->ip6_querier.seq, &br->multicast_lock); #endif +#ifdef CONFIG_NET_SWITCHDEV + brmctx->multicast_mdb_notify_on_flag_change = + MDB_NOTIFY_ON_FLAG_CHANGE_DISABLE; +#endif timer_setup(&brmctx->ip4_mc_router_timer, br_ip4_multicast_local_router_expired, 0); @@ -4708,6 +4712,27 @@ int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx, } #endif +#ifdef CONFIG_NET_SWITCHDEV +int br_multicast_set_mdb_notify_on_flag_change(struct net_bridge_mcast *brmctx, + u8 val) +{ + switch (val) { + case MDB_NOTIFY_ON_FLAG_CHANGE_DISABLE: + case MDB_NOTIFY_ON_FLAG_CHANGE_BOTH: + case MDB_NOTIFY_ON_FLAG_CHANGE_FAIL_ONLY: + break; + default: + return -EINVAL; + } + + spin_lock_bh(&brmctx->br->multicast_lock); + brmctx->multicast_mdb_notify_on_flag_change = val; + spin_unlock_bh(&brmctx->br->multicast_lock); + + return 0; +} +#endif + void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx, unsigned long val) { diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index cd6b4e91e7d6..8e8de5d54ae3 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -132,6 +132,10 @@ struct net_bridge_mcast_port { #endif /* CONFIG_BRIDGE_IGMP_SNOOPING */ }; +#define MDB_NOTIFY_ON_FLAG_CHANGE_DISABLE 0 +#define MDB_NOTIFY_ON_FLAG_CHANGE_BOTH 1 +#define MDB_NOTIFY_ON_FLAG_CHANGE_FAIL_ONLY 2 + /* net_bridge_mcast must be always defined due to forwarding stubs */ struct net_bridge_mcast { #ifdef CONFIG_BRIDGE_IGMP_SNOOPING @@ -146,6 +150,9 @@ struct net_bridge_mcast { u8 multicast_router; #if IS_ENABLED(CONFIG_IPV6) u8 multicast_mld_version; +#endif +#ifdef CONFIG_NET_SWITCHDEV + u8 multicast_mdb_notify_on_flag_change; #endif unsigned long multicast_last_member_interval; unsigned long multicast_membership_interval; @@ -988,6 +995,10 @@ int br_multicast_set_igmp_version(struct net_bridge_mcast *brmctx, int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx, unsigned long val); #endif +#ifdef CONFIG_NET_SWITCHDEV +int br_multicast_set_mdb_notify_on_flag_change(struct net_bridge_mcast *brmctx, + u8 val); +#endif struct net_bridge_mdb_entry * br_mdb_ip_get(struct net_bridge *br, struct br_ip *dst); struct net_bridge_mdb_entry * @@ -1004,6 +1015,10 @@ int br_mdb_hash_init(struct net_bridge *br); void br_mdb_hash_fini(struct net_bridge *br); void br_mdb_notify(struct net_device *dev, struct net_bridge_mdb_entry *mp, struct net_bridge_port_group *pg, int type); +#ifdef CONFIG_NET_SWITCHDEV +void br_mdb_flag_change_notify(struct net_device *dev, struct net_bridge_mdb_entry *mp, + struct net_bridge_port_group *pg); +#endif void br_rtr_notify(struct net_device *dev, struct net_bridge_mcast_port *pmctx, int type); void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 68dccc2ff7b1..5b09cfcdf3f3 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -504,20 +504,41 @@ static void br_switchdev_mdb_complete(struct net_device *dev, int err, void *pri struct net_bridge_mdb_entry *mp; struct net_bridge_port *port = data->port; struct net_bridge *br = port->br; + bool offload_changed = false; + bool failed_changed = false; + u8 notify; spin_lock_bh(&br->multicast_lock); mp = br_mdb_ip_get(br, &data->ip); if (!mp) goto out; + + notify = br->multicast_ctx.multicast_mdb_notify_on_flag_change; + for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL; pp = &p->next) { if (p->key.port != port) continue; - if (err) + if (err) { + if (!(p->flags & MDB_PG_FLAGS_OFFLOAD_FAILED)) + failed_changed = true; p->flags |= MDB_PG_FLAGS_OFFLOAD_FAILED; - else + } else { + if (!(p->flags & MDB_PG_FLAGS_OFFLOAD)) + offload_changed = true; p->flags |= MDB_PG_FLAGS_OFFLOAD; + } + + if (notify == MDB_NOTIFY_ON_FLAG_CHANGE_DISABLE || + (!offload_changed && !failed_changed)) + continue; + + if (notify == MDB_NOTIFY_ON_FLAG_CHANGE_FAIL_ONLY && + !failed_changed) + continue; + + br_mdb_flag_change_notify(br->dev, mp, p); } out: spin_unlock_bh(&br->multicast_lock); -- 2.49.0