Currently, when the user wants to create GTP device, he has to provide file handles to the sockets created in userspace (IFLA_GTP_FD0, IFLA_GTP_FD1). This behaviour is not ideal, considering the option of adding support for GTP device creation through ip link. Ip link application is not a good place to create such sockets. This patch allows to create GTP device without providing IFLA_GTP_FD0 and IFLA_GTP_FD1 arguments. If the user sets IFLA_GTP_CREATE_SOCKETS attribute, then GTP module takes care of creating UDP sockets by itself. Sockets are created with the commonly known UDP ports used for GTP protocol (GTP0_PORT and GTP1U_PORT). In this case we don't have to provide encap_destroy because no extra deinitialization is needed, everything is covered by udp_tunnel_sock_release. Note: GTP instance created with only this change applied, does not handle GTP Echo Requests. This is implemented in the following patch.
Unified · Split
| @@ -66,8 +66,10 @@ struct gtp_dev { · 65 unmodified lines | |||
| 66 | 66 | ||
| 67 | struct sock *sk0; | 67 | struct sock *sk0; |
| 68 | struct sock *sk1u; | 68 | struct sock *sk1u; |
| 69 | u8 sk_created; | ||
| 69 | 70 | ||
| 70 | struct net_device *dev; | 71 | struct net_device *dev; |
| 72 | struct net *net; | ||
| 71 | 73 | ||
| 72 | unsigned int role; | 74 | unsigned int role; |
| 73 | unsigned int hash_size; | 75 | unsigned int hash_size; |
| @@ -320,8 +322,16 @@ static void gtp_encap_disable_sock(struct sock *sk) · 246 unmodified lines | |||
| 320 | 322 | ||
| 321 | static void gtp_encap_disable(struct gtp_dev *gtp) | 323 | static void gtp_encap_disable(struct gtp_dev *gtp) |
| 322 | { | 324 | { |
| 323 | gtp_encap_disable_sock(gtp->sk0); | 325 | if (gtp->sk_created) { |
| 324 | gtp_encap_disable_sock(gtp->sk1u); | 326 | udp_tunnel_sock_release(gtp->sk0->sk_socket); |
| 327 | udp_tunnel_sock_release(gtp->sk1u->sk_socket); | ||
| 328 | gtp->sk_created = false; | ||
| 329 | gtp->sk0 = NULL; | ||
| 330 | gtp->sk1u = NULL; | ||
| 331 | } else { | ||
| 332 | gtp_encap_disable_sock(gtp->sk0); | ||
| 333 | gtp_encap_disable_sock(gtp->sk1u); | ||
| 334 | } | ||
| 325 | } | 335 | } |
| 326 | 336 | ||
| 327 | /* UDP encapsulation receive handler. See net/ipv4/udp.c. | 337 | /* UDP encapsulation receive handler. See net/ipv4/udp.c. |
| @@ -656,17 +666,69 @@ static void gtp_destructor(struct net_device *dev) · 328 unmodified lines | |||
| 656 | kfree(gtp->tid_hash); | 666 | kfree(gtp->tid_hash); |
| 657 | } | 667 | } |
| 658 | 668 | ||
| 669 | static struct sock *gtp_create_sock(int type, struct gtp_dev *gtp) | ||
| 670 | { | ||
| 671 | struct udp_tunnel_sock_cfg tuncfg = {}; | ||
| 672 | struct udp_port_cfg udp_conf = { | ||
| 673 | .local_ip.s_addr = htonl(INADDR_ANY), | ||
| 674 | .family = AF_INET, | ||
| 675 | }; | ||
| 676 | struct net *net = gtp->net; | ||
| 677 | struct socket *sock; | ||
| 678 | int err; | ||
| 679 | |||
| 680 | if (type == UDP_ENCAP_GTP0) | ||
| 681 | udp_conf.local_udp_port = htons(GTP0_PORT); | ||
| 682 | else if (type == UDP_ENCAP_GTP1U) | ||
| 683 | udp_conf.local_udp_port = htons(GTP1U_PORT); | ||
| 684 | else | ||
| 685 | return ERR_PTR(-EINVAL); | ||
| 686 | |||
| 687 | err = udp_sock_create(net, &udp_conf, &sock); | ||
| 688 | if (err) | ||
| 689 | return ERR_PTR(err); | ||
| 690 | |||
| 691 | tuncfg.sk_user_data = gtp; | ||
| 692 | tuncfg.encap_type = type; | ||
| 693 | tuncfg.encap_rcv = gtp_encap_recv; | ||
| 694 | tuncfg.encap_destroy = NULL; | ||
| 695 | |||
| 696 | setup_udp_tunnel_sock(net, sock, &tuncfg); | ||
| 697 | |||
| 698 | return sock->sk; | ||
| 699 | } | ||
| 700 | |||
| 701 | static int gtp_create_sockets(struct gtp_dev *gtp, struct nlattr *data[]) | ||
| 702 | { | ||
| 703 | struct sock *sk1u = NULL; | ||
| 704 | struct sock *sk0 = NULL; | ||
| 705 | |||
| 706 | sk0 = gtp_create_sock(UDP_ENCAP_GTP0, gtp); | ||
| 707 | if (IS_ERR(sk0)) | ||
| 708 | return PTR_ERR(sk0); | ||
| 709 | |||
| 710 | sk1u = gtp_create_sock(UDP_ENCAP_GTP1U, gtp); | ||
| 711 | if (IS_ERR(sk1u)) { | ||
| 712 | udp_tunnel_sock_release(sk0->sk_socket); | ||
| 713 | return PTR_ERR(sk1u); | ||
| 714 | } | ||
| 715 | |||
| 716 | gtp->sk_created = true; | ||
| 717 | gtp->sk0 = sk0; | ||
| 718 | gtp->sk1u = sk1u; | ||
| 719 | |||
| 720 | return 0; | ||
| 721 | } | ||
| 722 | |||
| 659 | static int gtp_newlink(struct net *src_net, struct net_device *dev, | 723 | static int gtp_newlink(struct net *src_net, struct net_device *dev, |
| 660 | struct nlattr *tb[], struct nlattr *data[], | 724 | struct nlattr *tb[], struct nlattr *data[], |
| 661 | struct netlink_ext_ack *extack) | 725 | struct netlink_ext_ack *extack) |
| 662 | { | 726 | { |
| 727 | unsigned int role = GTP_ROLE_GGSN; | ||
| 663 | struct gtp_dev *gtp; | 728 | struct gtp_dev *gtp; |
| 664 | struct gtp_net *gn; | 729 | struct gtp_net *gn; |
| 665 | int hashsize, err; | 730 | int hashsize, err; |
| 666 | 731 | ||
| 667 | if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) | ||
| 668 | return -EINVAL; | ||
| 669 | |||
| 670 | gtp = netdev_priv(dev); | 732 | gtp = netdev_priv(dev); |
| 671 | 733 | ||
| 672 | if (!data[IFLA_GTP_PDP_HASHSIZE]) { | 734 | if (!data[IFLA_GTP_PDP_HASHSIZE]) { |
| @@ -677,11 +739,23 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, · 4 unmodified lines | |||
| 677 | hashsize = 1024; | 739 | hashsize = 1024; |
| 678 | } | 740 | } |
| 679 | 741 | ||
| 742 | if (data[IFLA_GTP_ROLE]) { | ||
| 743 | role = nla_get_u32(data[IFLA_GTP_ROLE]); | ||
| 744 | if (role > GTP_ROLE_SGSN) | ||
| 745 | return -EINVAL; | ||
| 746 | } | ||
| 747 | gtp->role = role; | ||
| 748 | |||
| 749 | gtp->net = src_net; | ||
| 750 | |||
| 680 | err = gtp_hashtable_new(gtp, hashsize); | 751 | err = gtp_hashtable_new(gtp, hashsize); |
| 681 | if (err < 0) | 752 | if (err < 0) |
| 682 | return err; | 753 | return err; |
| 683 | 754 | ||
| 684 | err = gtp_encap_enable(gtp, data); | 755 | if (data[IFLA_GTP_CREATE_SOCKETS]) |
| 756 | err = gtp_create_sockets(gtp, data); | ||
| 757 | else | ||
| 758 | err = gtp_encap_enable(gtp, data); | ||
| 685 | if (err < 0) | 759 | if (err < 0) |
| 686 | goto out_hashtable; | 760 | goto out_hashtable; |
| 687 | 761 | ||
| @@ -726,6 +800,7 @@ static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = { · 38 unmodified lines | |||
| 726 | [IFLA_GTP_FD1] = { .type = NLA_U32 }, | 800 | [IFLA_GTP_FD1] = { .type = NLA_U32 }, |
| 727 | [IFLA_GTP_PDP_HASHSIZE] = { .type = NLA_U32 }, | 801 | [IFLA_GTP_PDP_HASHSIZE] = { .type = NLA_U32 }, |
| 728 | [IFLA_GTP_ROLE] = { .type = NLA_U32 }, | 802 | [IFLA_GTP_ROLE] = { .type = NLA_U32 }, |
| 803 | [IFLA_GTP_CREATE_SOCKETS] = { .type = NLA_U8 }, | ||
| 729 | }; | 804 | }; |
| 730 | 805 | ||
| 731 | static int gtp_validate(struct nlattr *tb[], struct nlattr *data[], | 806 | static int gtp_validate(struct nlattr *tb[], struct nlattr *data[], |
| @@ -848,7 +923,9 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]) · 116 unmodified lines | |||
| 848 | { | 923 | { |
| 849 | struct sock *sk1u = NULL; | 924 | struct sock *sk1u = NULL; |
| 850 | struct sock *sk0 = NULL; | 925 | struct sock *sk0 = NULL; |
| 851 | unsigned int role = GTP_ROLE_GGSN; | 926 | |
| 927 | if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) | ||
| 928 | return -EINVAL; | ||
| 852 | 929 | ||
| 853 | if (data[IFLA_GTP_FD0]) { | 930 | if (data[IFLA_GTP_FD0]) { |
| 854 | u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]); | 931 | u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]); |
| @@ -868,18 +945,8 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]) · 13 unmodified lines | |||
| 868 | } | 945 | } |
| 869 | } | 946 | } |
| 870 | 947 | ||
| 871 | if (data[IFLA_GTP_ROLE]) { | ||
| 872 | role = nla_get_u32(data[IFLA_GTP_ROLE]); | ||
| 873 | if (role > GTP_ROLE_SGSN) { | ||
| 874 | gtp_encap_disable_sock(sk0); | ||
| 875 | gtp_encap_disable_sock(sk1u); | ||
| 876 | return -EINVAL; | ||
| 877 | } | ||
| 878 | } | ||
| 879 | |||
| 880 | gtp->sk0 = sk0; | 948 | gtp->sk0 = sk0; |
| 881 | gtp->sk1u = sk1u; | 949 | gtp->sk1u = sk1u; |
| 882 | gtp->role = role; | ||
| 883 | 950 | ||
| 884 | return 0; | 951 | return 0; |
| 885 | } | 952 | } |
| @@ -887,6 +887,7 @@ enum { · 886 unmodified lines | |||
| 887 | IFLA_GTP_FD1, | 887 | IFLA_GTP_FD1, |
| 888 | IFLA_GTP_PDP_HASHSIZE, | 888 | IFLA_GTP_PDP_HASHSIZE, |
| 889 | IFLA_GTP_ROLE, | 889 | IFLA_GTP_ROLE, |
| 890 | IFLA_GTP_CREATE_SOCKETS, | ||
| 890 | __IFLA_GTP_MAX, | 891 | __IFLA_GTP_MAX, |
| 891 | }; | 892 | }; |
| 892 | #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1) | 893 | #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1) |