Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-block.git] / drivers / net / vxlan.c
index 5e2323592e084add6d025c8b9d9a800deca3f8e9..3d9bcc957f7da15b58aad5d9cb6acdb9803f4553 100644 (file)
@@ -812,6 +812,14 @@ static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan,
        return f;
 }
 
+static void vxlan_fdb_insert(struct vxlan_dev *vxlan, const u8 *mac,
+                            __be32 src_vni, struct vxlan_fdb *f)
+{
+       ++vxlan->addrcnt;
+       hlist_add_head_rcu(&f->hlist,
+                          vxlan_fdb_head(vxlan, mac, src_vni));
+}
+
 static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                            const u8 *mac, union vxlan_addr *ip,
                            __u16 state, __be16 port, __be32 src_vni,
@@ -837,18 +845,13 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                return rc;
        }
 
-       ++vxlan->addrcnt;
-       hlist_add_head_rcu(&f->hlist,
-                          vxlan_fdb_head(vxlan, mac, src_vni));
-
        *fdb = f;
 
        return 0;
 }
 
-static void vxlan_fdb_free(struct rcu_head *head)
+static void __vxlan_fdb_free(struct vxlan_fdb *f)
 {
-       struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu);
        struct vxlan_rdst *rd, *nd;
 
        list_for_each_entry_safe(rd, nd, &f->remotes, list) {
@@ -858,6 +861,13 @@ static void vxlan_fdb_free(struct rcu_head *head)
        kfree(f);
 }
 
+static void vxlan_fdb_free(struct rcu_head *head)
+{
+       struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu);
+
+       __vxlan_fdb_free(f);
+}
+
 static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
                              bool do_notify, bool swdev_notify)
 {
@@ -985,6 +995,7 @@ static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
        if (rc < 0)
                return rc;
 
+       vxlan_fdb_insert(vxlan, mac, src_vni, f);
        rc = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
                              swdev_notify, extack);
        if (rc)
@@ -3588,12 +3599,17 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev,
        if (err)
                goto errout;
 
-       /* notify default fdb entry */
        if (f) {
+               vxlan_fdb_insert(vxlan, all_zeros_mac,
+                                vxlan->default_dst.remote_vni, f);
+
+               /* notify default fdb entry */
                err = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f),
                                       RTM_NEWNEIGH, true, extack);
-               if (err)
-                       goto errout;
+               if (err) {
+                       vxlan_fdb_destroy(vxlan, f, false, false);
+                       goto unregister;
+               }
        }
 
        list_add(&vxlan->next, &vn->vxlan_list);
@@ -3605,7 +3621,8 @@ errout:
         * destroy the entry by hand here.
         */
        if (f)
-               vxlan_fdb_destroy(vxlan, f, false, false);
+               __vxlan_fdb_free(f);
+unregister:
        if (unregister)
                unregister_netdevice(dev);
        return err;