History

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.

Wojciech Drewek committed 4 years ago

Commit b20dc3c1 parent 59d59232 files · +85 −17Browse files

Unified · Split

2 files
  1. drivers/net/gtp.c +84 −17
  2. include/uapi/linux/if_link.h +1 −0
drivers/net/gtp.c+84−17
@@ -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
321static void gtp_encap_disable(struct gtp_dev *gtp)323static 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
669static 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
701static 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
659static int gtp_newlink(struct net *src_net, struct net_device *dev,723static 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
731static int gtp_validate(struct nlattr *tb[], struct nlattr *data[],806static 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}
include/uapi/linux/if_link.h+1−0
@@ -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)