diff options
author | stephen hemminger <stephen@networkplumber.org> | 2013-06-17 12:09:57 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-17 15:55:46 -0700 |
commit | 3bf74b1aecdce719f1445200d5db7dfee2297bba (patch) | |
tree | 3c219f5bbe142d0e5c096caf9169b546d7d669e1 | |
parent | 8177a9d79c0e942dcac3312f15585d0344d505a5 (diff) | |
download | linux-3bf74b1aecdce719f1445200d5db7dfee2297bba.tar.gz linux-3bf74b1aecdce719f1445200d5db7dfee2297bba.tar.bz2 linux-3bf74b1aecdce719f1445200d5db7dfee2297bba.zip |
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>
-rw-r--r-- | drivers/net/vxlan.c | 16 |
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); } } |