A VXLAN net_device looking for an appropriate socket may only consider
a socket which has a matching set of extensions enabled. If the
extensions don't match, return a conflict to have the caller create a
distinct socket with distinct port.

The OVS VXLAN port is kept unaware of extensions at this point.

Signed-off-by: Thomas Graf <tg...@suug.ch>
---
v3->v4:
 - No change
v2->v3:
 - No change
v1->v2:
 - Improved commit message, reported by Jesse

 drivers/net/vxlan.c           | 35 +++++++++++++++++++++--------------
 include/net/vxlan.h           |  2 +-
 net/openvswitch/vport-vxlan.c |  2 +-
 3 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 72c4e30..f41eb91 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -265,14 +265,15 @@ static inline struct vxlan_rdst *first_remote_rtnl(struct 
vxlan_fdb *fdb)
 }
 
 /* Find VXLAN socket based on network namespace, address family and UDP port */
-static struct vxlan_sock *vxlan_find_sock(struct net *net,
-                                         sa_family_t family, __be16 port)
+static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family,
+                                         __be16 port, u32 exts)
 {
        struct vxlan_sock *vs;
 
        hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) {
                if (inet_sk(vs->sock->sk)->inet_sport == port &&
-                   inet_sk(vs->sock->sk)->sk.sk_family == family)
+                   inet_sk(vs->sock->sk)->sk.sk_family == family &&
+                   vs->exts == exts)
                        return vs;
        }
        return NULL;
@@ -292,11 +293,12 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct 
vxlan_sock *vs, u32 id)
 
 /* Look up VNI in a per net namespace table */
 static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id,
-                                       sa_family_t family, __be16 port)
+                                       sa_family_t family, __be16 port,
+                                       u32 exts)
 {
        struct vxlan_sock *vs;
 
-       vs = vxlan_find_sock(net, family, port);
+       vs = vxlan_find_sock(net, family, port, exts);
        if (!vs)
                return NULL;
 
@@ -1790,7 +1792,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct 
net_device *dev,
 
                        ip_rt_put(rt);
                        dst_vxlan = vxlan_find_vni(vxlan->net, vni,
-                                                  dst->sa.sa_family, dst_port);
+                                                  dst->sa.sa_family, dst_port,
+                                                  vxlan->exts);
                        if (!dst_vxlan)
                                goto tx_error;
                        vxlan_encap_bypass(skb, vxlan, dst_vxlan);
@@ -1849,7 +1852,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct 
net_device *dev,
 
                        dst_release(ndst);
                        dst_vxlan = vxlan_find_vni(vxlan->net, vni,
-                                                  dst->sa.sa_family, dst_port);
+                                                  dst->sa.sa_family, dst_port,
+                                                  vxlan->exts);
                        if (!dst_vxlan)
                                goto tx_error;
                        vxlan_encap_bypass(skb, vxlan, dst_vxlan);
@@ -2019,7 +2023,7 @@ static int vxlan_init(struct net_device *dev)
 
        spin_lock(&vn->sock_lock);
        vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET,
-                            vxlan->dst_port);
+                            vxlan->dst_port, vxlan->exts);
        if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) {
                /* If we have a socket with same port already, reuse it */
                vxlan_vs_add_dev(vs, vxlan);
@@ -2373,7 +2377,7 @@ static struct socket *vxlan_create_sock(struct net *net, 
bool ipv6,
 /* Create new listen socket if needed */
 static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
                                              vxlan_rcv_t *rcv, void *data,
-                                             u32 flags)
+                                             u32 flags, u32 exts)
 {
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        struct vxlan_sock *vs;
@@ -2401,6 +2405,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net 
*net, __be16 port,
        atomic_set(&vs->refcnt, 1);
        vs->rcv = rcv;
        vs->data = data;
+       vs->exts = exts;
 
        /* Initialize the vxlan udp offloads structure */
        vs->udp_offloads.port = port;
@@ -2425,13 +2430,14 @@ static struct vxlan_sock *vxlan_socket_create(struct 
net *net, __be16 port,
 
 struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
                                  vxlan_rcv_t *rcv, void *data,
-                                 bool no_share, u32 flags)
+                                 bool no_share, u32 flags,
+                                 u32 exts)
 {
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        struct vxlan_sock *vs;
        bool ipv6 = flags & VXLAN_F_IPV6;
 
-       vs = vxlan_socket_create(net, port, rcv, data, flags);
+       vs = vxlan_socket_create(net, port, rcv, data, flags, exts);
        if (!IS_ERR(vs))
                return vs;
 
@@ -2439,7 +2445,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 
port,
                return vs;
 
        spin_lock(&vn->sock_lock);
-       vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port);
+       vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port, exts);
        if (vs && ((vs->rcv != rcv) ||
                   !atomic_add_unless(&vs->refcnt, 1, 0)))
                        vs = ERR_PTR(-EBUSY);
@@ -2461,7 +2467,8 @@ static void vxlan_sock_work(struct work_struct *work)
        __be16 port = vxlan->dst_port;
        struct vxlan_sock *nvs;
 
-       nvs = vxlan_sock_add(net, port, vxlan_rcv, NULL, false, vxlan->flags);
+       nvs = vxlan_sock_add(net, port, vxlan_rcv, NULL, false, vxlan->flags,
+                            vxlan->exts);
        spin_lock(&vn->sock_lock);
        if (!IS_ERR(nvs))
                vxlan_vs_add_dev(nvs, vxlan);
@@ -2611,7 +2618,7 @@ static int vxlan_newlink(struct net *net, struct 
net_device *dev,
                configure_vxlan_exts(vxlan, data[IFLA_VXLAN_EXTENSION]);
 
        if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET,
-                          vxlan->dst_port)) {
+                          vxlan->dst_port, vxlan->exts)) {
                pr_info("duplicate VNI %u\n", vni);
                return -EEXIST;
        }
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index 76a3aa2..4b6e794 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -121,7 +121,7 @@ struct vxlan_sock {
 
 struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
                                  vxlan_rcv_t *rcv, void *data,
-                                 bool no_share, u32 flags);
+                                 bool no_share, u32 flags, u32 exts);
 
 void vxlan_sock_release(struct vxlan_sock *vs);
 
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c
index deed9e3..40a16fb 100644
--- a/net/openvswitch/vport-vxlan.c
+++ b/net/openvswitch/vport-vxlan.c
@@ -128,7 +128,7 @@ static struct vport *vxlan_tnl_create(const struct 
vport_parms *parms)
        vxlan_port = vxlan_vport(vport);
        strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
 
-       vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, 0);
+       vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, 0, 0);
        if (IS_ERR(vs)) {
                ovs_vport_free(vport);
                return (void *)vs;
-- 
1.9.3

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to