vxlan: Split vxlan_fdb_update() in two
authorPetr Machata <petrm@mellanox.com>
Wed, 16 Jan 2019 23:06:32 +0000 (23:06 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 17 Jan 2019 23:18:46 +0000 (15:18 -0800)
In order to make it easier to implement rollbacks after FDB update
vetoing, separate the FDB update code to two parts: one that deals with
updates of existing FDB entries, and one that creates new entries.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/vxlan.c

index e4ace5e917a7ec4f0cd116be1a555bc58bbc1f21..aeaa429229c75185411c9febf9f31106de67d055 100644 (file)
@@ -855,92 +855,128 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
        call_rcu(&f->rcu, vxlan_fdb_free);
 }
 
-/* Add new entry to forwarding table -- assumes lock held */
-static int vxlan_fdb_update(struct vxlan_dev *vxlan,
-                           const u8 *mac, union vxlan_addr *ip,
-                           __u16 state, __u16 flags,
-                           __be16 port, __be32 src_vni, __be32 vni,
-                           __u32 ifindex, __u16 ndm_flags,
-                           bool swdev_notify)
+static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
+                                    union vxlan_addr *ip,
+                                    __u16 state, __u16 flags,
+                                    __be16 port, __be32 vni,
+                                    __u32 ifindex, __u16 ndm_flags,
+                                    struct vxlan_fdb *f,
+                                    bool swdev_notify)
 {
        __u16 fdb_flags = (ndm_flags & ~NTF_USE);
        struct vxlan_rdst *rd = NULL;
-       struct vxlan_fdb *f;
        int notify = 0;
        int rc;
 
-       f = __vxlan_find_mac(vxlan, mac, src_vni);
-       if (f) {
-               if (flags & NLM_F_EXCL) {
-                       netdev_dbg(vxlan->dev,
-                                  "lost race to create %pM\n", mac);
-                       return -EEXIST;
-               }
-
-               /* Do not allow an externally learned entry to take over an
-                * entry added by the user.
-                */
-               if (!(fdb_flags & NTF_EXT_LEARNED) ||
-                   !(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
-                       if (f->state != state) {
-                               f->state = state;
-                               f->updated = jiffies;
-                               notify = 1;
-                       }
-                       if (f->flags != fdb_flags) {
-                               f->flags = fdb_flags;
-                               f->updated = jiffies;
-                               notify = 1;
-                       }
+       /* Do not allow an externally learned entry to take over an entry added
+        * by the user.
+        */
+       if (!(fdb_flags & NTF_EXT_LEARNED) ||
+           !(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
+               if (f->state != state) {
+                       f->state = state;
+                       f->updated = jiffies;
+                       notify = 1;
                }
-
-               if ((flags & NLM_F_REPLACE)) {
-                       /* Only change unicasts */
-                       if (!(is_multicast_ether_addr(f->eth_addr) ||
-                            is_zero_ether_addr(f->eth_addr))) {
-                               notify |= vxlan_fdb_replace(f, ip, port, vni,
-                                                          ifindex);
-                       } else
-                               return -EOPNOTSUPP;
+               if (f->flags != fdb_flags) {
+                       f->flags = fdb_flags;
+                       f->updated = jiffies;
+                       notify = 1;
                }
-               if ((flags & NLM_F_APPEND) &&
-                   (is_multicast_ether_addr(f->eth_addr) ||
-                    is_zero_ether_addr(f->eth_addr))) {
-                       rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
+       }
 
-                       if (rc < 0)
-                               return rc;
+       if ((flags & NLM_F_REPLACE)) {
+               /* Only change unicasts */
+               if (!(is_multicast_ether_addr(f->eth_addr) ||
+                     is_zero_ether_addr(f->eth_addr))) {
+                       rc = vxlan_fdb_replace(f, ip, port, vni,
+                                              ifindex);
                        notify |= rc;
-               }
-
-               if (ndm_flags & NTF_USE)
-                       f->used = jiffies;
-       } else {
-               if (!(flags & NLM_F_CREATE))
-                       return -ENOENT;
-
-               /* Disallow replace to add a multicast entry */
-               if ((flags & NLM_F_REPLACE) &&
-                   (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac)))
+               } else {
                        return -EOPNOTSUPP;
+               }
+       }
+       if ((flags & NLM_F_APPEND) &&
+           (is_multicast_ether_addr(f->eth_addr) ||
+            is_zero_ether_addr(f->eth_addr))) {
+               rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
 
-               netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
-               rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni,
-                                     vni, ifindex, fdb_flags, &f);
                if (rc < 0)
                        return rc;
-               notify = 1;
+               notify |= rc;
        }
 
+       if (ndm_flags & NTF_USE)
+               f->used = jiffies;
+
        if (notify) {
                if (rd == NULL)
                        rd = first_remote_rtnl(f);
+
                vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify);
        }
 
        return 0;
 }
 
+static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
+                                  const u8 *mac, union vxlan_addr *ip,
+                                  __u16 state, __u16 flags,
+                                  __be16 port, __be32 src_vni, __be32 vni,
+                                  __u32 ifindex, __u16 ndm_flags,
+                                  bool swdev_notify)
+{
+       __u16 fdb_flags = (ndm_flags & ~NTF_USE);
+       struct vxlan_fdb *f;
+       int rc;
+
+       /* Disallow replace to add a multicast entry */
+       if ((flags & NLM_F_REPLACE) &&
+           (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac)))
+               return -EOPNOTSUPP;
+
+       netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
+       rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni,
+                             vni, ifindex, fdb_flags, &f);
+       if (rc < 0)
+               return rc;
+
+       vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
+                        swdev_notify);
+       return 0;
+}
+
+/* Add new entry to forwarding table -- assumes lock held */
+static int vxlan_fdb_update(struct vxlan_dev *vxlan,
+                           const u8 *mac, union vxlan_addr *ip,
+                           __u16 state, __u16 flags,
+                           __be16 port, __be32 src_vni, __be32 vni,
+                           __u32 ifindex, __u16 ndm_flags,
+                           bool swdev_notify)
+{
+       struct vxlan_fdb *f;
+
+       f = __vxlan_find_mac(vxlan, mac, src_vni);
+       if (f) {
+               if (flags & NLM_F_EXCL) {
+                       netdev_dbg(vxlan->dev,
+                                  "lost race to create %pM\n", mac);
+                       return -EEXIST;
+               }
+
+               return vxlan_fdb_update_existing(vxlan, ip, state, flags, port,
+                                                vni, ifindex, ndm_flags, f,
+                                                swdev_notify);
+       } else {
+               if (!(flags & NLM_F_CREATE))
+                       return -ENOENT;
+
+               return vxlan_fdb_update_create(vxlan, mac, ip, state, flags,
+                                              port, src_vni, vni, ifindex,
+                                              ndm_flags, swdev_notify);
+       }
+}
+
 static void vxlan_dst_free(struct rcu_head *head)
 {
        struct vxlan_rdst *rd = container_of(head, struct vxlan_rdst, rcu);