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
6666
6767 struct sock *sk0;
6868 struct sock *sk1u;
69+ u8 sk_created;
6970
7071 struct net_device *dev;
72+ struct net *net;
7173
7274 unsigned int role;
7375 unsigned int hash_size;
@@ -320,8 +322,16 @@ static void gtp_encap_disable_sock(struct sock *sk) · 246 unmodified lines
320322
321323 static void gtp_encap_disable(struct gtp_dev *gtp)
322324 {
323− gtp_encap_disable_sock(gtp->sk0);
324− gtp_encap_disable_sock(gtp->sk1u);
325+ if (gtp->sk_created) {
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+ }
325335 }
326336
327337 /* UDP encapsulation receive handler. See net/ipv4/udp.c.
@@ -656,17 +666,69 @@ static void gtp_destructor(struct net_device *dev) · 328 unmodified lines
656666 kfree(gtp->tid_hash);
657667 }
658668
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+
659723 static int gtp_newlink(struct net *src_net, struct net_device *dev,
660724 struct nlattr *tb[], struct nlattr *data[],
661725 struct netlink_ext_ack *extack)
662726 {
727+ unsigned int role = GTP_ROLE_GGSN;
663728 struct gtp_dev *gtp;
664729 struct gtp_net *gn;
665730 int hashsize, err;
666731
667− if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1])
668− return -EINVAL;
669−
670732 gtp = netdev_priv(dev);
671733
672734 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
677739 hashsize = 1024;
678740 }
679741
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+
680751 err = gtp_hashtable_new(gtp, hashsize);
681752 if (err < 0)
682753 return err;
683754
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);
685759 if (err < 0)
686760 goto out_hashtable;
687761
@@ -726,6 +800,7 @@ static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = { · 38 unmodified lines
726800 [IFLA_GTP_FD1] = { .type = NLA_U32 },
727801 [IFLA_GTP_PDP_HASHSIZE] = { .type = NLA_U32 },
728802 [IFLA_GTP_ROLE] = { .type = NLA_U32 },
803+ [IFLA_GTP_CREATE_SOCKETS] = { .type = NLA_U8 },
729804 };
730805
731806 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
848923 {
849924 struct sock *sk1u = NULL;
850925 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;
852929
853930 if (data[IFLA_GTP_FD0]) {
854931 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
868945 }
869946 }
870947
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−
880948 gtp->sk0 = sk0;
881949 gtp->sk1u = sk1u;
882− gtp->role = role;
883950
884951 return 0;
885952 }
include/uapi/linux/if_link.h+1−0
@@ -887,6 +887,7 @@ enum { · 886 unmodified lines
887887 IFLA_GTP_FD1,
888888 IFLA_GTP_PDP_HASHSIZE,
889889 IFLA_GTP_ROLE,
890+ IFLA_GTP_CREATE_SOCKETS,
890891 __IFLA_GTP_MAX,
891892 };
892893 #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)