]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
vxlan: fix test which detect duplicate vxlan iface
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Thu, 7 Jan 2016 10:26:53 +0000 (11:26 +0100)
committerLuis Henriques <luis.henriques@canonical.com>
Thu, 28 Jan 2016 10:40:23 +0000 (10:40 +0000)
commit 07b9b37c227cb8d88d478b4a9c5634fee514ede1 upstream.

When a vxlan interface is created, the driver checks that there is not
another vxlan interface with the same properties. To do this, it checks
the existing vxlan udp socket. Since commit 1c51a9159dde, the creation of
the vxlan socket is done only when the interface is set up, thus it breaks
that test.

Example:
$ ip l a vxlan10 type vxlan id 10 group 239.0.0.10 dev eth0 dstport 0
$ ip l a vxlan11 type vxlan id 10 group 239.0.0.10 dev eth0 dstport 0
$ ip -br l | grep vxlan
vxlan10          DOWN           f2:55:1c:6a:fb:00 <BROADCAST,MULTICAST>
vxlan11          DOWN           7a:cb:b9:38:59:0d <BROADCAST,MULTICAST>

Instead of checking sockets, let's loop over the vxlan iface list.

Fixes: 1c51a9159dde ("vxlan: fix race caused by dropping rtnl_unlock")
Reported-by: Thomas Faivre <thomas.faivre@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
[ luis: backported to 3.16: used davem's backport to 3.18 ]
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
drivers/net/vxlan.c
include/net/vxlan.h

index 8a7a35c4f6bd3397245a664b4d80d79ca0d04f76..74dccfa00a5ca340abf3d8cc53bf944f748c890e 100644 (file)
@@ -2579,7 +2579,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
                         struct nlattr *tb[], struct nlattr *data[])
 {
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
-       struct vxlan_dev *vxlan = netdev_priv(dev);
+       struct vxlan_dev *vxlan = netdev_priv(dev), *tmp;
        struct vxlan_rdst *dst = &vxlan->default_dst;
        __u32 vni;
        int err;
@@ -2704,9 +2704,13 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
            nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
                vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX;
 
-       if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET,
-                          vxlan->dst_port)) {
-               pr_info("duplicate VNI %u\n", vni);
+       list_for_each_entry(tmp, &vn->vxlan_list, next) {
+               if (tmp->default_dst.remote_vni == vni &&
+                   (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 ||
+                    tmp->saddr.sa.sa_family == AF_INET6) == use_ipv6 &&
+                   tmp->dst_port == vxlan->dst_port &&
+                   (tmp->flags & VXLAN_F_RCV_FLAGS) ==
+                   (vxlan->flags & VXLAN_F_RCV_FLAGS))
                return -EEXIST;
        }
 
index 12196ce661d9e288a3d3928ccd66cefff10920a9..94f5391736fe7bcf231a5550059be4f36deb513e 100644 (file)
@@ -34,6 +34,11 @@ struct vxlan_sock {
 #define VXLAN_F_UDP_ZERO_CSUM6_TX      0x80
 #define VXLAN_F_UDP_ZERO_CSUM6_RX      0x100
 
+/* Flags that are used in the receive path. These flags must match in
+ * order for a socket to be shareable
+ */
+#define VXLAN_F_RCV_FLAGS              VXLAN_F_UDP_ZERO_CSUM6_RX
+
 struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
                                  vxlan_rcv_t *rcv, void *data,
                                  bool no_share, u32 flags);