diff options
| author | WANG Cong <xiyou.wangcong@gmail.com> | 2015-04-10 15:00:29 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-04-12 21:25:13 -0400 |
| commit | 02d793c5bbebf2c750da03df4c950fc4e8e8a5a7 (patch) | |
| tree | 453d992bc7880d54d7a4433323de0691f08f1b78 /net | |
| parent | 4cbcdf2b6c8065cb9f2e0eda8c12d33b1b617043 (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')
| -rw-r--r-- | net/ipv4/fou.c | 106 |
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 | ||
| 19 | static DEFINE_SPINLOCK(fou_lock); | ||
| 20 | static LIST_HEAD(fou_list); | ||
| 21 | |||
| 22 | struct fou { | 19 | struct 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 | ||
| 37 | static unsigned int fou_net_id; | ||
| 38 | |||
| 39 | struct fou_net { | ||
| 40 | struct list_head fou_list; | ||
| 41 | struct mutex fou_lock; | ||
| 42 | }; | ||
| 43 | |||
| 40 | static inline struct fou *fou_from_sock(struct sock *sk) | 44 | static 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 | ||
| 390 | static int fou_add_to_port_list(struct fou *fou) | 394 | static 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) | |||
| 448 | static int fou_create(struct net *net, struct fou_cfg *cfg, | 448 | static 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, | |||
| 515 | error: | 515 | error: |
| 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 | ||
| 523 | static int fou_destroy(struct net *net, struct fou_cfg *cfg) | 523 | static 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 | ||
| 593 | static int fou_nl_cmd_add_port(struct sk_buff *skb, struct genl_info *info) | 594 | static 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 | ||
| 605 | static int fou_nl_cmd_rm_port(struct sk_buff *skb, struct genl_info *info) | 607 | static 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 | ||
| 617 | static const struct genl_ops fou_nl_ops[] = { | 620 | static 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 | ||
| 829 | static __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 | |||
| 838 | static __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 | |||
| 850 | static 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 | |||
| 826 | static int __init fou_init(void) | 857 | static 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); | ||
| 875 | unregister: | ||
| 876 | unregister_pernet_device(&fou_net_ops); | ||
| 840 | exit: | 877 | exit: |
| 841 | return ret; | 878 | return ret; |
| 842 | } | 879 | } |
| 843 | 880 | ||
| 844 | static void __exit fou_fini(void) | 881 | static 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 | ||
| 860 | module_init(fou_init); | 888 | module_init(fou_init); |
