diff options
-rw-r--r-- | include/net/geneve.h | 2 | ||||
-rw-r--r-- | net/ipv4/geneve.c | 59 |
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. */ | ||
55 | static 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 */ |
57 | struct geneve_net { | 61 | struct 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 | ||
62 | static int geneve_net_id; | 65 | static 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 | ||
407 | void geneve_sock_release(struct geneve_sock *gs) | 403 | void 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 | |||
415 | unlock: | ||
416 | mutex_unlock(&geneve_mutex); | ||
422 | } | 417 | } |
423 | EXPORT_SYMBOL_GPL(geneve_sock_release); | 418 | EXPORT_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 | } |
457 | late_initcall(geneve_init_module); | 450 | module_init(geneve_init_module); |
458 | 451 | ||
459 | static void __exit geneve_cleanup_module(void) | 452 | static void __exit geneve_cleanup_module(void) |
460 | { | 453 | { |