ndo_fdb_add: Add a parameter to report whether notification was sent
authorPetr Machata <petrm@nvidia.com>
Thu, 14 Nov 2024 14:09:53 +0000 (15:09 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sat, 16 Nov 2024 00:39:18 +0000 (16:39 -0800)
Currently when FDB entries are added to or deleted from a VXLAN netdevice,
the VXLAN driver emits one notification, including the VXLAN-specific
attributes. The core however always sends a notification as well, a generic
one. Thus two notifications are unnecessarily sent for these operations. A
similar situation comes up with bridge driver, which also emits
notifications on its own:

 # ip link add name vx type vxlan id 1000 dstport 4789
 # bridge monitor fdb &
 [1] 1981693
 # bridge fdb add de:ad:be:ef:13:37 dev vx self dst 192.0.2.1
 de:ad:be:ef:13:37 dev vx dst 192.0.2.1 self permanent
 de:ad:be:ef:13:37 dev vx self permanent

In order to prevent this duplicity, add a paremeter to ndo_fdb_add,
bool *notified. The flag is primed to false, and if the callee sends a
notification on its own, it sets it to true, thus informing the core that
it should not generate another notification.

Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Amit Cohen <amcohen@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/cbf6ae8195e85cbf922f8058ce4eba770f3b71ed.1731589511.git.petrm@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 files changed:
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/mscc/ocelot_net.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/macvlan.c
drivers/net/vxlan/vxlan_core.c
include/linux/netdevice.h
net/bridge/br_fdb.c
net/bridge/br_private.h
net/core/rtnetlink.c

index 55fb362..ab5febf 100644 (file)
@@ -13095,12 +13095,13 @@ static int i40e_get_phys_port_id(struct net_device *netdev,
  * @addr: the MAC address entry being added
  * @vid: VLAN ID
  * @flags: instructions from stack about fdb operation
+ * @notified: whether notification was emitted
  * @extack: netlink extended ack, unused currently
  */
 static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                            struct net_device *dev,
                            const unsigned char *addr, u16 vid,
-                           u16 flags,
+                           u16 flags, bool *notified,
                            struct netlink_ext_ack *extack)
 {
        struct i40e_netdev_priv *np = netdev_priv(dev);
index a6f586f..c875036 100644 (file)
@@ -6125,12 +6125,14 @@ ice_set_tx_maxrate(struct net_device *netdev, int queue_index, u32 maxrate)
  * @addr: the MAC address entry being added
  * @vid: VLAN ID
  * @flags: instructions from stack about fdb operation
+ * @notified: whether notification was emitted
  * @extack: netlink extended ack
  */
 static int
 ice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[],
            struct net_device *dev, const unsigned char *addr, u16 vid,
-           u16 flags, struct netlink_ext_ack __always_unused *extack)
+           u16 flags, bool *notified,
+           struct netlink_ext_ack __always_unused *extack)
 {
        int err;
 
index f1d0881..f0528bd 100644 (file)
@@ -2486,7 +2486,7 @@ static int igb_set_features(struct net_device *netdev,
 static int igb_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                           struct net_device *dev,
                           const unsigned char *addr, u16 vid,
-                          u16 flags,
+                          u16 flags, bool *notified,
                           struct netlink_ext_ack *extack)
 {
        /* guarantee we can provide a unique filter for the unicast address */
index 8b8404d..adc9392 100644 (file)
@@ -9954,7 +9954,7 @@ static int ixgbe_set_features(struct net_device *netdev,
 static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                             struct net_device *dev,
                             const unsigned char *addr, u16 vid,
-                            u16 flags,
+                            u16 flags, bool *notified,
                             struct netlink_ext_ack *extack)
 {
        /* guarantee we can provide a unique filter for the unicast address */
index 7c9540a..4f15ba2 100644 (file)
@@ -730,7 +730,7 @@ static void ocelot_get_stats64(struct net_device *dev,
 static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                               struct net_device *dev,
                               const unsigned char *addr,
-                              u16 vid, u16 flags,
+                              u16 vid, u16 flags, bool *notified,
                               struct netlink_ext_ack *extack)
 {
        struct ocelot_port_private *priv = netdev_priv(dev);
index b3588a1..2484ceb 100644 (file)
@@ -394,7 +394,7 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
 static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                        struct net_device *netdev,
                        const unsigned char *addr, u16 vid, u16 flags,
-                       struct netlink_ext_ack *extack)
+                       bool *notified, struct netlink_ext_ack *extack)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int err = 0;
index edbd5af..dfb462e 100644 (file)
@@ -1024,7 +1024,7 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev,
 static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                           struct net_device *dev,
                           const unsigned char *addr, u16 vid,
-                          u16 flags,
+                          u16 flags, bool *notified,
                           struct netlink_ext_ack *extack)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
index 42b07bc..22f17c5 100644 (file)
@@ -1241,7 +1241,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
 static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                         struct net_device *dev,
                         const unsigned char *addr, u16 vid, u16 flags,
-                        struct netlink_ext_ack *extack)
+                        bool *notified, struct netlink_ext_ack *extack)
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
        /* struct net *net = dev_net(vxlan->dev); */
@@ -1277,6 +1277,9 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                               nhid, true, extack);
        spin_unlock_bh(&vxlan->hash_lock[hash_index]);
 
+       if (!err)
+               *notified = true;
+
        return err;
 }
 
index 0aae346..6a7fd19 100644 (file)
@@ -1248,8 +1248,10 @@ struct netdev_net_notifier {
  * int (*ndo_fdb_add)(struct ndmsg *ndm, struct nlattr *tb[],
  *                   struct net_device *dev,
  *                   const unsigned char *addr, u16 vid, u16 flags,
- *                   struct netlink_ext_ack *extack);
+ *                   bool *notified, struct netlink_ext_ack *extack);
  *     Adds an FDB entry to dev for addr.
+ *     Callee shall set *notified to true if it sent any appropriate
+ *     notification(s). Otherwise core will send a generic one.
  * int (*ndo_fdb_del)(struct ndmsg *ndm, struct nlattr *tb[],
  *                   struct net_device *dev,
  *                   const unsigned char *addr, u16 vid)
@@ -1525,6 +1527,7 @@ struct net_device_ops {
                                               const unsigned char *addr,
                                               u16 vid,
                                               u16 flags,
+                                              bool *notified,
                                               struct netlink_ext_ack *extack);
        int                     (*ndo_fdb_del)(struct ndmsg *ndm,
                                               struct nlattr *tb[],
index 77f1100..5f29958 100644 (file)
@@ -1152,7 +1152,7 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
 static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
                        struct net_bridge_port *p, const unsigned char *addr,
                        u16 nlh_flags, u16 vid, struct nlattr *nfea_tb[],
-                       struct netlink_ext_ack *extack)
+                       bool *notified, struct netlink_ext_ack *extack)
 {
        int err = 0;
 
@@ -1183,6 +1183,8 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
                spin_unlock_bh(&br->hash_lock);
        }
 
+       if (!err)
+               *notified = true;
        return err;
 }
 
@@ -1195,7 +1197,7 @@ static const struct nla_policy br_nda_fdb_pol[NFEA_MAX + 1] = {
 int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
               struct net_device *dev,
               const unsigned char *addr, u16 vid, u16 nlh_flags,
-              struct netlink_ext_ack *extack)
+              bool *notified, struct netlink_ext_ack *extack)
 {
        struct nlattr *nfea_tb[NFEA_MAX + 1], *attr;
        struct net_bridge_vlan_group *vg;
@@ -1258,10 +1260,10 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 
                /* VID was specified, so use it. */
                err = __br_fdb_add(ndm, br, p, addr, nlh_flags, vid, nfea_tb,
-                                  extack);
+                                  notified, extack);
        } else {
                err = __br_fdb_add(ndm, br, p, addr, nlh_flags, 0, nfea_tb,
-                                  extack);
+                                  notified, extack);
                if (err || !vg || !vg->num_vlans)
                        goto out;
 
@@ -1273,7 +1275,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                        if (!br_vlan_should_use(v))
                                continue;
                        err = __br_fdb_add(ndm, br, p, addr, nlh_flags, v->vid,
-                                          nfea_tb, extack);
+                                          nfea_tb, notified, extack);
                        if (err)
                                goto out;
                }
index 041f6e5..ebfc590 100644 (file)
@@ -858,7 +858,7 @@ int br_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev,
                       struct netlink_ext_ack *extack);
 int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev,
               const unsigned char *addr, u16 vid, u16 nlh_flags,
-              struct netlink_ext_ack *extack);
+              bool *notified, struct netlink_ext_ack *extack);
 int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
                struct net_device *dev, struct net_device *fdev, int *idx);
 int br_fdb_get(struct sk_buff *skb, struct nlattr *tb[], struct net_device *dev,
index 327fa49..f31b243 100644 (file)
@@ -4578,9 +4578,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
            netif_is_bridge_port(dev)) {
                struct net_device *br_dev = netdev_master_upper_dev_get(dev);
                const struct net_device_ops *ops = br_dev->netdev_ops;
+               bool notified = false;
 
                err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid,
-                                      nlh->nlmsg_flags, extack);
+                                      nlh->nlmsg_flags, &notified, extack);
                if (err)
                        goto out;
                else
@@ -4589,16 +4590,18 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        /* Embedded bridge, macvlan, and any other device support */
        if ((ndm->ndm_flags & NTF_SELF)) {
+               bool notified = false;
+
                if (dev->netdev_ops->ndo_fdb_add)
                        err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr,
                                                           vid,
                                                           nlh->nlmsg_flags,
-                                                          extack);
+                                                          &notified, extack);
                else
                        err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid,
                                               nlh->nlmsg_flags);
 
-               if (!err) {
+               if (!err && !notified) {
                        rtnl_fdb_notify(dev, addr, vid, RTM_NEWNEIGH,
                                        ndm->ndm_state);
                        ndm->ndm_flags &= ~NTF_SELF;