summaryrefslogtreecommitdiffstats
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
parent8177a9d79c0e942dcac3312f15585d0344d505a5 (diff)
downloadlinux-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.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);
}
}