vxlan: fix race between flush and incoming learning
authorstephen hemminger <stephen@networkplumber.org>
Mon, 17 Jun 2013 19:09:57 +0000 (12:09 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 17 Jun 2013 22:55:46 +0000 (15:55 -0700)
It is possible for a packet to arrive during vxlan_stop(), and
have a dynamic entry created. Close this by checking if device
is up.

 CPU1                             CPU2
vxlan_stop
  vxlan_flush
     hash_lock acquired
                                  vxlan_encap_recv
                                     vxlan_snoop
                                        waiting for hash_lock
     hash_lock relased
  vxlan_flush done
                                        hash_lock acquired
                                        vxlan_fdb_create

This is a day-one bug in vxlan goes back to 3.7.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/vxlan.c

index 3b1d2ee..577a069 100644 (file)
@@ -571,7 +571,6 @@ static void vxlan_snoop(struct net_device *dev,
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_fdb *f;
-       int err;
 
        f = vxlan_find_mac(vxlan, src_mac);
        if (likely(f)) {
@@ -588,12 +587,15 @@ static void vxlan_snoop(struct net_device *dev,
        } else {
                /* learned new entry */
                spin_lock(&vxlan->hash_lock);
-               err = vxlan_fdb_create(vxlan, src_mac, src_ip,
-                                      NUD_REACHABLE,
-                                      NLM_F_EXCL|NLM_F_CREATE,
-                                      vxlan->dst_port,
-                                      vxlan->default_dst.remote_vni,
-                                      0, NTF_SELF);
+
+               /* close off race between vxlan_flush and incoming packets */
+               if (netif_running(dev))
+                       vxlan_fdb_create(vxlan, src_mac, src_ip,
+                                        NUD_REACHABLE,
+                                        NLM_F_EXCL|NLM_F_CREATE,
+                                        vxlan->dst_port,
+                                        vxlan->default_dst.remote_vni,
+                                        0, NTF_SELF);
                spin_unlock(&vxlan->hash_lock);
        }
 }