summary refs log tree commit diff
path: root/drivers/net
diff options
context:
space:
mode:
authorstephen hemminger <stephen@networkplumber.org>2013-06-17 12:09:57 -0700
committerDavid S. Miller <davem@davemloft.net>2013-06-17 15:55:46 -0700
commit3bf74b1aecdce719f1445200d5db7dfee2297bba (patch)
tree3c219f5bbe142d0e5c096caf9169b546d7d669e1 /drivers/net
parent8177a9d79c0e942dcac3312f15585d0344d505a5 (diff)
downloadlinux-3bf74b1aecdce719f1445200d5db7dfee2297bba.tar.gz
vxlan: fix race between flush and incoming learning
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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/vxlan.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 3b1d2ee7156b..577a069a6dde 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -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);
 	}
 }