Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gtp: Allow to create GTP device without FDs

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.

Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>

authored by

Wojciech Drewek and committed by
Tony Nguyen
b20dc3c6 59d59235

+85 -17
+84 -17
drivers/net/gtp.c
··· 66 66 67 67 struct sock *sk0; 68 68 struct sock *sk1u; 69 + u8 sk_created; 69 70 70 71 struct net_device *dev; 72 + struct net *net; 71 73 72 74 unsigned int role; 73 75 unsigned int hash_size; ··· 322 320 323 321 static void gtp_encap_disable(struct gtp_dev *gtp) 324 322 { 325 - gtp_encap_disable_sock(gtp->sk0); 326 - gtp_encap_disable_sock(gtp->sk1u); 323 + if (gtp->sk_created) { 324 + udp_tunnel_sock_release(gtp->sk0->sk_socket); 325 + udp_tunnel_sock_release(gtp->sk1u->sk_socket); 326 + gtp->sk_created = false; 327 + gtp->sk0 = NULL; 328 + gtp->sk1u = NULL; 329 + } else { 330 + gtp_encap_disable_sock(gtp->sk0); 331 + gtp_encap_disable_sock(gtp->sk1u); 332 + } 327 333 } 328 334 329 335 /* UDP encapsulation receive handler. See net/ipv4/udp.c. ··· 666 656 kfree(gtp->tid_hash); 667 657 } 668 658 659 + static struct sock *gtp_create_sock(int type, struct gtp_dev *gtp) 660 + { 661 + struct udp_tunnel_sock_cfg tuncfg = {}; 662 + struct udp_port_cfg udp_conf = { 663 + .local_ip.s_addr = htonl(INADDR_ANY), 664 + .family = AF_INET, 665 + }; 666 + struct net *net = gtp->net; 667 + struct socket *sock; 668 + int err; 669 + 670 + if (type == UDP_ENCAP_GTP0) 671 + udp_conf.local_udp_port = htons(GTP0_PORT); 672 + else if (type == UDP_ENCAP_GTP1U) 673 + udp_conf.local_udp_port = htons(GTP1U_PORT); 674 + else 675 + return ERR_PTR(-EINVAL); 676 + 677 + err = udp_sock_create(net, &udp_conf, &sock); 678 + if (err) 679 + return ERR_PTR(err); 680 + 681 + tuncfg.sk_user_data = gtp; 682 + tuncfg.encap_type = type; 683 + tuncfg.encap_rcv = gtp_encap_recv; 684 + tuncfg.encap_destroy = NULL; 685 + 686 + setup_udp_tunnel_sock(net, sock, &tuncfg); 687 + 688 + return sock->sk; 689 + } 690 + 691 + static int gtp_create_sockets(struct gtp_dev *gtp, struct nlattr *data[]) 692 + { 693 + struct sock *sk1u = NULL; 694 + struct sock *sk0 = NULL; 695 + 696 + sk0 = gtp_create_sock(UDP_ENCAP_GTP0, gtp); 697 + if (IS_ERR(sk0)) 698 + return PTR_ERR(sk0); 699 + 700 + sk1u = gtp_create_sock(UDP_ENCAP_GTP1U, gtp); 701 + if (IS_ERR(sk1u)) { 702 + udp_tunnel_sock_release(sk0->sk_socket); 703 + return PTR_ERR(sk1u); 704 + } 705 + 706 + gtp->sk_created = true; 707 + gtp->sk0 = sk0; 708 + gtp->sk1u = sk1u; 709 + 710 + return 0; 711 + } 712 + 669 713 static int gtp_newlink(struct net *src_net, struct net_device *dev, 670 714 struct nlattr *tb[], struct nlattr *data[], 671 715 struct netlink_ext_ack *extack) 672 716 { 717 + unsigned int role = GTP_ROLE_GGSN; 673 718 struct gtp_dev *gtp; 674 719 struct gtp_net *gn; 675 720 int hashsize, err; 676 - 677 - if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) 678 - return -EINVAL; 679 721 680 722 gtp = netdev_priv(dev); 681 723 ··· 739 677 hashsize = 1024; 740 678 } 741 679 680 + if (data[IFLA_GTP_ROLE]) { 681 + role = nla_get_u32(data[IFLA_GTP_ROLE]); 682 + if (role > GTP_ROLE_SGSN) 683 + return -EINVAL; 684 + } 685 + gtp->role = role; 686 + 687 + gtp->net = src_net; 688 + 742 689 err = gtp_hashtable_new(gtp, hashsize); 743 690 if (err < 0) 744 691 return err; 745 692 746 - err = gtp_encap_enable(gtp, data); 693 + if (data[IFLA_GTP_CREATE_SOCKETS]) 694 + err = gtp_create_sockets(gtp, data); 695 + else 696 + err = gtp_encap_enable(gtp, data); 747 697 if (err < 0) 748 698 goto out_hashtable; 749 699 ··· 800 726 [IFLA_GTP_FD1] = { .type = NLA_U32 }, 801 727 [IFLA_GTP_PDP_HASHSIZE] = { .type = NLA_U32 }, 802 728 [IFLA_GTP_ROLE] = { .type = NLA_U32 }, 729 + [IFLA_GTP_CREATE_SOCKETS] = { .type = NLA_U8 }, 803 730 }; 804 731 805 732 static int gtp_validate(struct nlattr *tb[], struct nlattr *data[], ··· 923 848 { 924 849 struct sock *sk1u = NULL; 925 850 struct sock *sk0 = NULL; 926 - unsigned int role = GTP_ROLE_GGSN; 851 + 852 + if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) 853 + return -EINVAL; 927 854 928 855 if (data[IFLA_GTP_FD0]) { 929 856 u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]); ··· 945 868 } 946 869 } 947 870 948 - if (data[IFLA_GTP_ROLE]) { 949 - role = nla_get_u32(data[IFLA_GTP_ROLE]); 950 - if (role > GTP_ROLE_SGSN) { 951 - gtp_encap_disable_sock(sk0); 952 - gtp_encap_disable_sock(sk1u); 953 - return -EINVAL; 954 - } 955 - } 956 - 957 871 gtp->sk0 = sk0; 958 872 gtp->sk1u = sk1u; 959 - gtp->role = role; 960 873 961 874 return 0; 962 875 }
+1
include/uapi/linux/if_link.h
··· 887 887 IFLA_GTP_FD1, 888 888 IFLA_GTP_PDP_HASHSIZE, 889 889 IFLA_GTP_ROLE, 890 + IFLA_GTP_CREATE_SOCKETS, 890 891 __IFLA_GTP_MAX, 891 892 }; 892 893 #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)