Do not automatically bail out on sending notifications about activity on non-user-added FDB entries. Instead, notify about this activity except for cases where the activity itself originates in a notification, to avoid sending duplicate notifications.
Signed-off-by: Petr Machata <pe...@mellanox.com> --- net/bridge/br.c | 4 ++-- net/bridge/br_fdb.c | 40 +++++++++++++++++++++++++++------------- net/bridge/br_private.h | 4 ++-- net/bridge/br_switchdev.c | 2 +- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/net/bridge/br.c b/net/bridge/br.c index 671d13c..c6b033e 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -141,7 +141,7 @@ static int br_switchdev_event(struct notifier_block *unused, case SWITCHDEV_FDB_ADD_TO_BRIDGE: fdb_info = ptr; err = br_fdb_external_learn_add(br, p, fdb_info->addr, - fdb_info->vid); + fdb_info->vid, false); if (err) { err = notifier_from_errno(err); break; @@ -152,7 +152,7 @@ static int br_switchdev_event(struct notifier_block *unused, case SWITCHDEV_FDB_DEL_TO_BRIDGE: fdb_info = ptr; err = br_fdb_external_learn_del(br, p, fdb_info->addr, - fdb_info->vid); + fdb_info->vid, false); if (err) err = notifier_from_errno(err); break; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index a1c409c..272d1a2 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -39,8 +39,8 @@ static const struct rhashtable_params br_fdb_rht_params = { static struct kmem_cache *br_fdb_cache __read_mostly; static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr, u16 vid); -static void fdb_notify(struct net_bridge *br, - const struct net_bridge_fdb_entry *, int); +static void __fdb_notify(struct net_bridge *br, + const struct net_bridge_fdb_entry *, int, bool); int __init br_fdb_init(void) { @@ -195,7 +195,8 @@ static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr) } } -static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) +static void __fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f, + bool notify) { trace_fdb_delete(br, f); @@ -205,10 +206,15 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) hlist_del_init_rcu(&f->fdb_node); rhashtable_remove_fast(&br->fdb_hash_tbl, &f->rhnode, br_fdb_rht_params); - fdb_notify(br, f, RTM_DELNEIGH); + __fdb_notify(br, f, RTM_DELNEIGH, notify); call_rcu(&f->rcu, fdb_rcu_free); } +static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) +{ + __fdb_delete(br, f, true); +} + /* Delete a local entry if no other port had the same address. */ static void fdb_delete_local(struct net_bridge *br, const struct net_bridge_port *p, @@ -514,6 +520,12 @@ static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br, return fdb; } +static void fdb_notify(struct net_bridge *br, + const struct net_bridge_fdb_entry *fdb, int type) +{ + __fdb_notify(br, fdb, type, true); +} + static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr, u16 vid) { @@ -686,14 +698,16 @@ static inline size_t fdb_nlmsg_size(void) + nla_total_size(sizeof(struct nda_cacheinfo)); } -static void fdb_notify(struct net_bridge *br, - const struct net_bridge_fdb_entry *fdb, int type) +static void __fdb_notify(struct net_bridge *br, + const struct net_bridge_fdb_entry *fdb, int type, + bool notify) { struct net *net = dev_net(br->dev); struct sk_buff *skb; int err = -ENOBUFS; - br_switchdev_fdb_notify(fdb, type); + if (notify) + br_switchdev_fdb_notify(fdb, type); skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) @@ -856,7 +870,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br, rcu_read_unlock(); local_bh_enable(); } else if (ndm->ndm_flags & NTF_EXT_LEARNED) { - err = br_fdb_external_learn_add(br, p, addr, vid); + err = br_fdb_external_learn_add(br, p, addr, vid, true); } else { spin_lock_bh(&br->hash_lock); err = fdb_add_entry(br, p, addr, ndm->ndm_state, @@ -1065,7 +1079,7 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p) } int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, - const unsigned char *addr, u16 vid) + const unsigned char *addr, u16 vid, bool notify) { struct net_bridge_fdb_entry *fdb; bool modified = false; @@ -1083,7 +1097,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, goto err_unlock; } fdb->added_by_external_learn = 1; - fdb_notify(br, fdb, RTM_NEWNEIGH); + __fdb_notify(br, fdb, RTM_NEWNEIGH, notify); } else { fdb->updated = jiffies; @@ -1102,7 +1116,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, } if (modified) - fdb_notify(br, fdb, RTM_NEWNEIGH); + __fdb_notify(br, fdb, RTM_NEWNEIGH, notify); } err_unlock: @@ -1112,7 +1126,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, } int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, - const unsigned char *addr, u16 vid) + const unsigned char *addr, u16 vid, bool notify) { struct net_bridge_fdb_entry *fdb; int err = 0; @@ -1121,7 +1135,7 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, fdb = br_fdb_find(br, addr, vid); if (fdb && fdb->added_by_external_learn) - fdb_delete(br, fdb); + __fdb_delete(br, fdb, notify); else err = -ENOENT; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 1a50931..b9ab4e5 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -553,9 +553,9 @@ int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, - const unsigned char *addr, u16 vid); + const unsigned char *addr, u16 vid, bool notify); int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, - const unsigned char *addr, u16 vid); + const unsigned char *addr, u16 vid, bool notify); void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p, const unsigned char *addr, u16 vid); diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 71a03c4..35474d4 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -118,7 +118,7 @@ br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac, void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) { - if (!fdb->added_by_user || !fdb->dst) + if (!fdb->dst) return; switch (type) { -- 2.4.11