aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/geneve.h2
-rw-r--r--net/ipv4/geneve.c59
2 files changed, 27 insertions, 34 deletions
diff --git a/include/net/geneve.h b/include/net/geneve.h
index 56c7e1ac216a..b40f4affc4cb 100644
--- a/include/net/geneve.h
+++ b/include/net/geneve.h
@@ -73,7 +73,7 @@ struct geneve_sock {
73 void *rcv_data; 73 void *rcv_data;
74 struct socket *sock; 74 struct socket *sock;
75 struct rcu_head rcu; 75 struct rcu_head rcu;
76 atomic_t refcnt; 76 int refcnt;
77 struct udp_offload udp_offloads; 77 struct udp_offload udp_offloads;
78}; 78};
79 79
diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c
index 136a829e8746..ad8dbae11d01 100644
--- a/net/ipv4/geneve.c
+++ b/net/ipv4/geneve.c
@@ -17,7 +17,7 @@
17#include <linux/errno.h> 17#include <linux/errno.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/skbuff.h> 19#include <linux/skbuff.h>
20#include <linux/rculist.h> 20#include <linux/list.h>
21#include <linux/netdevice.h> 21#include <linux/netdevice.h>
22#include <linux/in.h> 22#include <linux/in.h>
23#include <linux/ip.h> 23#include <linux/ip.h>
@@ -28,6 +28,7 @@
28#include <linux/if_vlan.h> 28#include <linux/if_vlan.h>
29#include <linux/hash.h> 29#include <linux/hash.h>
30#include <linux/ethtool.h> 30#include <linux/ethtool.h>
31#include <linux/mutex.h>
31#include <net/arp.h> 32#include <net/arp.h>
32#include <net/ndisc.h> 33#include <net/ndisc.h>
33#include <net/ip.h> 34#include <net/ip.h>
@@ -50,13 +51,15 @@
50#include <net/ip6_checksum.h> 51#include <net/ip6_checksum.h>
51#endif 52#endif
52 53
54/* Protects sock_list and refcounts. */
55static DEFINE_MUTEX(geneve_mutex);
56
53#define PORT_HASH_BITS 8 57#define PORT_HASH_BITS 8
54#define PORT_HASH_SIZE (1<<PORT_HASH_BITS) 58#define PORT_HASH_SIZE (1<<PORT_HASH_BITS)
55 59
56/* per-network namespace private data for this module */ 60/* per-network namespace private data for this module */
57struct geneve_net { 61struct geneve_net {
58 struct hlist_head sock_list[PORT_HASH_SIZE]; 62 struct hlist_head sock_list[PORT_HASH_SIZE];
59 spinlock_t sock_lock; /* Protects sock_list */
60}; 63};
61 64
62static int geneve_net_id; 65static int geneve_net_id;
@@ -78,7 +81,7 @@ static struct geneve_sock *geneve_find_sock(struct net *net, __be16 port)
78{ 81{
79 struct geneve_sock *gs; 82 struct geneve_sock *gs;
80 83
81 hlist_for_each_entry_rcu(gs, gs_head(net, port), hlist) { 84 hlist_for_each_entry(gs, gs_head(net, port), hlist) {
82 if (inet_sk(gs->sock->sk)->inet_sport == port) 85 if (inet_sk(gs->sock->sk)->inet_sport == port)
83 return gs; 86 return gs;
84 } 87 }
@@ -336,7 +339,6 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
336 geneve_rcv_t *rcv, void *data, 339 geneve_rcv_t *rcv, void *data,
337 bool ipv6) 340 bool ipv6)
338{ 341{
339 struct geneve_net *gn = net_generic(net, geneve_net_id);
340 struct geneve_sock *gs; 342 struct geneve_sock *gs;
341 struct socket *sock; 343 struct socket *sock;
342 struct udp_tunnel_sock_cfg tunnel_cfg; 344 struct udp_tunnel_sock_cfg tunnel_cfg;
@@ -352,7 +354,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
352 } 354 }
353 355
354 gs->sock = sock; 356 gs->sock = sock;
355 atomic_set(&gs->refcnt, 1); 357 gs->refcnt = 1;
356 gs->rcv = rcv; 358 gs->rcv = rcv;
357 gs->rcv_data = data; 359 gs->rcv_data = data;
358 360
@@ -360,11 +362,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
360 gs->udp_offloads.port = port; 362 gs->udp_offloads.port = port;
361 gs->udp_offloads.callbacks.gro_receive = geneve_gro_receive; 363 gs->udp_offloads.callbacks.gro_receive = geneve_gro_receive;
362 gs->udp_offloads.callbacks.gro_complete = geneve_gro_complete; 364 gs->udp_offloads.callbacks.gro_complete = geneve_gro_complete;
363
364 spin_lock(&gn->sock_lock);
365 hlist_add_head_rcu(&gs->hlist, gs_head(net, port));
366 geneve_notify_add_rx_port(gs); 365 geneve_notify_add_rx_port(gs);
367 spin_unlock(&gn->sock_lock);
368 366
369 /* Mark socket as an encapsulation socket */ 367 /* Mark socket as an encapsulation socket */
370 tunnel_cfg.sk_user_data = gs; 368 tunnel_cfg.sk_user_data = gs;
@@ -373,6 +371,8 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
373 tunnel_cfg.encap_destroy = NULL; 371 tunnel_cfg.encap_destroy = NULL;
374 setup_udp_tunnel_sock(net, sock, &tunnel_cfg); 372 setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
375 373
374 hlist_add_head(&gs->hlist, gs_head(net, port));
375
376 return gs; 376 return gs;
377} 377}
378 378
@@ -380,25 +380,21 @@ struct geneve_sock *geneve_sock_add(struct net *net, __be16 port,
380 geneve_rcv_t *rcv, void *data, 380 geneve_rcv_t *rcv, void *data,
381 bool no_share, bool ipv6) 381 bool no_share, bool ipv6)
382{ 382{
383 struct geneve_net *gn = net_generic(net, geneve_net_id);
384 struct geneve_sock *gs; 383 struct geneve_sock *gs;
385 384
386 gs = geneve_socket_create(net, port, rcv, data, ipv6); 385 mutex_lock(&geneve_mutex);
387 if (!IS_ERR(gs))
388 return gs;
389
390 if (no_share) /* Return error if sharing is not allowed. */
391 return ERR_PTR(-EINVAL);
392 386
393 spin_lock(&gn->sock_lock);
394 gs = geneve_find_sock(net, port); 387 gs = geneve_find_sock(net, port);
395 if (gs && ((gs->rcv != rcv) || 388 if (gs) {
396 !atomic_add_unless(&gs->refcnt, 1, 0))) 389 if (!no_share && gs->rcv == rcv)
390 gs->refcnt++;
391 else
397 gs = ERR_PTR(-EBUSY); 392 gs = ERR_PTR(-EBUSY);
398 spin_unlock(&gn->sock_lock); 393 } else {
394 gs = geneve_socket_create(net, port, rcv, data, ipv6);
395 }
399 396
400 if (!gs) 397 mutex_unlock(&geneve_mutex);
401 gs = ERR_PTR(-EINVAL);
402 398
403 return gs; 399 return gs;
404} 400}
@@ -406,19 +402,18 @@ EXPORT_SYMBOL_GPL(geneve_sock_add);
406 402
407void geneve_sock_release(struct geneve_sock *gs) 403void geneve_sock_release(struct geneve_sock *gs)
408{ 404{
409 struct net *net = sock_net(gs->sock->sk); 405 mutex_lock(&geneve_mutex);
410 struct geneve_net *gn = net_generic(net, geneve_net_id);
411 406
412 if (!atomic_dec_and_test(&gs->refcnt)) 407 if (--gs->refcnt)
413 return; 408 goto unlock;
414 409
415 spin_lock(&gn->sock_lock); 410 hlist_del(&gs->hlist);
416 hlist_del_rcu(&gs->hlist);
417 geneve_notify_del_rx_port(gs); 411 geneve_notify_del_rx_port(gs);
418 spin_unlock(&gn->sock_lock);
419
420 udp_tunnel_sock_release(gs->sock); 412 udp_tunnel_sock_release(gs->sock);
421 kfree_rcu(gs, rcu); 413 kfree_rcu(gs, rcu);
414
415unlock:
416 mutex_unlock(&geneve_mutex);
422} 417}
423EXPORT_SYMBOL_GPL(geneve_sock_release); 418EXPORT_SYMBOL_GPL(geneve_sock_release);
424 419
@@ -427,8 +422,6 @@ static __net_init int geneve_init_net(struct net *net)
427 struct geneve_net *gn = net_generic(net, geneve_net_id); 422 struct geneve_net *gn = net_generic(net, geneve_net_id);
428 unsigned int h; 423 unsigned int h;
429 424
430 spin_lock_init(&gn->sock_lock);
431
432 for (h = 0; h < PORT_HASH_SIZE; ++h) 425 for (h = 0; h < PORT_HASH_SIZE; ++h)
433 INIT_HLIST_HEAD(&gn->sock_list[h]); 426 INIT_HLIST_HEAD(&gn->sock_list[h]);
434 427
@@ -454,7 +447,7 @@ static int __init geneve_init_module(void)
454 447
455 return 0; 448 return 0;
456} 449}
457late_initcall(geneve_init_module); 450module_init(geneve_init_module);
458 451
459static void __exit geneve_cleanup_module(void) 452static void __exit geneve_cleanup_module(void)
460{ 453{