aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/vxlan.c
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2015-01-14 21:53:56 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-15 01:11:41 -0500
commitac5132d1a03fe1ebbefb2382b36e829dff056283 (patch)
treec6485d636e3d8a25a4ead7fd1e6520286816fdfb /drivers/net/vxlan.c
parent3511494ce2f3d3b77544c79b87511a4ddb61dc89 (diff)
vxlan: Only bind to sockets with compatible flags enabled
A VXLAN net_device looking for an appropriate socket may only consider a socket which has a matching set of flags/extensions enabled. If incompatible flags are enabled, 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 <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxlan.c')
-rw-r--r--drivers/net/vxlan.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 6dbf8e041922..6b6b45622a0a 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -263,15 +263,19 @@ static inline struct vxlan_rdst *first_remote_rtnl(struct vxlan_fdb *fdb)
263 return list_first_entry(&fdb->remotes, struct vxlan_rdst, list); 263 return list_first_entry(&fdb->remotes, struct vxlan_rdst, list);
264} 264}
265 265
266/* Find VXLAN socket based on network namespace, address family and UDP port */ 266/* Find VXLAN socket based on network namespace, address family and UDP port
267static struct vxlan_sock *vxlan_find_sock(struct net *net, 267 * and enabled unshareable flags.
268 sa_family_t family, __be16 port) 268 */
269static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family,
270 __be16 port, u32 flags)
269{ 271{
270 struct vxlan_sock *vs; 272 struct vxlan_sock *vs;
273 u32 match_flags = flags & VXLAN_F_UNSHAREABLE;
271 274
272 hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) { 275 hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) {
273 if (inet_sk(vs->sock->sk)->inet_sport == port && 276 if (inet_sk(vs->sock->sk)->inet_sport == port &&
274 inet_sk(vs->sock->sk)->sk.sk_family == family) 277 inet_sk(vs->sock->sk)->sk.sk_family == family &&
278 (vs->flags & VXLAN_F_UNSHAREABLE) == match_flags)
275 return vs; 279 return vs;
276 } 280 }
277 return NULL; 281 return NULL;
@@ -291,11 +295,12 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id)
291 295
292/* Look up VNI in a per net namespace table */ 296/* Look up VNI in a per net namespace table */
293static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, 297static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id,
294 sa_family_t family, __be16 port) 298 sa_family_t family, __be16 port,
299 u32 flags)
295{ 300{
296 struct vxlan_sock *vs; 301 struct vxlan_sock *vs;
297 302
298 vs = vxlan_find_sock(net, family, port); 303 vs = vxlan_find_sock(net, family, port, flags);
299 if (!vs) 304 if (!vs)
300 return NULL; 305 return NULL;
301 306
@@ -1957,7 +1962,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
1957 1962
1958 ip_rt_put(rt); 1963 ip_rt_put(rt);
1959 dst_vxlan = vxlan_find_vni(vxlan->net, vni, 1964 dst_vxlan = vxlan_find_vni(vxlan->net, vni,
1960 dst->sa.sa_family, dst_port); 1965 dst->sa.sa_family, dst_port,
1966 vxlan->flags);
1961 if (!dst_vxlan) 1967 if (!dst_vxlan)
1962 goto tx_error; 1968 goto tx_error;
1963 vxlan_encap_bypass(skb, vxlan, dst_vxlan); 1969 vxlan_encap_bypass(skb, vxlan, dst_vxlan);
@@ -2016,7 +2022,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
2016 2022
2017 dst_release(ndst); 2023 dst_release(ndst);
2018 dst_vxlan = vxlan_find_vni(vxlan->net, vni, 2024 dst_vxlan = vxlan_find_vni(vxlan->net, vni,
2019 dst->sa.sa_family, dst_port); 2025 dst->sa.sa_family, dst_port,
2026 vxlan->flags);
2020 if (!dst_vxlan) 2027 if (!dst_vxlan)
2021 goto tx_error; 2028 goto tx_error;
2022 vxlan_encap_bypass(skb, vxlan, dst_vxlan); 2029 vxlan_encap_bypass(skb, vxlan, dst_vxlan);
@@ -2186,7 +2193,7 @@ static int vxlan_init(struct net_device *dev)
2186 2193
2187 spin_lock(&vn->sock_lock); 2194 spin_lock(&vn->sock_lock);
2188 vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET, 2195 vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET,
2189 vxlan->dst_port); 2196 vxlan->dst_port, vxlan->flags);
2190 if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) { 2197 if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) {
2191 /* If we have a socket with same port already, reuse it */ 2198 /* If we have a socket with same port already, reuse it */
2192 vxlan_vs_add_dev(vs, vxlan); 2199 vxlan_vs_add_dev(vs, vxlan);
@@ -2593,7 +2600,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
2593 return vs; 2600 return vs;
2594 2601
2595 spin_lock(&vn->sock_lock); 2602 spin_lock(&vn->sock_lock);
2596 vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port); 2603 vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port, flags);
2597 if (vs && ((vs->rcv != rcv) || 2604 if (vs && ((vs->rcv != rcv) ||
2598 !atomic_add_unless(&vs->refcnt, 1, 0))) 2605 !atomic_add_unless(&vs->refcnt, 1, 0)))
2599 vs = ERR_PTR(-EBUSY); 2606 vs = ERR_PTR(-EBUSY);
@@ -2761,7 +2768,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
2761 vxlan->flags |= VXLAN_F_GBP; 2768 vxlan->flags |= VXLAN_F_GBP;
2762 2769
2763 if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET, 2770 if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET,
2764 vxlan->dst_port)) { 2771 vxlan->dst_port, vxlan->flags)) {
2765 pr_info("duplicate VNI %u\n", vni); 2772 pr_info("duplicate VNI %u\n", vni);
2766 return -EEXIST; 2773 return -EEXIST;
2767 } 2774 }