aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fou.c
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2015-04-10 15:00:29 -0400
committerDavid S. Miller <davem@davemloft.net>2015-04-12 21:25:13 -0400
commit02d793c5bbebf2c750da03df4c950fc4e8e8a5a7 (patch)
tree453d992bc7880d54d7a4433323de0691f08f1b78 /net/ipv4/fou.c
parent4cbcdf2b6c8065cb9f2e0eda8c12d33b1b617043 (diff)
fou: add network namespace support
Also convert the spinlock to a mutex. Cc: Tom Herbert <tom@herbertland.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fou.c')
-rw-r--r--net/ipv4/fou.c106
1 files changed, 67 insertions, 39 deletions
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index d61f6f995733..c244b1a65787 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -16,9 +16,6 @@
16#include <uapi/linux/fou.h> 16#include <uapi/linux/fou.h>
17#include <uapi/linux/genetlink.h> 17#include <uapi/linux/genetlink.h>
18 18
19static DEFINE_SPINLOCK(fou_lock);
20static LIST_HEAD(fou_list);
21
22struct fou { 19struct fou {
23 struct socket *sock; 20 struct socket *sock;
24 u8 protocol; 21 u8 protocol;
@@ -37,6 +34,13 @@ struct fou_cfg {
37 struct udp_port_cfg udp_config; 34 struct udp_port_cfg udp_config;
38}; 35};
39 36
37static unsigned int fou_net_id;
38
39struct fou_net {
40 struct list_head fou_list;
41 struct mutex fou_lock;
42};
43
40static inline struct fou *fou_from_sock(struct sock *sk) 44static inline struct fou *fou_from_sock(struct sock *sk)
41{ 45{
42 return sk->sk_user_data; 46 return sk->sk_user_data;
@@ -387,20 +391,21 @@ out_unlock:
387 return err; 391 return err;
388} 392}
389 393
390static int fou_add_to_port_list(struct fou *fou) 394static int fou_add_to_port_list(struct net *net, struct fou *fou)
391{ 395{
396 struct fou_net *fn = net_generic(net, fou_net_id);
392 struct fou *fout; 397 struct fou *fout;
393 398
394 spin_lock(&fou_lock); 399 mutex_lock(&fn->fou_lock);
395 list_for_each_entry(fout, &fou_list, list) { 400 list_for_each_entry(fout, &fn->fou_list, list) {
396 if (fou->port == fout->port) { 401 if (fou->port == fout->port) {
397 spin_unlock(&fou_lock); 402 mutex_unlock(&fn->fou_lock);
398 return -EALREADY; 403 return -EALREADY;
399 } 404 }
400 } 405 }
401 406
402 list_add(&fou->list, &fou_list); 407 list_add(&fou->list, &fn->fou_list);
403 spin_unlock(&fou_lock); 408 mutex_unlock(&fn->fou_lock);
404 409
405 return 0; 410 return 0;
406} 411}
@@ -412,13 +417,8 @@ static void fou_release(struct fou *fou)
412 417
413 if (sk->sk_family == AF_INET) 418 if (sk->sk_family == AF_INET)
414 udp_del_offload(&fou->udp_offloads); 419 udp_del_offload(&fou->udp_offloads);
415
416 list_del(&fou->list); 420 list_del(&fou->list);
417 421 udp_tunnel_sock_release(sock);
418 /* Remove hooks into tunnel socket */
419 sk->sk_user_data = NULL;
420
421 sock_release(sock);
422 422
423 kfree(fou); 423 kfree(fou);
424} 424}
@@ -448,10 +448,10 @@ static int gue_encap_init(struct sock *sk, struct fou *fou, struct fou_cfg *cfg)
448static int fou_create(struct net *net, struct fou_cfg *cfg, 448static int fou_create(struct net *net, struct fou_cfg *cfg,
449 struct socket **sockp) 449 struct socket **sockp)
450{ 450{
451 struct fou *fou = NULL;
452 int err;
453 struct socket *sock = NULL; 451 struct socket *sock = NULL;
452 struct fou *fou = NULL;
454 struct sock *sk; 453 struct sock *sk;
454 int err;
455 455
456 /* Open UDP socket */ 456 /* Open UDP socket */
457 err = udp_sock_create(net, &cfg->udp_config, &sock); 457 err = udp_sock_create(net, &cfg->udp_config, &sock);
@@ -503,7 +503,7 @@ static int fou_create(struct net *net, struct fou_cfg *cfg,
503 goto error; 503 goto error;
504 } 504 }
505 505
506 err = fou_add_to_port_list(fou); 506 err = fou_add_to_port_list(net, fou);
507 if (err) 507 if (err)
508 goto error; 508 goto error;
509 509
@@ -515,26 +515,27 @@ static int fou_create(struct net *net, struct fou_cfg *cfg,
515error: 515error:
516 kfree(fou); 516 kfree(fou);
517 if (sock) 517 if (sock)
518 sock_release(sock); 518 udp_tunnel_sock_release(sock);
519 519
520 return err; 520 return err;
521} 521}
522 522
523static int fou_destroy(struct net *net, struct fou_cfg *cfg) 523static int fou_destroy(struct net *net, struct fou_cfg *cfg)
524{ 524{
525 struct fou *fou; 525 struct fou_net *fn = net_generic(net, fou_net_id);
526 __be16 port = cfg->udp_config.local_udp_port; 526 __be16 port = cfg->udp_config.local_udp_port;
527 int err = -EINVAL; 527 int err = -EINVAL;
528 struct fou *fou;
528 529
529 spin_lock(&fou_lock); 530 mutex_lock(&fn->fou_lock);
530 list_for_each_entry(fou, &fou_list, list) { 531 list_for_each_entry(fou, &fn->fou_list, list) {
531 if (fou->port == port) { 532 if (fou->port == port) {
532 fou_release(fou); 533 fou_release(fou);
533 err = 0; 534 err = 0;
534 break; 535 break;
535 } 536 }
536 } 537 }
537 spin_unlock(&fou_lock); 538 mutex_unlock(&fn->fou_lock);
538 539
539 return err; 540 return err;
540} 541}
@@ -592,6 +593,7 @@ static int parse_nl_config(struct genl_info *info,
592 593
593static int fou_nl_cmd_add_port(struct sk_buff *skb, struct genl_info *info) 594static int fou_nl_cmd_add_port(struct sk_buff *skb, struct genl_info *info)
594{ 595{
596 struct net *net = genl_info_net(info);
595 struct fou_cfg cfg; 597 struct fou_cfg cfg;
596 int err; 598 int err;
597 599
@@ -599,11 +601,12 @@ static int fou_nl_cmd_add_port(struct sk_buff *skb, struct genl_info *info)
599 if (err) 601 if (err)
600 return err; 602 return err;
601 603
602 return fou_create(&init_net, &cfg, NULL); 604 return fou_create(net, &cfg, NULL);
603} 605}
604 606
605static int fou_nl_cmd_rm_port(struct sk_buff *skb, struct genl_info *info) 607static int fou_nl_cmd_rm_port(struct sk_buff *skb, struct genl_info *info)
606{ 608{
609 struct net *net = genl_info_net(info);
607 struct fou_cfg cfg; 610 struct fou_cfg cfg;
608 int err; 611 int err;
609 612
@@ -611,7 +614,7 @@ static int fou_nl_cmd_rm_port(struct sk_buff *skb, struct genl_info *info)
611 if (err) 614 if (err)
612 return err; 615 return err;
613 616
614 return fou_destroy(&init_net, &cfg); 617 return fou_destroy(net, &cfg);
615} 618}
616 619
617static const struct genl_ops fou_nl_ops[] = { 620static const struct genl_ops fou_nl_ops[] = {
@@ -823,38 +826,63 @@ static void ip_tunnel_encap_del_fou_ops(void)
823 826
824#endif 827#endif
825 828
829static __net_init int fou_init_net(struct net *net)
830{
831 struct fou_net *fn = net_generic(net, fou_net_id);
832
833 INIT_LIST_HEAD(&fn->fou_list);
834 mutex_init(&fn->fou_lock);
835 return 0;
836}
837
838static __net_exit void fou_exit_net(struct net *net)
839{
840 struct fou_net *fn = net_generic(net, fou_net_id);
841 struct fou *fou, *next;
842
843 /* Close all the FOU sockets */
844 mutex_lock(&fn->fou_lock);
845 list_for_each_entry_safe(fou, next, &fn->fou_list, list)
846 fou_release(fou);
847 mutex_unlock(&fn->fou_lock);
848}
849
850static struct pernet_operations fou_net_ops = {
851 .init = fou_init_net,
852 .exit = fou_exit_net,
853 .id = &fou_net_id,
854 .size = sizeof(struct fou_net),
855};
856
826static int __init fou_init(void) 857static int __init fou_init(void)
827{ 858{
828 int ret; 859 int ret;
829 860
861 ret = register_pernet_device(&fou_net_ops);
862 if (ret)
863 goto exit;
864
830 ret = genl_register_family_with_ops(&fou_nl_family, 865 ret = genl_register_family_with_ops(&fou_nl_family,
831 fou_nl_ops); 866 fou_nl_ops);
832
833 if (ret < 0) 867 if (ret < 0)
834 goto exit; 868 goto unregister;
835 869
836 ret = ip_tunnel_encap_add_fou_ops(); 870 ret = ip_tunnel_encap_add_fou_ops();
837 if (ret < 0) 871 if (ret == 0)
838 genl_unregister_family(&fou_nl_family); 872 return 0;
839 873
874 genl_unregister_family(&fou_nl_family);
875unregister:
876 unregister_pernet_device(&fou_net_ops);
840exit: 877exit:
841 return ret; 878 return ret;
842} 879}
843 880
844static void __exit fou_fini(void) 881static void __exit fou_fini(void)
845{ 882{
846 struct fou *fou, *next;
847
848 ip_tunnel_encap_del_fou_ops(); 883 ip_tunnel_encap_del_fou_ops();
849
850 genl_unregister_family(&fou_nl_family); 884 genl_unregister_family(&fou_nl_family);
851 885 unregister_pernet_device(&fou_net_ops);
852 /* Close all the FOU sockets */
853
854 spin_lock(&fou_lock);
855 list_for_each_entry_safe(fou, next, &fou_list, list)
856 fou_release(fou);
857 spin_unlock(&fou_lock);
858} 886}
859 887
860module_init(fou_init); 888module_init(fou_init);