diff options
author | Thomas Graf <tgraf@suug.ch> | 2015-01-14 21:53:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-15 01:11:41 -0500 |
commit | ac5132d1a03fe1ebbefb2382b36e829dff056283 (patch) | |
tree | c6485d636e3d8a25a4ead7fd1e6520286816fdfb /drivers/net/vxlan.c | |
parent | 3511494ce2f3d3b77544c79b87511a4ddb61dc89 (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.c | 29 |
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 |
267 | static struct vxlan_sock *vxlan_find_sock(struct net *net, | 267 | * and enabled unshareable flags. |
268 | sa_family_t family, __be16 port) | 268 | */ |
269 | static 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 */ |
293 | static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, | 297 | static 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 | } |