summaryrefslogtreecommitdiff
path: root/drivers/net/vxlan.c
diff options
context:
space:
mode:
authorTaehee Yoo <ap420073@gmail.com>2019-10-30 11:15:12 +0300
committerDavid S. Miller <davem@davemloft.net>2019-10-30 21:52:47 +0300
commitc6761cf521f9bffbdcbb619dba665ebf3bcefb1e (patch)
tree2239aae2ad437c9a5160029dee85b3f6335e7fcf /drivers/net/vxlan.c
parentdc99da4f31ce48d15684bde7916104064520025c (diff)
downloadlinux-c6761cf521f9bffbdcbb619dba665ebf3bcefb1e.tar.xz
vxlan: fix unexpected failure of vxlan_changelink()
After commit 0ce1822c2a08 ("vxlan: add adjacent link to limit depth level"), vxlan_changelink() could fail because of netdev_adjacent_change_prepare(). netdev_adjacent_change_prepare() returns -EEXIST when old lower device and new lower device are same. (old lower device is "dst->remote_dev" and new lower device is "lowerdev") So, before calling it, lowerdev should be NULL if these devices are same. Test command1: ip link add dummy0 type dummy ip link add vxlan0 type vxlan dev dummy0 dstport 4789 vni 1 ip link set vxlan0 type vxlan ttl 5 RTNETLINK answers: File exists Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Fixes: 0ce1822c2a08 ("vxlan: add adjacent link to limit depth level") Signed-off-by: Taehee Yoo <ap420073@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxlan.c')
-rw-r--r--drivers/net/vxlan.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index ac5c597aa703..8869154fad88 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -3967,6 +3967,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
if (err)
return err;
+ if (dst->remote_dev == lowerdev)
+ lowerdev = NULL;
+
err = netdev_adjacent_change_prepare(dst->remote_dev, lowerdev, dev,
extack);
if (err)
@@ -4008,10 +4011,10 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
mod_timer(&vxlan->age_timer, jiffies);
netdev_adjacent_change_commit(dst->remote_dev, lowerdev, dev);
- if (lowerdev && lowerdev != dst->remote_dev)
+ if (lowerdev && lowerdev != dst->remote_dev) {
dst->remote_dev = lowerdev;
-
- netdev_update_lockdep_key(lowerdev);
+ netdev_update_lockdep_key(lowerdev);
+ }
vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true);
return 0;
}