Message ID | 20220218145130.6858-1-marcin.szycik@linux.intel.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | ice: GTP support in switchdev | expand |
Please ignore, sent a duplicate by mistake. On 18-Feb-22 15:51, Marcin Szycik wrote: > From: Wojciech Drewek <wojciech.drewek@intel.com> > > 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> > --- > v4: use ntohs when creating UDP socket > v5: IFLA_GTP_CREATE_SOCKETS introduced, gtp_newlink refactor > v6: reordering refactor removed > --- > drivers/net/gtp.c | 101 +++++++++++++++++++++++++++++------ > include/uapi/linux/if_link.h | 1 + > 2 files changed, 85 insertions(+), 17 deletions(-) > > diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c > index bf087171bcf0..25d8521897b3 100644 > --- a/drivers/net/gtp.c > +++ b/drivers/net/gtp.c > @@ -66,8 +66,10 @@ struct gtp_dev { > > struct sock *sk0; > struct sock *sk1u; > + u8 sk_created; > > struct net_device *dev; > + struct net *net; > > unsigned int role; > unsigned int hash_size; > @@ -320,8 +322,16 @@ static void gtp_encap_disable_sock(struct sock *sk) > > static void gtp_encap_disable(struct gtp_dev *gtp) > { > - gtp_encap_disable_sock(gtp->sk0); > - gtp_encap_disable_sock(gtp->sk1u); > + if (gtp->sk_created) { > + udp_tunnel_sock_release(gtp->sk0->sk_socket); > + udp_tunnel_sock_release(gtp->sk1u->sk_socket); > + gtp->sk_created = false; > + gtp->sk0 = NULL; > + gtp->sk1u = NULL; > + } else { > + gtp_encap_disable_sock(gtp->sk0); > + gtp_encap_disable_sock(gtp->sk1u); > + } > } > > /* UDP encapsulation receive handler. See net/ipv4/udp.c. > @@ -656,17 +666,69 @@ static void gtp_destructor(struct net_device *dev) > kfree(gtp->tid_hash); > } > > +static struct sock *gtp_create_sock(int type, struct gtp_dev *gtp) > +{ > + struct udp_tunnel_sock_cfg tuncfg = {}; > + struct udp_port_cfg udp_conf = { > + .local_ip.s_addr = htonl(INADDR_ANY), > + .family = AF_INET, > + }; > + struct net *net = gtp->net; > + struct socket *sock; > + int err; > + > + if (type == UDP_ENCAP_GTP0) > + udp_conf.local_udp_port = htons(GTP0_PORT); > + else if (type == UDP_ENCAP_GTP1U) > + udp_conf.local_udp_port = htons(GTP1U_PORT); > + else > + return ERR_PTR(-EINVAL); > + > + err = udp_sock_create(net, &udp_conf, &sock); > + if (err) > + return ERR_PTR(err); > + > + tuncfg.sk_user_data = gtp; > + tuncfg.encap_type = type; > + tuncfg.encap_rcv = gtp_encap_recv; > + tuncfg.encap_destroy = NULL; > + > + setup_udp_tunnel_sock(net, sock, &tuncfg); > + > + return sock->sk; > +} > + > +static int gtp_create_sockets(struct gtp_dev *gtp, struct nlattr *data[]) > +{ > + struct sock *sk1u = NULL; > + struct sock *sk0 = NULL; > + > + sk0 = gtp_create_sock(UDP_ENCAP_GTP0, gtp); > + if (IS_ERR(sk0)) > + return PTR_ERR(sk0); > + > + sk1u = gtp_create_sock(UDP_ENCAP_GTP1U, gtp); > + if (IS_ERR(sk1u)) { > + udp_tunnel_sock_release(sk0->sk_socket); > + return PTR_ERR(sk1u); > + } > + > + gtp->sk_created = true; > + gtp->sk0 = sk0; > + gtp->sk1u = sk1u; > + > + return 0; > +} > + > static int gtp_newlink(struct net *src_net, struct net_device *dev, > struct nlattr *tb[], struct nlattr *data[], > struct netlink_ext_ack *extack) > { > + unsigned int role = GTP_ROLE_GGSN; > struct gtp_dev *gtp; > struct gtp_net *gn; > int hashsize, err; > > - if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) > - return -EINVAL; > - > gtp = netdev_priv(dev); > > if (!data[IFLA_GTP_PDP_HASHSIZE]) { > @@ -677,11 +739,23 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, > hashsize = 1024; > } > > + if (data[IFLA_GTP_ROLE]) { > + role = nla_get_u32(data[IFLA_GTP_ROLE]); > + if (role > GTP_ROLE_SGSN) > + return -EINVAL; > + } > + gtp->role = role; > + > + gtp->net = src_net; > + > err = gtp_hashtable_new(gtp, hashsize); > if (err < 0) > return err; > > - err = gtp_encap_enable(gtp, data); > + if (data[IFLA_GTP_CREATE_SOCKETS]) > + err = gtp_create_sockets(gtp, data); > + else > + err = gtp_encap_enable(gtp, data); > if (err < 0) > goto out_hashtable; > > @@ -726,6 +800,7 @@ static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = { > [IFLA_GTP_FD1] = { .type = NLA_U32 }, > [IFLA_GTP_PDP_HASHSIZE] = { .type = NLA_U32 }, > [IFLA_GTP_ROLE] = { .type = NLA_U32 }, > + [IFLA_GTP_CREATE_SOCKETS] = { .type = NLA_U8 }, > }; > > 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[]) > { > struct sock *sk1u = NULL; > struct sock *sk0 = NULL; > - unsigned int role = GTP_ROLE_GGSN; > + > + if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) > + return -EINVAL; > > if (data[IFLA_GTP_FD0]) { > 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[]) > } > } > > - if (data[IFLA_GTP_ROLE]) { > - role = nla_get_u32(data[IFLA_GTP_ROLE]); > - if (role > GTP_ROLE_SGSN) { > - gtp_encap_disable_sock(sk0); > - gtp_encap_disable_sock(sk1u); > - return -EINVAL; > - } > - } > - > gtp->sk0 = sk0; > gtp->sk1u = sk1u; > - gtp->role = role; > > return 0; > } > diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h > index 6218f93f5c1a..42f3fb097271 100644 > --- a/include/uapi/linux/if_link.h > +++ b/include/uapi/linux/if_link.h > @@ -822,6 +822,7 @@ enum { > IFLA_GTP_FD1, > IFLA_GTP_PDP_HASHSIZE, > IFLA_GTP_ROLE, > + IFLA_GTP_CREATE_SOCKETS, > __IFLA_GTP_MAX, > }; > #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index bf087171bcf0..25d8521897b3 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -66,8 +66,10 @@ struct gtp_dev { struct sock *sk0; struct sock *sk1u; + u8 sk_created; struct net_device *dev; + struct net *net; unsigned int role; unsigned int hash_size; @@ -320,8 +322,16 @@ static void gtp_encap_disable_sock(struct sock *sk) static void gtp_encap_disable(struct gtp_dev *gtp) { - gtp_encap_disable_sock(gtp->sk0); - gtp_encap_disable_sock(gtp->sk1u); + if (gtp->sk_created) { + udp_tunnel_sock_release(gtp->sk0->sk_socket); + udp_tunnel_sock_release(gtp->sk1u->sk_socket); + gtp->sk_created = false; + gtp->sk0 = NULL; + gtp->sk1u = NULL; + } else { + gtp_encap_disable_sock(gtp->sk0); + gtp_encap_disable_sock(gtp->sk1u); + } } /* UDP encapsulation receive handler. See net/ipv4/udp.c. @@ -656,17 +666,69 @@ static void gtp_destructor(struct net_device *dev) kfree(gtp->tid_hash); } +static struct sock *gtp_create_sock(int type, struct gtp_dev *gtp) +{ + struct udp_tunnel_sock_cfg tuncfg = {}; + struct udp_port_cfg udp_conf = { + .local_ip.s_addr = htonl(INADDR_ANY), + .family = AF_INET, + }; + struct net *net = gtp->net; + struct socket *sock; + int err; + + if (type == UDP_ENCAP_GTP0) + udp_conf.local_udp_port = htons(GTP0_PORT); + else if (type == UDP_ENCAP_GTP1U) + udp_conf.local_udp_port = htons(GTP1U_PORT); + else + return ERR_PTR(-EINVAL); + + err = udp_sock_create(net, &udp_conf, &sock); + if (err) + return ERR_PTR(err); + + tuncfg.sk_user_data = gtp; + tuncfg.encap_type = type; + tuncfg.encap_rcv = gtp_encap_recv; + tuncfg.encap_destroy = NULL; + + setup_udp_tunnel_sock(net, sock, &tuncfg); + + return sock->sk; +} + +static int gtp_create_sockets(struct gtp_dev *gtp, struct nlattr *data[]) +{ + struct sock *sk1u = NULL; + struct sock *sk0 = NULL; + + sk0 = gtp_create_sock(UDP_ENCAP_GTP0, gtp); + if (IS_ERR(sk0)) + return PTR_ERR(sk0); + + sk1u = gtp_create_sock(UDP_ENCAP_GTP1U, gtp); + if (IS_ERR(sk1u)) { + udp_tunnel_sock_release(sk0->sk_socket); + return PTR_ERR(sk1u); + } + + gtp->sk_created = true; + gtp->sk0 = sk0; + gtp->sk1u = sk1u; + + return 0; +} + static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { + unsigned int role = GTP_ROLE_GGSN; struct gtp_dev *gtp; struct gtp_net *gn; int hashsize, err; - if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) - return -EINVAL; - gtp = netdev_priv(dev); if (!data[IFLA_GTP_PDP_HASHSIZE]) { @@ -677,11 +739,23 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, hashsize = 1024; } + if (data[IFLA_GTP_ROLE]) { + role = nla_get_u32(data[IFLA_GTP_ROLE]); + if (role > GTP_ROLE_SGSN) + return -EINVAL; + } + gtp->role = role; + + gtp->net = src_net; + err = gtp_hashtable_new(gtp, hashsize); if (err < 0) return err; - err = gtp_encap_enable(gtp, data); + if (data[IFLA_GTP_CREATE_SOCKETS]) + err = gtp_create_sockets(gtp, data); + else + err = gtp_encap_enable(gtp, data); if (err < 0) goto out_hashtable; @@ -726,6 +800,7 @@ static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = { [IFLA_GTP_FD1] = { .type = NLA_U32 }, [IFLA_GTP_PDP_HASHSIZE] = { .type = NLA_U32 }, [IFLA_GTP_ROLE] = { .type = NLA_U32 }, + [IFLA_GTP_CREATE_SOCKETS] = { .type = NLA_U8 }, }; 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[]) { struct sock *sk1u = NULL; struct sock *sk0 = NULL; - unsigned int role = GTP_ROLE_GGSN; + + if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) + return -EINVAL; if (data[IFLA_GTP_FD0]) { 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[]) } } - if (data[IFLA_GTP_ROLE]) { - role = nla_get_u32(data[IFLA_GTP_ROLE]); - if (role > GTP_ROLE_SGSN) { - gtp_encap_disable_sock(sk0); - gtp_encap_disable_sock(sk1u); - return -EINVAL; - } - } - gtp->sk0 = sk0; gtp->sk1u = sk1u; - gtp->role = role; return 0; } diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 6218f93f5c1a..42f3fb097271 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -822,6 +822,7 @@ enum { IFLA_GTP_FD1, IFLA_GTP_PDP_HASHSIZE, IFLA_GTP_ROLE, + IFLA_GTP_CREATE_SOCKETS, __IFLA_GTP_MAX, }; #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)