From christian.r.wilkinson11 at gmail.com Thu Mar 9 01:09:10 2017 From: christian.r.wilkinson11 at gmail.com (Christian Wilkinson) Date: Wed, 8 Mar 2017 20:09:10 -0500 Subject: SMS over GPRS Message-ID: Hi! According to the OsmoSGSN wiki, SMS delivery over GPRS is currently a TODO item. I was wondering about the current state of this feature, and if there is any work in progress that could be built upon. Is there an estimate of the amount of dev work required to contribute this feature to the project? Thanks, Christian -------------- next part -------------- An HTML attachment was scrubbed... URL: From laforge at gnumonks.org Thu Mar 9 08:10:10 2017 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 09 Mar 2017 09:10:10 +0100 Subject: SMS over GPRS In-Reply-To: References: Message-ID: <22F5CA6C-0289-4C9F-9B12-DDCC0F62BC6B@gnumonks.org> It is a TODO item means: somebody yet has to implement it. There is no existing work on it so far. I think there is little effort in the actual transmission of the SMS over a GPRS channel itself. The bigger question is who will handle it and where. SMS handling so far was/is inside the NITB, and GPRS handling is inside the SGSN So the logical choice is to first externalize the SMSC code from the NITB (or now OsmoMSC on which Neels is working) and then simply talk to that external smsc from both the SGSN and the MSC. In terms of effort, I would assume anywhere between one and two weeks full time for somebody familiar with the code. Regards, Harald. -- Sent from a mobile device. Please excuse my brevity. From aschultz at tpip.net Thu Mar 9 16:42:55 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Thu, 9 Mar 2017 17:42:55 +0100 Subject: [PATCH net-next v5 0/7] gtp: misc improvements Message-ID: <20170309164302.13550-1-aschultz@tpip.net> Hi Pablo, This is a resent of last series that missed the merge window. There are no changes compared to v4. v4: Compared to v3 it contains mostly smallish naming and spelling fixes. It also drops the documentation patch, Harald did a better job with the documentation and the some things I described do not yet match the implementation. I'll readd the relevant parts with a follow up series. This series lays the groundwork for removing the socket references from the GTP netdevice by removing duplicate code and simplifying the logic on some code paths. It slighly changes the GTP genl API by making the socket parameters optional (though one of them is still required). The removal of the socket references will break the 1:1 releation between GTP netdevice and GTP socket that prevents us to support multiple VRFs with overlapping IP addresse spaces attached to the same GTP-U entity (needed for multi APN support, coming a follow up series). Pablo found a socket hold problem in v2. In order to solve that I had to switch the socket references from the struct socket to the internal struct sock. This should have no functionl impact, but we can now hang on to the reference without blocking user space from closing the GTP socket. v4->v5: * resent for new merge window v3->v4: * drop the documentation patch * spelling fixes * pass nlattr instead of genl_info into gtp_find_dev, makes the code slightly more compact and readable v2->v3: * add documentation to explain the goal of all these changes * incorporate review comments * switch from struct socket to struct sock Regards Andreas -- Andreas Schultz (7): gtp: switch from struct socket to struct sock for the GTP sockets gtp: make GTP sockets in gtp_newlink optional gtp: merge gtp_get_net and gtp_genl_find_dev gtp: consolidate gtp socket rx path gtp: unify genl_find_pdp and prepare for per socket lookup gtp: consolidate pdp context destruction into helper gtp: add socket to pdp context drivers/net/gtp.c | 543 +++++++++++++++++++++++++++--------------------------- 1 file changed, 269 insertions(+), 274 deletions(-) -- 2.10.2 From aschultz at tpip.net Thu Mar 9 16:42:56 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Thu, 9 Mar 2017 17:42:56 +0100 Subject: [PATCH net-next v5 1/7] gtp: switch from struct socket to struct sock for the GTP sockets In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170309164302.13550-2-aschultz@tpip.net> After enabling the UDP encapsulation, only the sk member is used. Holding the socket would prevent user space from closing the socket, but holding a reference to the sk member does not have the same effect. This change will make it simpler to later detach the sockets from the netdevice. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 8969874..e1b5af3 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -66,8 +66,8 @@ struct pdp_ctx { struct gtp_dev { struct list_head list; - struct socket *sock0; - struct socket *sock1u; + struct sock *sk0; + struct sock *sk1u; struct net_device *dev; @@ -261,17 +261,19 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, static void gtp_encap_disable(struct gtp_dev *gtp) { - if (gtp->sock0 && gtp->sock0->sk) { - udp_sk(gtp->sock0->sk)->encap_type = 0; - rcu_assign_sk_user_data(gtp->sock0->sk, NULL); + if (gtp->sk0) { + udp_sk(gtp->sk0)->encap_type = 0; + rcu_assign_sk_user_data(gtp->sk0, NULL); + sock_put(gtp->sk0); } - if (gtp->sock1u && gtp->sock1u->sk) { - udp_sk(gtp->sock1u->sk)->encap_type = 0; - rcu_assign_sk_user_data(gtp->sock1u->sk, NULL); + if (gtp->sk1u) { + udp_sk(gtp->sk1u)->encap_type = 0; + rcu_assign_sk_user_data(gtp->sk1u, NULL); + sock_put(gtp->sk1u); } - gtp->sock0 = NULL; - gtp->sock1u = NULL; + gtp->sk0 = NULL; + gtp->sk1u = NULL; } static void gtp_encap_destroy(struct sock *sk) @@ -484,14 +486,14 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, switch (pctx->gtp_version) { case GTP_V0: - if (gtp->sock0) - sk = gtp->sock0->sk; + if (gtp->sk0) + sk = gtp->sk0; else sk = NULL; break; case GTP_V1: - if (gtp->sock1u) - sk = gtp->sock1u->sk; + if (gtp->sk1u) + sk = gtp->sk1u; else sk = NULL; break; @@ -504,7 +506,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, return -ENOENT; } - rt = ip4_route_output_gtp(sock_net(sk), &fl4, gtp->sock0->sk, + rt = ip4_route_output_gtp(sock_net(sk), &fl4, gtp->sk0, pctx->sgsn_addr_ip4.s_addr); if (IS_ERR(rt)) { netdev_dbg(dev, "no route to SSGN %pI4\n", @@ -839,18 +841,20 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u); - gtp->sock0 = sock0; - gtp->sock1u = sock1u; + sock_hold(sock0->sk); + gtp->sk0 = sock0->sk; + sock_hold(sock1u->sk); + gtp->sk1u = sock1u->sk; tuncfg.sk_user_data = gtp; tuncfg.encap_rcv = gtp_encap_recv; tuncfg.encap_destroy = gtp_encap_destroy; tuncfg.encap_type = UDP_ENCAP_GTP0; - setup_udp_tunnel_sock(sock_net(gtp->sock0->sk), gtp->sock0, &tuncfg); + setup_udp_tunnel_sock(sock_net(gtp->sk0), sock0, &tuncfg); tuncfg.encap_type = UDP_ENCAP_GTP1U; - setup_udp_tunnel_sock(sock_net(gtp->sock1u->sk), gtp->sock1u, &tuncfg); + setup_udp_tunnel_sock(sock_net(gtp->sk1u), sock1u, &tuncfg); err = 0; err2: -- 2.10.2 From aschultz at tpip.net Thu Mar 9 16:42:57 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Thu, 9 Mar 2017 17:42:57 +0100 Subject: [PATCH net-next v5 2/7] gtp: make GTP sockets in gtp_newlink optional In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170309164302.13550-3-aschultz@tpip.net> Having both GTPv0-U and GTPv1-U is not always desirable. Fallback from GTPv1-U to GTPv0-U was depreciated from 3GPP Rel-8 onwards. Post Rel-8 implementation are discuraged from listening on the v0 port (see 3GPP TS 29.281, Sect. 1). A future change will completely decouple the sockets from the network device. Till then, at least one of the sockets needs to be specified (either v0 or v1), the other is optional. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 148 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 70 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index e1b5af3..9aa2b35 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -259,30 +259,30 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet); } -static void gtp_encap_disable(struct gtp_dev *gtp) -{ - if (gtp->sk0) { - udp_sk(gtp->sk0)->encap_type = 0; - rcu_assign_sk_user_data(gtp->sk0, NULL); - sock_put(gtp->sk0); - } - if (gtp->sk1u) { - udp_sk(gtp->sk1u)->encap_type = 0; - rcu_assign_sk_user_data(gtp->sk1u, NULL); - sock_put(gtp->sk1u); - } - - gtp->sk0 = NULL; - gtp->sk1u = NULL; -} - static void gtp_encap_destroy(struct sock *sk) { struct gtp_dev *gtp; gtp = rcu_dereference_sk_user_data(sk); - if (gtp) - gtp_encap_disable(gtp); + if (gtp) { + udp_sk(sk)->encap_type = 0; + rcu_assign_sk_user_data(sk, NULL); + sock_put(sk); + } +} + +static void gtp_encap_disable_sock(struct sock *sk) +{ + if (!sk) + return; + + gtp_encap_destroy(sk); +} + +static void gtp_encap_disable(struct gtp_dev *gtp) +{ + gtp_encap_disable_sock(gtp->sk0); + gtp_encap_disable_sock(gtp->sk1u); } /* UDP encapsulation receive handler. See net/ipv4/udp.c. @@ -642,27 +642,23 @@ static void gtp_link_setup(struct net_device *dev) static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize); static void gtp_hashtable_free(struct gtp_dev *gtp); -static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, - int fd_gtp0, int fd_gtp1); +static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]); static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - int hashsize, err, fd0, fd1; struct gtp_dev *gtp; struct gtp_net *gn; + int hashsize, err; - if (!data[IFLA_GTP_FD0] || !data[IFLA_GTP_FD1]) + if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) return -EINVAL; gtp = netdev_priv(dev); - fd0 = nla_get_u32(data[IFLA_GTP_FD0]); - fd1 = nla_get_u32(data[IFLA_GTP_FD1]); - - err = gtp_encap_enable(dev, gtp, fd0, fd1); + err = gtp_encap_enable(gtp, data); if (err < 0) - goto out_err; + return err; if (!data[IFLA_GTP_PDP_HASHSIZE]) hashsize = 1024; @@ -690,7 +686,6 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, gtp_hashtable_free(gtp); out_encap: gtp_encap_disable(gtp); -out_err: return err; } @@ -805,63 +800,76 @@ static void gtp_hashtable_free(struct gtp_dev *gtp) kfree(gtp->tid_hash); } -static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, - int fd_gtp0, int fd_gtp1) +static struct sock *gtp_encap_enable_socket(int fd, int type, + struct gtp_dev *gtp) { struct udp_tunnel_sock_cfg tuncfg = {NULL}; - struct socket *sock0, *sock1u; + struct socket *sock; + struct sock *sk; int err; - netdev_dbg(dev, "enable gtp on %d, %d\n", fd_gtp0, fd_gtp1); + pr_debug("enable gtp on %d, %d\n", fd, type); - sock0 = sockfd_lookup(fd_gtp0, &err); - if (sock0 == NULL) { - netdev_dbg(dev, "socket fd=%d not found (gtp0)\n", fd_gtp0); - return -ENOENT; + sock = sockfd_lookup(fd, &err); + if (!sock) { + pr_debug("gtp socket fd=%d not found\n", fd); + return NULL; } - if (sock0->sk->sk_protocol != IPPROTO_UDP) { - netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp0); - err = -EINVAL; - goto err1; + if (sock->sk->sk_protocol != IPPROTO_UDP) { + pr_debug("socket fd=%d not UDP\n", fd); + sk = ERR_PTR(-EINVAL); + goto out_sock; } - sock1u = sockfd_lookup(fd_gtp1, &err); - if (sock1u == NULL) { - netdev_dbg(dev, "socket fd=%d not found (gtp1u)\n", fd_gtp1); - err = -ENOENT; - goto err1; + if (rcu_dereference_sk_user_data(sock->sk)) { + sk = ERR_PTR(-EBUSY); + goto out_sock; } - if (sock1u->sk->sk_protocol != IPPROTO_UDP) { - netdev_dbg(dev, "socket fd=%d not UDP\n", fd_gtp1); - err = -EINVAL; - goto err2; - } - - netdev_dbg(dev, "enable gtp on %p, %p\n", sock0, sock1u); - - sock_hold(sock0->sk); - gtp->sk0 = sock0->sk; - sock_hold(sock1u->sk); - gtp->sk1u = sock1u->sk; + sk = sock->sk; + sock_hold(sk); tuncfg.sk_user_data = gtp; + tuncfg.encap_type = type; tuncfg.encap_rcv = gtp_encap_recv; tuncfg.encap_destroy = gtp_encap_destroy; - tuncfg.encap_type = UDP_ENCAP_GTP0; - setup_udp_tunnel_sock(sock_net(gtp->sk0), sock0, &tuncfg); - - tuncfg.encap_type = UDP_ENCAP_GTP1U; - setup_udp_tunnel_sock(sock_net(gtp->sk1u), sock1u, &tuncfg); - - err = 0; -err2: - sockfd_put(sock1u); -err1: - sockfd_put(sock0); - return err; + setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg); + +out_sock: + sockfd_put(sock); + return sk; +} + +static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]) +{ + struct sock *sk1u = NULL; + struct sock *sk0 = NULL; + + if (data[IFLA_GTP_FD0]) { + u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]); + + sk0 = gtp_encap_enable_socket(fd0, UDP_ENCAP_GTP0, gtp); + if (IS_ERR(sk0)) + return PTR_ERR(sk0); + } + + if (data[IFLA_GTP_FD1]) { + u32 fd1 = nla_get_u32(data[IFLA_GTP_FD1]); + + sk1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, gtp); + if (IS_ERR(sk1u)) { + if (sk0) + gtp_encap_disable_sock(sk0); + return PTR_ERR(sk1u); + } + } + + gtp->sk0 = sk0; + gtp->sk1u = sk1u; + + return 0; } static struct net_device *gtp_find_dev(struct net *net, int ifindex) -- 2.10.2 From aschultz at tpip.net Thu Mar 9 16:42:58 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Thu, 9 Mar 2017 17:42:58 +0100 Subject: [PATCH net-next v5 3/7] gtp: merge gtp_get_net and gtp_genl_find_dev In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170309164302.13550-4-aschultz@tpip.net> Both function are always used together with the final goal to get the gtp_dev. This simplifies the code by merging them together. The netdevice lookup is changed to use the regular dev_get_by_index. The gtp netdevice list is now only used to find the PDP contexts for imcomming packets. It can be completely eliminated Once the TEID hash is moved into the GTP socket. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 146 ++++++++++++++++++++++++++---------------------------- 1 file changed, 69 insertions(+), 77 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 9aa2b35..74018eb 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -744,21 +744,6 @@ static struct rtnl_link_ops gtp_link_ops __read_mostly = { .fill_info = gtp_fill_info, }; -static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[]) -{ - struct net *net; - - /* Examine the link attributes and figure out which network namespace - * we are talking about. - */ - if (tb[GTPA_NET_NS_FD]) - net = get_net_ns_by_fd(nla_get_u32(tb[GTPA_NET_NS_FD])); - else - net = get_net(src_net); - - return net; -} - static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize) { int i; @@ -872,16 +857,30 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]) return 0; } -static struct net_device *gtp_find_dev(struct net *net, int ifindex) +static struct gtp_dev *gtp_find_dev(struct net *src_net, struct nlattr *nla[]) { - struct gtp_net *gn = net_generic(net, gtp_net_id); - struct gtp_dev *gtp; - - list_for_each_entry_rcu(gtp, &gn->gtp_dev_list, list) { - if (ifindex == gtp->dev->ifindex) - return gtp->dev; - } - return NULL; + struct gtp_dev *gtp = NULL; + struct net_device *dev; + struct net *net; + + /* Examine the link attributes and figure out which network namespace + * we are talking about. + */ + if (nla[GTPA_NET_NS_FD]) + net = get_net_ns_by_fd(nla_get_u32(nla[GTPA_NET_NS_FD])); + else + net = get_net(src_net); + + if (IS_ERR(net)) + return NULL; + + /* Check if there's an existing gtpX device to configure */ + dev = dev_get_by_index_rcu(net, nla_get_u32(nla[GTPA_LINK])); + if (dev->netdev_ops == >p_netdev_ops) + gtp = netdev_priv(dev); + + put_net(net); + return gtp; } static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) @@ -911,9 +910,9 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) } } -static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) +static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) { - struct gtp_dev *gtp = netdev_priv(dev); + struct net_device *dev = gtp->dev; u32 hash_ms, hash_tid = 0; struct pdp_ctx *pctx; bool found = false; @@ -990,8 +989,8 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info) static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) { - struct net_device *dev; - struct net *net; + struct gtp_dev *gtp; + int err; if (!info->attrs[GTPA_VERSION] || !info->attrs[GTPA_LINK] || @@ -1015,77 +1014,79 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } - net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); - if (IS_ERR(net)) - return PTR_ERR(net); + rcu_read_lock(); - /* Check if there's an existing gtpX device to configure */ - dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); - if (dev == NULL) { - put_net(net); - return -ENODEV; + gtp = gtp_find_dev(sock_net(skb->sk), info->attrs); + if (!gtp) { + err = -ENODEV; + goto out_unlock; } - put_net(net); - return ipv4_pdp_add(dev, info); + err = ipv4_pdp_add(gtp, info); + +out_unlock: + rcu_read_unlock(); + return err; } static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info) { - struct net_device *dev; struct pdp_ctx *pctx; struct gtp_dev *gtp; - struct net *net; + int err = 0; if (!info->attrs[GTPA_VERSION] || !info->attrs[GTPA_LINK]) return -EINVAL; - net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); - if (IS_ERR(net)) - return PTR_ERR(net); + rcu_read_lock(); - /* Check if there's an existing gtpX device to configure */ - dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); - if (dev == NULL) { - put_net(net); - return -ENODEV; + gtp = gtp_find_dev(sock_net(skb->sk), info->attrs); + if (!gtp) { + err = -ENODEV; + goto out_unlock; } - put_net(net); - - gtp = netdev_priv(dev); switch (nla_get_u32(info->attrs[GTPA_VERSION])) { case GTP_V0: - if (!info->attrs[GTPA_TID]) - return -EINVAL; + if (!info->attrs[GTPA_TID]) { + err = -EINVAL; + goto out_unlock; + } pctx = gtp0_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_TID])); break; case GTP_V1: - if (!info->attrs[GTPA_I_TEI]) - return -EINVAL; + if (!info->attrs[GTPA_I_TEI]) { + err = -EINVAL; + goto out_unlock; + } pctx = gtp1_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_I_TEI])); break; default: - return -EINVAL; + err = -EINVAL; + goto out_unlock; } - if (pctx == NULL) - return -ENOENT; + if (!pctx) { + err = -ENOENT; + goto out_unlock; + } if (pctx->gtp_version == GTP_V0) - netdev_dbg(dev, "GTPv0-U: deleting tunnel id = %llx (pdp %p)\n", + netdev_dbg(gtp->dev, "GTPv0-U: deleting tunnel id = %llx (pdp %p)\n", pctx->u.v0.tid, pctx); else if (pctx->gtp_version == GTP_V1) - netdev_dbg(dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n", + netdev_dbg(gtp->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n", pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx); hlist_del_rcu(&pctx->hlist_tid); hlist_del_rcu(&pctx->hlist_addr); kfree_rcu(pctx, rcu_head); - return 0; +out_unlock: + rcu_read_unlock(); + return err; } static struct genl_family gtp_genl_family; @@ -1129,11 +1130,9 @@ static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, static int gtp_genl_get_pdp(struct sk_buff *skb, struct genl_info *info) { struct pdp_ctx *pctx = NULL; - struct net_device *dev; struct sk_buff *skb2; struct gtp_dev *gtp; u32 gtp_version; - struct net *net; int err; if (!info->attrs[GTPA_VERSION] || @@ -1149,21 +1148,14 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } - net = gtp_genl_get_net(sock_net(skb->sk), info->attrs); - if (IS_ERR(net)) - return PTR_ERR(net); - - /* Check if there's an existing gtpX device to configure */ - dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK])); - if (dev == NULL) { - put_net(net); - return -ENODEV; - } - put_net(net); - - gtp = netdev_priv(dev); - rcu_read_lock(); + + gtp = gtp_find_dev(sock_net(skb->sk), info->attrs); + if (!gtp) { + err = -ENODEV; + goto err_unlock; + } + if (gtp_version == GTP_V0 && info->attrs[GTPA_TID]) { u64 tid = nla_get_u64(info->attrs[GTPA_TID]); -- 2.10.2 From aschultz at tpip.net Thu Mar 9 16:42:59 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Thu, 9 Mar 2017 17:42:59 +0100 Subject: [PATCH net-next v5 4/7] gtp: consolidate gtp socket rx path In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170309164302.13550-5-aschultz@tpip.net> Add network device to gtp context in preparation for splitting the TEID from the network device. Use this to rework the socker rx path. Move the common RX part of v0 and v1 into a helper. Also move the final rx part into that helper as well. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 80 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 74018eb..0c6707a 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -58,6 +58,8 @@ struct pdp_ctx { struct in_addr ms_addr_ip4; struct in_addr sgsn_addr_ip4; + struct net_device *dev; + atomic_t tx_seq; struct rcu_head rcu_head; }; @@ -175,6 +177,40 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx, return false; } +static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen, + bool xnet) +{ + struct pcpu_sw_netstats *stats; + + if (!gtp_check_src_ms(skb, pctx, hdrlen)) { + netdev_dbg(pctx->dev, "No PDP ctx for this MS\n"); + return 1; + } + + /* Get rid of the GTP + UDP headers. */ + if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet)) + return -1; + + netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n"); + + /* Now that the UDP and the GTP header have been removed, set up the + * new network header. This is required by the upper layer to + * calculate the transport header. + */ + skb_reset_network_header(skb); + + skb->dev = pctx->dev; + + stats = this_cpu_ptr(pctx->dev->tstats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); + + netif_rx(skb); + return 0; +} + /* 1 means pass up to the stack, -1 means drop and 0 means decapsulated. */ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, bool xnet) @@ -201,13 +237,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, return 1; } - if (!gtp_check_src_ms(skb, pctx, hdrlen)) { - netdev_dbg(gtp->dev, "No PDP ctx for this MS\n"); - return 1; - } - - /* Get rid of the GTP + UDP headers. */ - return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet); + return gtp_rx(pctx, skb, hdrlen, xnet); } static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, @@ -250,13 +280,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, return 1; } - if (!gtp_check_src_ms(skb, pctx, hdrlen)) { - netdev_dbg(gtp->dev, "No PDP ctx for this MS\n"); - return 1; - } - - /* Get rid of the GTP + UDP headers. */ - return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet); + return gtp_rx(pctx, skb, hdrlen, xnet); } static void gtp_encap_destroy(struct sock *sk) @@ -290,10 +314,9 @@ static void gtp_encap_disable(struct gtp_dev *gtp) */ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) { - struct pcpu_sw_netstats *stats; struct gtp_dev *gtp; + int ret = 0; bool xnet; - int ret; gtp = rcu_dereference_sk_user_data(sk); if (!gtp) @@ -319,33 +342,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) switch (ret) { case 1: netdev_dbg(gtp->dev, "pass up to the process\n"); - return 1; + break; case 0: - netdev_dbg(gtp->dev, "forwarding packet from GGSN to uplink\n"); break; case -1: netdev_dbg(gtp->dev, "GTP packet has been dropped\n"); kfree_skb(skb); - return 0; + ret = 0; + break; } - /* Now that the UDP and the GTP header have been removed, set up the - * new network header. This is required by the upper layer to - * calculate the transport header. - */ - skb_reset_network_header(skb); - - skb->dev = gtp->dev; - - stats = this_cpu_ptr(gtp->dev->tstats); - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += skb->len; - u64_stats_update_end(&stats->syncp); - - netif_rx(skb); - - return 0; + return ret; } static int gtp_dev_init(struct net_device *dev) @@ -951,6 +958,7 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) if (pctx == NULL) return -ENOMEM; + pctx->dev = gtp->dev; ipv4_pdp_fill(pctx, info); atomic_set(&pctx->tx_seq, 0); -- 2.10.2 From aschultz at tpip.net Thu Mar 9 16:43:00 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Thu, 9 Mar 2017 17:43:00 +0100 Subject: [PATCH net-next v5 5/7] gtp: unify genl_find_pdp and prepare for per socket lookup In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170309164302.13550-6-aschultz@tpip.net> This unifies duplicate code into a helper. It also prepares the groundwork to add a lookup version that uses the socket to find attached pdp contexts. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 121 ++++++++++++++++++++++-------------------------------- 1 file changed, 50 insertions(+), 71 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 0c6707a..bf4b352 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -1037,55 +1037,67 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) return err; } +static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net, + struct nlattr *nla[]) +{ + struct gtp_dev *gtp; + + gtp = gtp_find_dev(net, nla); + if (!gtp) + return ERR_PTR(-ENODEV); + + if (nla[GTPA_MS_ADDRESS]) { + __be32 ip = nla_get_be32(nla[GTPA_MS_ADDRESS]); + + return ipv4_pdp_find(gtp, ip); + } else if (nla[GTPA_VERSION]) { + u32 gtp_version = nla_get_u32(nla[GTPA_VERSION]); + + if (gtp_version == GTP_V0 && nla[GTPA_TID]) + return gtp0_pdp_find(gtp, nla_get_u64(nla[GTPA_TID])); + else if (gtp_version == GTP_V1 && nla[GTPA_I_TEI]) + return gtp1_pdp_find(gtp, nla_get_u32(nla[GTPA_I_TEI])); + } + + return ERR_PTR(-EINVAL); +} + +static struct pdp_ctx *gtp_find_pdp(struct net *net, struct nlattr *nla[]) +{ + struct pdp_ctx *pctx; + + if (nla[GTPA_LINK]) + pctx = gtp_find_pdp_by_link(net, nla); + else + pctx = ERR_PTR(-EINVAL); + + if (!pctx) + pctx = ERR_PTR(-ENOENT); + + return pctx; +} + static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info) { struct pdp_ctx *pctx; - struct gtp_dev *gtp; int err = 0; - if (!info->attrs[GTPA_VERSION] || - !info->attrs[GTPA_LINK]) + if (!info->attrs[GTPA_VERSION]) return -EINVAL; rcu_read_lock(); - gtp = gtp_find_dev(sock_net(skb->sk), info->attrs); - if (!gtp) { - err = -ENODEV; - goto out_unlock; - } - - switch (nla_get_u32(info->attrs[GTPA_VERSION])) { - case GTP_V0: - if (!info->attrs[GTPA_TID]) { - err = -EINVAL; - goto out_unlock; - } - pctx = gtp0_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_TID])); - break; - case GTP_V1: - if (!info->attrs[GTPA_I_TEI]) { - err = -EINVAL; - goto out_unlock; - } - pctx = gtp1_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_I_TEI])); - break; - - default: - err = -EINVAL; - goto out_unlock; - } - - if (!pctx) { - err = -ENOENT; + pctx = gtp_find_pdp(sock_net(skb->sk), info->attrs); + if (IS_ERR(pctx)) { + err = PTR_ERR(pctx); goto out_unlock; } if (pctx->gtp_version == GTP_V0) - netdev_dbg(gtp->dev, "GTPv0-U: deleting tunnel id = %llx (pdp %p)\n", + netdev_dbg(pctx->dev, "GTPv0-U: deleting tunnel id = %llx (pdp %p)\n", pctx->u.v0.tid, pctx); else if (pctx->gtp_version == GTP_V1) - netdev_dbg(gtp->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n", + netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n", pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx); hlist_del_rcu(&pctx->hlist_tid); @@ -1139,49 +1151,16 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct genl_info *info) { struct pdp_ctx *pctx = NULL; struct sk_buff *skb2; - struct gtp_dev *gtp; - u32 gtp_version; int err; - if (!info->attrs[GTPA_VERSION] || - !info->attrs[GTPA_LINK]) + if (!info->attrs[GTPA_VERSION]) return -EINVAL; - gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]); - switch (gtp_version) { - case GTP_V0: - case GTP_V1: - break; - default: - return -EINVAL; - } - rcu_read_lock(); - gtp = gtp_find_dev(sock_net(skb->sk), info->attrs); - if (!gtp) { - err = -ENODEV; - goto err_unlock; - } - - if (gtp_version == GTP_V0 && - info->attrs[GTPA_TID]) { - u64 tid = nla_get_u64(info->attrs[GTPA_TID]); - - pctx = gtp0_pdp_find(gtp, tid); - } else if (gtp_version == GTP_V1 && - info->attrs[GTPA_I_TEI]) { - u32 tid = nla_get_u32(info->attrs[GTPA_I_TEI]); - - pctx = gtp1_pdp_find(gtp, tid); - } else if (info->attrs[GTPA_MS_ADDRESS]) { - __be32 ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]); - - pctx = ipv4_pdp_find(gtp, ip); - } - - if (pctx == NULL) { - err = -ENOENT; + pctx = gtp_find_pdp(sock_net(skb->sk), info->attrs); + if (IS_ERR(pctx)) { + err = PTR_ERR(pctx); goto err_unlock; } -- 2.10.2 From aschultz at tpip.net Thu Mar 9 16:43:01 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Thu, 9 Mar 2017 17:43:01 +0100 Subject: [PATCH net-next v5 6/7] gtp: consolidate pdp context destruction into helper In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170309164302.13550-7-aschultz@tpip.net> Consolidate duplicate code into helper. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index bf4b352..d58f46f 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -86,6 +86,8 @@ struct gtp_net { static u32 gtp_h_initval; +static void pdp_context_delete(struct pdp_ctx *pctx); + static inline u32 gtp0_hashfn(u64 tid) { u32 *tid32 = (u32 *) &tid; @@ -780,13 +782,10 @@ static void gtp_hashtable_free(struct gtp_dev *gtp) struct pdp_ctx *pctx; int i; - for (i = 0; i < gtp->hash_size; i++) { - hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) { - hlist_del_rcu(&pctx->hlist_tid); - hlist_del_rcu(&pctx->hlist_addr); - kfree_rcu(pctx, rcu_head); - } - } + for (i = 0; i < gtp->hash_size; i++) + hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) + pdp_context_delete(pctx); + synchronize_rcu(); kfree(gtp->addr_hash); kfree(gtp->tid_hash); @@ -995,6 +994,13 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) return 0; } +static void pdp_context_delete(struct pdp_ctx *pctx) +{ + hlist_del_rcu(&pctx->hlist_tid); + hlist_del_rcu(&pctx->hlist_addr); + kfree_rcu(pctx, rcu_head); +} + static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) { struct gtp_dev *gtp; @@ -1100,9 +1106,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info) netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n", pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx); - hlist_del_rcu(&pctx->hlist_tid); - hlist_del_rcu(&pctx->hlist_addr); - kfree_rcu(pctx, rcu_head); + pdp_context_delete(pctx); out_unlock: rcu_read_unlock(); -- 2.10.2 From aschultz at tpip.net Thu Mar 9 16:43:02 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Thu, 9 Mar 2017 17:43:02 +0100 Subject: [PATCH net-next v5 7/7] gtp: add socket to pdp context In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170309164302.13550-8-aschultz@tpip.net> Having the socket present in context simplifies the sending logic. It also fixes the invalid assumption that we have to use the same sending socket for all client IP's on a specific gtp interface. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 94 +++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index d58f46f..3e1854f 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -58,6 +58,7 @@ struct pdp_ctx { struct in_addr ms_addr_ip4; struct in_addr sgsn_addr_ip4; + struct sock *sk; struct net_device *dev; atomic_t tx_seq; @@ -179,8 +180,7 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx, return false; } -static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen, - bool xnet) +static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen) { struct pcpu_sw_netstats *stats; @@ -190,7 +190,8 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen } /* Get rid of the GTP + UDP headers. */ - if (iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet)) + if (iptunnel_pull_header(skb, hdrlen, skb->protocol, + !net_eq(sock_net(pctx->sk), dev_net(pctx->dev)))) return -1; netdev_dbg(pctx->dev, "forwarding packet from GGSN to uplink\n"); @@ -214,8 +215,7 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen } /* 1 means pass up to the stack, -1 means drop and 0 means decapsulated. */ -static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, - bool xnet) +static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) { unsigned int hdrlen = sizeof(struct udphdr) + sizeof(struct gtp0_header); @@ -239,11 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, return 1; } - return gtp_rx(pctx, skb, hdrlen, xnet); + return gtp_rx(pctx, skb, hdrlen); } -static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, - bool xnet) +static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) { unsigned int hdrlen = sizeof(struct udphdr) + sizeof(struct gtp1_header); @@ -282,7 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, return 1; } - return gtp_rx(pctx, skb, hdrlen, xnet); + return gtp_rx(pctx, skb, hdrlen); } static void gtp_encap_destroy(struct sock *sk) @@ -318,7 +317,6 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) { struct gtp_dev *gtp; int ret = 0; - bool xnet; gtp = rcu_dereference_sk_user_data(sk); if (!gtp) @@ -326,16 +324,14 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk); - xnet = !net_eq(sock_net(sk), dev_net(gtp->dev)); - switch (udp_sk(sk)->encap_type) { case UDP_ENCAP_GTP0: netdev_dbg(gtp->dev, "received GTP0 packet\n"); - ret = gtp0_udp_encap_recv(gtp, skb, xnet); + ret = gtp0_udp_encap_recv(gtp, skb); break; case UDP_ENCAP_GTP1U: netdev_dbg(gtp->dev, "received GTP1U packet\n"); - ret = gtp1u_udp_encap_recv(gtp, skb, xnet); + ret = gtp1u_udp_encap_recv(gtp, skb); break; default: ret = -1; /* Shouldn't happen. */ @@ -378,8 +374,9 @@ static void gtp_dev_uninit(struct net_device *dev) free_percpu(dev->tstats); } -static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4, - const struct sock *sk, __be32 daddr) +static struct rtable *ip4_route_output_gtp(struct flowi4 *fl4, + const struct sock *sk, + __be32 daddr) { memset(fl4, 0, sizeof(*fl4)); fl4->flowi4_oif = sk->sk_bound_dev_if; @@ -388,7 +385,7 @@ static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4, fl4->flowi4_tos = RT_CONN_FLAGS(sk); fl4->flowi4_proto = sk->sk_protocol; - return ip_route_output_key(net, fl4); + return ip_route_output_key(sock_net(sk), fl4); } static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) @@ -477,7 +474,6 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, struct rtable *rt; struct flowi4 fl4; struct iphdr *iph; - struct sock *sk; __be16 df; int mtu; @@ -493,30 +489,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, } netdev_dbg(dev, "found PDP context %p\n", pctx); - switch (pctx->gtp_version) { - case GTP_V0: - if (gtp->sk0) - sk = gtp->sk0; - else - sk = NULL; - break; - case GTP_V1: - if (gtp->sk1u) - sk = gtp->sk1u; - else - sk = NULL; - break; - default: - return -ENOENT; - } - - if (!sk) { - netdev_dbg(dev, "no userspace socket is available, skip\n"); - return -ENOENT; - } - - rt = ip4_route_output_gtp(sock_net(sk), &fl4, gtp->sk0, - pctx->sgsn_addr_ip4.s_addr); + rt = ip4_route_output_gtp(&fl4, pctx->sk, pctx->sgsn_addr_ip4.s_addr); if (IS_ERR(rt)) { netdev_dbg(dev, "no route to SSGN %pI4\n", &pctx->sgsn_addr_ip4.s_addr); @@ -561,7 +534,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, goto err_rt; } - gtp_set_pktinfo_ipv4(pktinfo, sk, iph, pctx, rt, &fl4, dev); + gtp_set_pktinfo_ipv4(pktinfo, pctx->sk, iph, pctx, rt, &fl4, dev); gtp_push_header(skb, pktinfo); return 0; @@ -916,7 +889,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) } } -static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) +static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk, + struct genl_info *info) { struct net_device *dev = gtp->dev; u32 hash_ms, hash_tid = 0; @@ -957,6 +931,8 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) if (pctx == NULL) return -ENOMEM; + sock_hold(sk); + pctx->sk = sk; pctx->dev = gtp->dev; ipv4_pdp_fill(pctx, info); atomic_set(&pctx->tx_seq, 0); @@ -994,16 +970,26 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct genl_info *info) return 0; } +static void pdp_context_free(struct rcu_head *head) +{ + struct pdp_ctx *pctx = container_of(head, struct pdp_ctx, rcu_head); + + sock_put(pctx->sk); + kfree(pctx); +} + static void pdp_context_delete(struct pdp_ctx *pctx) { hlist_del_rcu(&pctx->hlist_tid); hlist_del_rcu(&pctx->hlist_addr); - kfree_rcu(pctx, rcu_head); + call_rcu(&pctx->rcu_head, pdp_context_free); } static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) { + unsigned int version; struct gtp_dev *gtp; + struct sock *sk; int err; if (!info->attrs[GTPA_VERSION] || @@ -1012,7 +998,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) !info->attrs[GTPA_MS_ADDRESS]) return -EINVAL; - switch (nla_get_u32(info->attrs[GTPA_VERSION])) { + version = nla_get_u32(info->attrs[GTPA_VERSION]); + + switch (version) { case GTP_V0: if (!info->attrs[GTPA_TID] || !info->attrs[GTPA_FLOW]) @@ -1036,7 +1024,19 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) goto out_unlock; } - err = ipv4_pdp_add(gtp, info); + if (version == GTP_V0) + sk = gtp->sk0; + else if (version == GTP_V1) + sk = gtp->sk1u; + else + sk = NULL; + + if (!sk) { + err = -ENODEV; + goto out_unlock; + } + + err = ipv4_pdp_add(gtp, sk, info); out_unlock: rcu_read_unlock(); -- 2.10.2 From christian.r.wilkinson11 at gmail.com Fri Mar 10 17:44:52 2017 From: christian.r.wilkinson11 at gmail.com (Christian Wilkinson) Date: Fri, 10 Mar 2017 12:44:52 -0500 Subject: SMS over GPRS In-Reply-To: <22F5CA6C-0289-4C9F-9B12-DDCC0F62BC6B@gnumonks.org> References: <22F5CA6C-0289-4C9F-9B12-DDCC0F62BC6B@gnumonks.org> Message-ID: Thanks for the information! I have a working but somewhat shallow understanding of the code, but maybe I can give it a shot. I have a GSM test lab set up - I'm limited by the speed of sending SMS and was hoping SMS over GPRS would be a solution. I am also considering Osmocom's experimental 3G support (with new hardware) which may be a more appropriate solution without requiring additional dev work. Christian On Thu, Mar 9, 2017 at 3:10 AM, Harald Welte wrote: > It is a TODO item means: somebody yet has to implement it. There is no > existing work on it so far. > > I think there is little effort in the actual transmission of the SMS over > a GPRS channel itself. The bigger question is who will handle it and where. > SMS handling so far was/is inside the NITB, and GPRS handling is inside the > SGSN > > So the logical choice is to first externalize the SMSC code from the NITB > (or now OsmoMSC on which Neels is working) and then simply talk to that > external smsc from both the SGSN and the MSC. > > In terms of effort, I would assume anywhere between one and two weeks full > time for somebody familiar with the code. > > Regards, > Harald. > -- > Sent from a mobile device. Please excuse my brevity. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From laforge at gnumonks.org Sat Mar 11 21:51:47 2017 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 11 Mar 2017 22:51:47 +0100 Subject: [PATCH net-next v5 0/7] gtp: misc improvements In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170311215147.lfyqz4jjtxyo5gm4@nataraja> Hi Andreas, > Andreas Schultz (7): > gtp: switch from struct socket to struct sock for the GTP sockets > gtp: make GTP sockets in gtp_newlink optional > gtp: merge gtp_get_net and gtp_genl_find_dev > gtp: consolidate gtp socket rx path > gtp: unify genl_find_pdp and prepare for per socket lookup > gtp: consolidate pdp context destruction into helper > gtp: add socket to pdp context I agree with the conceptual and architectural direction that you're taking the code, and I also think your current patchset is good to go ahead, so feel free to add my "Acked-By: Harald Welte ". However, the usual disclaimer: I've been out of kernel networking land for a long time, so my review skills are clearly not the best anymore. I'm happy for any input others can give from that point of view. There are some minor typos in the commit logs, but at the rate my typos increase over the years, I am the last one to complain about wasting time on fixing these ;) Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From pablo at netfilter.org Mon Mar 13 16:48:12 2017 From: pablo at netfilter.org (Pablo Neira Ayuso) Date: Mon, 13 Mar 2017 17:48:12 +0100 Subject: [PATCH net-next v5 0/7] gtp: misc improvements In-Reply-To: <20170309164302.13550-1-aschultz@tpip.net> References: <20170309164302.13550-1-aschultz@tpip.net> Message-ID: <20170313164812.GA31925@salvia> On Thu, Mar 09, 2017 at 05:42:55PM +0100, Andreas Schultz wrote: > Hi Pablo, > > This is a resent of last series that missed the merge window. There > are no changes compared to v4. > > v4: Compared to v3 it contains mostly smallish naming and spelling fixes. > It also drops the documentation patch, Harald did a better job with the > documentation and the some things I described do not yet match the implementation. > I'll readd the relevant parts with a follow up series. > > This series lays the groundwork for removing the socket references from > the GTP netdevice by removing duplicate code and simplifying the logic on > some code paths. > > It slighly changes the GTP genl API by making the socket parameters optional > (though one of them is still required). > > The removal of the socket references will break the 1:1 releation between > GTP netdevice and GTP socket that prevents us to support multiple VRFs with > overlapping IP addresse spaces attached to the same GTP-U entity (needed for > multi APN support, coming a follow up series). > > Pablo found a socket hold problem in v2. In order to solve that I had to > switch the socket references from the struct socket to the internal > struct sock. This should have no functionl impact, but we can now hang > on to the reference without blocking user space from closing the GTP socket. Acked-by: Pablo Neira Ayuso I personally don't like this podge hodge unsorted submissions, I don't think they belong to the same series but you keep pushing with this patchset in this same way, which is annoying. In your follow up patchsets, please split them in smaller series that are related. I would like you take the time to develop the VRF idea that you want to introduce, I just would like that we avoid bloating the GTP tunnel with features that we can just achieve via composite of different subsystems. Thank you. From laforge at gnumonks.org Mon Mar 13 17:12:40 2017 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 13 Mar 2017 18:12:40 +0100 Subject: [PATCH net-next v5 0/7] gtp: misc improvements In-Reply-To: <20170313164812.GA31925@salvia> References: <20170309164302.13550-1-aschultz@tpip.net> <20170313164812.GA31925@salvia> Message-ID: <20170313171240.4726igml4b3tm6ff@nataraja> Hi Pablo, On Mon, Mar 13, 2017 at 05:48:12PM +0100, Pablo Neira Ayuso wrote: > I would like you take the time to develop the VRF idea that you want > to introduce, I just would like that we avoid bloating the GTP tunnel > with features that we can just achieve via composite of different > subsystems. I presume you're talking about the "several APN behind one GGSN IP" which requires the de-coupling of the UDP socket from the gtp net-device? I actually think it is a very straight forward idea what Andreas is proposing, and I see no bloat associated. It's rather like splitting existing combined functionality in two parts, which can still be used together, but also be used separately. Or are you referring to something else? In any case, I'm looking forward to the related technical discussion on this mailing list[s] :) Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From aschultz at tpip.net Mon Mar 13 18:45:55 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 13 Mar 2017 19:45:55 +0100 (CET) Subject: [PATCH net-next v5 0/7] gtp: misc improvements In-Reply-To: <20170313164812.GA31925@salvia> References: <20170309164302.13550-1-aschultz@tpip.net> <20170313164812.GA31925@salvia> Message-ID: <1675883877.375949.1489430755546.JavaMail.zimbra@tpip.net> Hi Pablo, ----- On Mar 13, 2017, at 5:48 PM, pablo pablo at netfilter.org wrote: > On Thu, Mar 09, 2017 at 05:42:55PM +0100, Andreas Schultz wrote: >> Hi Pablo, >> >> This is a resent of last series that missed the merge window. There >> are no changes compared to v4. >> >> v4: Compared to v3 it contains mostly smallish naming and spelling fixes. >> It also drops the documentation patch, Harald did a better job with the >> documentation and the some things I described do not yet match the >> implementation. >> I'll readd the relevant parts with a follow up series. >> >> This series lays the groundwork for removing the socket references from >> the GTP netdevice by removing duplicate code and simplifying the logic on >> some code paths. >> >> It slighly changes the GTP genl API by making the socket parameters optional >> (though one of them is still required). >> >> The removal of the socket references will break the 1:1 releation between >> GTP netdevice and GTP socket that prevents us to support multiple VRFs with >> overlapping IP addresse spaces attached to the same GTP-U entity (needed for >> multi APN support, coming a follow up series). >> >> Pablo found a socket hold problem in v2. In order to solve that I had to >> switch the socket references from the struct socket to the internal >> struct sock. This should have no functionl impact, but we can now hang >> on to the reference without blocking user space from closing the GTP socket. > > Acked-by: Pablo Neira Ayuso Thanks, Pablo. > I personally don't like this podge hodge unsorted submissions, I don't > think they belong to the same series but you keep pushing with this > patchset in this same way, which is annoying. I don't think this a podge hodge series. There is a clear goal behind all those changes and every patch is a step towards this. When I tried to send the full series including the final change that ties everything together, I got told that this was way too much. Now, that I split it into a smaller series, I get told that there is no clear idea connecting those changes. Frankly, between the two options, I had no idea how else to submit this work. > In your follow up patchsets, please split them in smaller series that > are related. Now that the basic infrastructure changes are in place, the followup changes are much more focused. The IPv6 transport change might be challenge later one, but that will be a separate series anyway. > I would like you take the time to develop the VRF idea that you want > to introduce, I just would like that we avoid bloating the GTP tunnel > with features that we can just achieve via composite of different > subsystems. The VRF change is more about moving stuff around, it doesn't add much. But you'll see that for yourself when I send the changes. > Thank you. Thank you, Andreas From davem at davemloft.net Mon Mar 13 20:06:52 2017 From: davem at davemloft.net (David Miller) Date: Mon, 13 Mar 2017 13:06:52 -0700 (PDT) Subject: [PATCH net-next v5 0/7] gtp: misc improvements In-Reply-To: <20170313164812.GA31925@salvia> References: <20170309164302.13550-1-aschultz@tpip.net> <20170313164812.GA31925@salvia> Message-ID: <20170313.130652.118680417397625023.davem@davemloft.net> From: Pablo Neira Ayuso Date: Mon, 13 Mar 2017 17:48:12 +0100 > On Thu, Mar 09, 2017 at 05:42:55PM +0100, Andreas Schultz wrote: >> Hi Pablo, >> >> This is a resent of last series that missed the merge window. There >> are no changes compared to v4. >> >> v4: Compared to v3 it contains mostly smallish naming and spelling fixes. >> It also drops the documentation patch, Harald did a better job with the >> documentation and the some things I described do not yet match the implementation. >> I'll readd the relevant parts with a follow up series. >> >> This series lays the groundwork for removing the socket references from >> the GTP netdevice by removing duplicate code and simplifying the logic on >> some code paths. >> >> It slighly changes the GTP genl API by making the socket parameters optional >> (though one of them is still required). >> >> The removal of the socket references will break the 1:1 releation between >> GTP netdevice and GTP socket that prevents us to support multiple VRFs with >> overlapping IP addresse spaces attached to the same GTP-U entity (needed for >> multi APN support, coming a follow up series). >> >> Pablo found a socket hold problem in v2. In order to solve that I had to >> switch the socket references from the struct socket to the internal >> struct sock. This should have no functionl impact, but we can now hang >> on to the reference without blocking user space from closing the GTP socket. > > Acked-by: Pablo Neira Ayuso > > I personally don't like this podge hodge unsorted submissions, I don't > think they belong to the same series but you keep pushing with this > patchset in this same way, which is annoying. > > In your follow up patchsets, please split them in smaller series that > are related. Series applied, and I agree with Pablo. If the best you can come up with for a Subject line in your series header posting is "misc improvements" it absolutely means you are putting unrelated changes together in a series and you need to refine the submission such that only related changes are submitted together. Then you can say "gtp: Adjust GTP socket handling", for example, in your header posting of a 2 patch series that includes only patches #1 and #2. Then you patiently wait for that patch series to be accepted, and then you can move onwards to the other aspects of this series. From aschultz at tpip.net Tue Mar 14 11:25:47 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 14 Mar 2017 12:25:47 +0100 Subject: [PATCH net-next 3/4] gtp: add support to select a GTP socket during PDP context creation In-Reply-To: <20170314112548.24027-1-aschultz@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> Message-ID: <20170314112548.24027-4-aschultz@tpip.net> For each new PDP a separate socket can be selected. The per netdevice default sockets are no longer mandatory. This means also that multiple gtp netdevices can share the same default socket and that therefore the destruction of a gtp netdevice can no longer automatically disable the gtp encapsulation on it's sockets. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index c4cf1b9..afa043d 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -381,9 +381,6 @@ static int gtp_dev_init(struct net_device *dev) static void gtp_dev_uninit(struct net_device *dev) { - struct gtp_dev *gtp = netdev_priv(dev); - - gtp_encap_disable(gtp); free_percpu(dev->tstats); } @@ -647,9 +644,6 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, 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]) @@ -689,8 +683,11 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head) { struct gtp_dev *gtp = netdev_priv(dev); - gtp_encap_disable(gtp); gtp_hashtable_free(gtp); + if (gtp->sk0) + sock_put(gtp->sk0); + if (gtp->sk1u) + sock_put(gtp->sk1u); list_del_rcu(>p->list); unregister_netdevice_queue(dev, head); } @@ -1008,9 +1005,10 @@ static void pdp_context_delete(struct pdp_ctx *pctx) static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) { + struct socket *sock = NULL; + struct sock *sk = NULL; unsigned int version; struct gtp_dev *gtp; - struct sock *sk; int err; if (!info->attrs[GTPA_VERSION] || @@ -1045,12 +1043,14 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) goto out_unlock; } - if (version == GTP_V0) + if (info->attrs[GTPA_FD]) { + sock = sockfd_lookup(nla_get_u32(info->attrs[GTPA_FD]), &err); + if (sock) + sk = sock->sk; + } else if (version == GTP_V0) sk = gtp->sk0; else if (version == GTP_V1) sk = gtp->sk1u; - else - sk = NULL; if (!sk) { err = -ENODEV; @@ -1059,6 +1059,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) err = ipv4_pdp_add(gtp, sk, info); + if (sock) + sockfd_put(sock); + out_unlock: rcu_read_unlock(); return err; @@ -1079,12 +1082,66 @@ static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net, return ipv4_pdp_find(gtp, nla_get_be32(nla[GTPA_MS_ADDRESS])); } +static struct pdp_ctx *gtp_genl_find_pdp_by_socket(struct net *net, + struct nlattr *nla[]) +{ + struct socket *sock; + struct gtp_sock *gsk; + struct pdp_ctx *pctx; + int fd, err = 0; + + if (!nla[GTPA_FD]) + return ERR_PTR(-EINVAL); + + fd = nla_get_u32(nla[GTPA_FD]); + sock = sockfd_lookup(fd, &err); + if (!sock) { + pr_debug("gtp socket fd=%d not found\n", fd); + return ERR_PTR(-EBADF); + } + + gsk = rcu_dereference_sk_user_data(sock->sk); + if (!gsk) { + pctx = ERR_PTR(-EINVAL); + goto out_sock; + } + + switch (nla_get_u32(nla[GTPA_VERSION])) { + case GTP_V0: + if (!nla[GTPA_TID]) { + pctx = ERR_PTR(-EINVAL); + break; + } + pctx = gtp0_pdp_find(gsk, nla_get_u64(nla[GTPA_TID])); + break; + + case GTP_V1: + if (!nla[GTPA_I_TEI]) { + pctx = ERR_PTR(-EINVAL); + break; + } + pctx = gtp1_pdp_find(gsk, nla_get_u64(nla[GTPA_I_TEI])); + break; + + default: + pctx = ERR_PTR(-EINVAL); + break; + } + +out_sock: + sockfd_put(sock); + return pctx; +} + static struct pdp_ctx *gtp_find_pdp(struct net *net, struct nlattr *nla[]) { struct pdp_ctx *pctx; if (nla[GTPA_LINK]) pctx = gtp_find_pdp_by_link(net, nla); + else if (nla[GTPA_FD]) + pctx = gtp_genl_find_pdp_by_socket(net, nla); + else pctx = ERR_PTR(-EINVAL); -- 2.10.2 From aschultz at tpip.net Tue Mar 14 11:25:44 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 14 Mar 2017 12:25:44 +0100 Subject: [PATCH net-next 0/4] gtp: support multiple APN's per GTP endpoint Message-ID: <20170314112548.24027-1-aschultz@tpip.net> Support multiple APN's per GTP endpoint and as an additional benefit support multiple GTP sockets per GTP entity. Use case multiple APN's: ------------------------ In 3GPP a APN is control path construct. When mappend into the data path, it mean that UE IP's can be source from independended IP networks with overlaping IP ranges. 3GPP, TS 29.061 version 13.6.0 Release 13, Section 11.3 describes this as: > 2. each private network manages its own addressing. In general this will > result in different private networks having overlapping address ranges. > A logically separate connection (e.g. an IP in IP tunnel or layer 2 > virtual circuit) is used between the GGSN/P-GW and each private network. > In this case the IP address alone is not necessarily unique. The pair > of values, Access Point Name (APN) and IPv4 address and/or IPv6 prefixes, > is unique. To support such a setup, each APN is mapped to a Linux network device. VRF-Lite, network namespaces or other mechanismns can the be used to realize the full separation of the per APN IP networks. Use case multiple GTP sockets per GTP entity: --------------------------------------------- A GTP entity like a PGW can use multiple GTP sockets for: * separate IPv4 and IPv6 transport endpoints * support multiple reference points in separated IP networks, e.g. have Gn/Gp/S5/S8 in a GRX attaches network and S2a/S2b in another private network Especially the S2a/S2b separation is an important scenario. The networks use for roaming and non roaming attachment (Gn/Gp/S5/S8 reference points) are usually different from the connection for trusted and untrusted WiFi access (S2a/S2b). Will the GTP transport networks are separated, it is still desirable to terminated the tunnels in the same GTP entity to ensure uninterrupted IP connectivity during 3G/LTE to/from WiFi handover. Implementation: --------------- APN's are a control path construct, the identification of the associated network device need therefore to be bound to be tunnel endpoint identifier. This series moves the hash for the incoming tunnel endpoint identifiers into the socket to support multiple network devices per GTP socket. It the adds a method of enabling the GTP encapsulation on a socket without having to bound the socket to a network device and finally allows to specify a GTP socket per PDP context. API impact: ----------- This is probably the most problematic part of this series... The removeal of the TEID form the netdevice also means that the gtp genl API for retriving tunnel information and removing tunnels needs to be adjusted. Before this change it was possible to change a GTP tunnel using the gtp netdevice id and the teid. The teid is no longer unique per gtp netdevice. After this change it has to be either the netdevice and MS IP or the GTP socket and teid. Fortunatly, libgtpnl has always populated the Link Id, TEID, GSN Peer IP and MS IP. The library interface has ensured that all information that is mandatory after this change is guaranteed to be present. The only project that doesn't use libgtpnl (OpenAir-CN) is also populating all of those values. The API change will therefore not break any existing userspace applications. -- Andreas Schultz (4): gtp: move TEID hash to per socket structure gtp: add genl cmd to enable GTP encapsulation on UDP socket gtp: add support to select a GTP socket during PDP context creation Extend Kernel GTP-U tunneling documentation Documentation/networking/gtp.txt | 103 ++++++++++++++- drivers/net/gtp.c | 263 ++++++++++++++++++++++++++++----------- include/uapi/linux/gtp.h | 4 + 3 files changed, 292 insertions(+), 78 deletions(-) -- 2.10.2 From aschultz at tpip.net Tue Mar 14 11:25:45 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 14 Mar 2017 12:25:45 +0100 Subject: [PATCH net-next 1/4] gtp: move TEID hash to per socket structure In-Reply-To: <20170314112548.24027-1-aschultz@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> Message-ID: <20170314112548.24027-2-aschultz@tpip.net> Untangele the TEID information from the network device and move it into a per socket structure. The removeal of the TEID form the netdevice also means that the gtp genl API for retriving tunnel information and removing tunnels needs to be adjusted. Before this change it was possible to change a GTP tunnel using the gtp netdevice id and the teid. The teid is no longer unique per gtp netdevice. So after this change it has to be either the netdevice and MS IP or the GTP socket and teid. Fortunatly, libgtpnl has always populated the Link Id, TEID, GSN Peer IP and MS IP. So, the library interface has ensured that all information that is mandatory after this change is guranteed to be present. The only project that doesn't use libgtpnl (OpenAir-CN) is also populating all of those values. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 145 +++++++++++++++++++++++++++++------------------------- 1 file changed, 78 insertions(+), 67 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 3e1854f..66616f7 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -75,10 +75,15 @@ struct gtp_dev { struct net_device *dev; unsigned int hash_size; - struct hlist_head *tid_hash; struct hlist_head *addr_hash; }; +/* One instance of the GTP socket. */ +struct gtp_sock { + unsigned int hash_size; + struct hlist_head tid_hash[]; +}; + static unsigned int gtp_net_id __read_mostly; struct gtp_net { @@ -106,12 +111,12 @@ static inline u32 ipv4_hashfn(__be32 ip) } /* Resolve a PDP context structure based on the 64bit TID. */ -static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid) +static struct pdp_ctx *gtp0_pdp_find(struct gtp_sock *gsk, u64 tid) { struct hlist_head *head; struct pdp_ctx *pdp; - head = >p->tid_hash[gtp0_hashfn(tid) % gtp->hash_size]; + head = &gsk->tid_hash[gtp0_hashfn(tid) % gsk->hash_size]; hlist_for_each_entry_rcu(pdp, head, hlist_tid) { if (pdp->gtp_version == GTP_V0 && @@ -122,12 +127,12 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid) } /* Resolve a PDP context structure based on the 32bit TEI. */ -static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid) +static struct pdp_ctx *gtp1_pdp_find(struct gtp_sock *gsk, u32 tid) { struct hlist_head *head; struct pdp_ctx *pdp; - head = >p->tid_hash[gtp1u_hashfn(tid) % gtp->hash_size]; + head = &gsk->tid_hash[gtp1u_hashfn(tid) % gsk->hash_size]; hlist_for_each_entry_rcu(pdp, head, hlist_tid) { if (pdp->gtp_version == GTP_V1 && @@ -215,7 +220,7 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen } /* 1 means pass up to the stack, -1 means drop and 0 means decapsulated. */ -static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) +static int gtp0_udp_encap_recv(struct gtp_sock *gsk, struct sk_buff *skb) { unsigned int hdrlen = sizeof(struct udphdr) + sizeof(struct gtp0_header); @@ -233,16 +238,16 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) if (gtp0->type != GTP_TPDU) return 1; - pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid)); + pctx = gtp0_pdp_find(gsk, be64_to_cpu(gtp0->tid)); if (!pctx) { - netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb); + pr_debug("No PDP ctx to decap skb=%p\n", skb); return 1; } return gtp_rx(pctx, skb, hdrlen); } -static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) +static int gtp1u_udp_encap_recv(struct gtp_sock *gsk, struct sk_buff *skb) { unsigned int hdrlen = sizeof(struct udphdr) + sizeof(struct gtp1_header); @@ -275,9 +280,9 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr)); - pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid)); + pctx = gtp1_pdp_find(gsk, ntohl(gtp1->tid)); if (!pctx) { - netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb); + pr_debug("No PDP ctx to decap skb=%p\n", skb); return 1; } @@ -286,13 +291,21 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) static void gtp_encap_destroy(struct sock *sk) { - struct gtp_dev *gtp; + struct gtp_sock *gsk; + struct pdp_ctx *pctx; + int i; - gtp = rcu_dereference_sk_user_data(sk); - if (gtp) { + gsk = rcu_dereference_sk_user_data(sk); + if (gsk) { udp_sk(sk)->encap_type = 0; rcu_assign_sk_user_data(sk, NULL); - sock_put(sk); + + for (i = 0; i < gsk->hash_size; i++) + hlist_for_each_entry_rcu(pctx, &gsk->tid_hash[i], hlist_tid) + pdp_context_delete(pctx); + + synchronize_rcu(); + kfree(gsk); } } @@ -315,23 +328,23 @@ static void gtp_encap_disable(struct gtp_dev *gtp) */ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) { - struct gtp_dev *gtp; + struct gtp_sock *gsk; int ret = 0; - gtp = rcu_dereference_sk_user_data(sk); - if (!gtp) + gsk = rcu_dereference_sk_user_data(sk); + if (!gsk) return 1; - netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk); + pr_debug("encap_recv sk=%p\n", sk); switch (udp_sk(sk)->encap_type) { case UDP_ENCAP_GTP0: - netdev_dbg(gtp->dev, "received GTP0 packet\n"); - ret = gtp0_udp_encap_recv(gtp, skb); + pr_debug("received GTP0 packet\n"); + ret = gtp0_udp_encap_recv(gsk, skb); break; case UDP_ENCAP_GTP1U: - netdev_dbg(gtp->dev, "received GTP1U packet\n"); - ret = gtp1u_udp_encap_recv(gtp, skb); + pr_debug("received GTP1U packet\n"); + ret = gtp1u_udp_encap_recv(gsk, skb); break; default: ret = -1; /* Shouldn't happen. */ @@ -339,12 +352,12 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) switch (ret) { case 1: - netdev_dbg(gtp->dev, "pass up to the process\n"); + pr_debug("pass up to the process\n"); break; case 0: break; case -1: - netdev_dbg(gtp->dev, "GTP packet has been dropped\n"); + pr_debug("GTP packet has been dropped\n"); kfree_skb(skb); ret = 0; break; @@ -624,7 +637,8 @@ static void gtp_link_setup(struct net_device *dev) static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize); static void gtp_hashtable_free(struct gtp_dev *gtp); -static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]); +static int gtp_encap_enable(struct gtp_dev *gtp, int hsize, + struct nlattr *data[]); static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) @@ -638,15 +652,15 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, gtp = netdev_priv(dev); - err = gtp_encap_enable(gtp, data); - if (err < 0) - return err; - if (!data[IFLA_GTP_PDP_HASHSIZE]) hashsize = 1024; else hashsize = nla_get_u32(data[IFLA_GTP_PDP_HASHSIZE]); + err = gtp_encap_enable(gtp, hashsize, data); + if (err < 0) + return err; + err = gtp_hashtable_new(gtp, hashsize); if (err < 0) goto out_encap; @@ -734,20 +748,12 @@ static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize) if (gtp->addr_hash == NULL) return -ENOMEM; - gtp->tid_hash = kmalloc(sizeof(struct hlist_head) * hsize, GFP_KERNEL); - if (gtp->tid_hash == NULL) - goto err1; - gtp->hash_size = hsize; - for (i = 0; i < hsize; i++) { + for (i = 0; i < hsize; i++) INIT_HLIST_HEAD(>p->addr_hash[i]); - INIT_HLIST_HEAD(>p->tid_hash[i]); - } + return 0; -err1: - kfree(gtp->addr_hash); - return -ENOMEM; } static void gtp_hashtable_free(struct gtp_dev *gtp) @@ -756,21 +762,20 @@ static void gtp_hashtable_free(struct gtp_dev *gtp) int i; for (i = 0; i < gtp->hash_size; i++) - hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) + hlist_for_each_entry_rcu(pctx, >p->addr_hash[i], hlist_addr) pdp_context_delete(pctx); synchronize_rcu(); kfree(gtp->addr_hash); - kfree(gtp->tid_hash); } -static struct sock *gtp_encap_enable_socket(int fd, int type, - struct gtp_dev *gtp) +static struct sock *gtp_encap_enable_socket(int fd, int type, int hsize) { struct udp_tunnel_sock_cfg tuncfg = {NULL}; + struct gtp_sock *gsk; struct socket *sock; struct sock *sk; - int err; + int err, i; pr_debug("enable gtp on %d, %d\n", fd, type); @@ -791,10 +796,20 @@ static struct sock *gtp_encap_enable_socket(int fd, int type, goto out_sock; } + gsk = kzalloc(sizeof(*gsk) + sizeof(struct hlist_head) * hsize, GFP_KERNEL); + if (!gsk) { + sk = ERR_PTR(-ENOMEM); + goto out_sock; + } + + gsk->hash_size = hsize; + for (i = 0; i < hsize; i++) + INIT_HLIST_HEAD(&gsk->tid_hash[i]); + sk = sock->sk; sock_hold(sk); - tuncfg.sk_user_data = gtp; + tuncfg.sk_user_data = gsk; tuncfg.encap_type = type; tuncfg.encap_rcv = gtp_encap_recv; tuncfg.encap_destroy = gtp_encap_destroy; @@ -806,7 +821,8 @@ static struct sock *gtp_encap_enable_socket(int fd, int type, return sk; } -static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]) +static int gtp_encap_enable(struct gtp_dev *gtp, int hsize, + struct nlattr *data[]) { struct sock *sk1u = NULL; struct sock *sk0 = NULL; @@ -814,7 +830,7 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]) if (data[IFLA_GTP_FD0]) { u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]); - sk0 = gtp_encap_enable_socket(fd0, UDP_ENCAP_GTP0, gtp); + sk0 = gtp_encap_enable_socket(fd0, UDP_ENCAP_GTP0, hsize); if (IS_ERR(sk0)) return PTR_ERR(sk0); } @@ -822,7 +838,7 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]) if (data[IFLA_GTP_FD1]) { u32 fd1 = nla_get_u32(data[IFLA_GTP_FD1]); - sk1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, gtp); + sk1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, hsize); if (IS_ERR(sk1u)) { if (sk0) gtp_encap_disable_sock(sk0); @@ -895,9 +911,14 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk, struct net_device *dev = gtp->dev; u32 hash_ms, hash_tid = 0; struct pdp_ctx *pctx; + struct gtp_sock *gsk; bool found = false; __be32 ms_addr; + gsk = rcu_dereference_sk_user_data(sk); + if (!gsk) + return -ENODEV; + ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]); hash_ms = ipv4_hashfn(ms_addr) % gtp->hash_size; @@ -944,15 +965,15 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk, * situation in which this doesn't unambiguosly identify the * PDP context. */ - hash_tid = gtp0_hashfn(pctx->u.v0.tid) % gtp->hash_size; + hash_tid = gtp0_hashfn(pctx->u.v0.tid) % gsk->hash_size; break; case GTP_V1: - hash_tid = gtp1u_hashfn(pctx->u.v1.i_tei) % gtp->hash_size; + hash_tid = gtp1u_hashfn(pctx->u.v1.i_tei) % gsk->hash_size; break; } hlist_add_head_rcu(&pctx->hlist_addr, >p->addr_hash[hash_ms]); - hlist_add_head_rcu(&pctx->hlist_tid, >p->tid_hash[hash_tid]); + hlist_add_head_rcu(&pctx->hlist_tid, &gsk->tid_hash[hash_tid]); switch (pctx->gtp_version) { case GTP_V0: @@ -1048,24 +1069,14 @@ static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net, { struct gtp_dev *gtp; + if (!nla[GTPA_MS_ADDRESS]) + return ERR_PTR(-EINVAL); + gtp = gtp_find_dev(net, nla); if (!gtp) return ERR_PTR(-ENODEV); - if (nla[GTPA_MS_ADDRESS]) { - __be32 ip = nla_get_be32(nla[GTPA_MS_ADDRESS]); - - return ipv4_pdp_find(gtp, ip); - } else if (nla[GTPA_VERSION]) { - u32 gtp_version = nla_get_u32(nla[GTPA_VERSION]); - - if (gtp_version == GTP_V0 && nla[GTPA_TID]) - return gtp0_pdp_find(gtp, nla_get_u64(nla[GTPA_TID])); - else if (gtp_version == GTP_V1 && nla[GTPA_I_TEI]) - return gtp1_pdp_find(gtp, nla_get_u32(nla[GTPA_I_TEI])); - } - - return ERR_PTR(-EINVAL); + return ipv4_pdp_find(gtp, nla_get_be32(nla[GTPA_MS_ADDRESS])); } static struct pdp_ctx *gtp_find_pdp(struct net *net, struct nlattr *nla[]) @@ -1209,7 +1220,7 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb, last_gtp = NULL; for (i = k; i < gtp->hash_size; i++) { - hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) { + hlist_for_each_entry_rcu(pctx, >p->addr_hash[i], hlist_addr) { if (tid && tid != pctx->u.tid) continue; else -- 2.10.2 From aschultz at tpip.net Tue Mar 14 11:25:46 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 14 Mar 2017 12:25:46 +0100 Subject: [PATCH net-next 2/4] gtp: add genl cmd to enable GTP encapsulation on UDP socket In-Reply-To: <20170314112548.24027-1-aschultz@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> Message-ID: <20170314112548.24027-3-aschultz@tpip.net> Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/gtp.h | 4 ++++ 2 files changed, 51 insertions(+) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 66616f7..c4cf1b9 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -1244,6 +1244,45 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb, return skb->len; } +static int gtp_genl_enable_socket(struct sk_buff *skb, struct genl_info *info) +{ + u32 version, fd, hashsize; + struct sock *sk; + + if (!info->attrs[GTPA_VERSION] || + !info->attrs[GTPA_FD]) + return -EINVAL; + + if (!info->attrs[GTPA_PDP_HASHSIZE]) + hashsize = 1024; + else + hashsize = nla_get_u32(info->attrs[IFLA_GTP_PDP_HASHSIZE]); + + version = nla_get_u32(info->attrs[GTPA_VERSION]); + fd = nla_get_u32(info->attrs[GTPA_FD]); + + switch (version) { + case GTP_V0: + sk = gtp_encap_enable_socket(fd, UDP_ENCAP_GTP0, hashsize); + break; + + case GTP_V1: + sk = gtp_encap_enable_socket(fd, UDP_ENCAP_GTP1U, hashsize); + break; + + default: + return -EINVAL; + } + + if (!sk) + return -EINVAL; + + if (IS_ERR(sk)) + return PTR_ERR(sk); + + return 0; +} + static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { [GTPA_LINK] = { .type = NLA_U32, }, [GTPA_VERSION] = { .type = NLA_U32, }, @@ -1254,6 +1293,8 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { [GTPA_NET_NS_FD] = { .type = NLA_U32, }, [GTPA_I_TEI] = { .type = NLA_U32, }, [GTPA_O_TEI] = { .type = NLA_U32, }, + [GTPA_PDP_HASHSIZE] = { .type = NLA_U32, }, + [GTPA_FD] = { .type = NLA_U32, }, }; static const struct genl_ops gtp_genl_ops[] = { @@ -1276,6 +1317,12 @@ static const struct genl_ops gtp_genl_ops[] = { .policy = gtp_genl_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = GTP_CMD_ENABLE_SOCKET, + .doit = gtp_genl_enable_socket, + .policy = gtp_genl_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_family gtp_genl_family __ro_after_init = { diff --git a/include/uapi/linux/gtp.h b/include/uapi/linux/gtp.h index 72a04a0..a9e9fe0 100644 --- a/include/uapi/linux/gtp.h +++ b/include/uapi/linux/gtp.h @@ -6,6 +6,8 @@ enum gtp_genl_cmds { GTP_CMD_DELPDP, GTP_CMD_GETPDP, + GTP_CMD_ENABLE_SOCKET, + GTP_CMD_MAX, }; @@ -26,6 +28,8 @@ enum gtp_attrs { GTPA_I_TEI, /* for GTPv1 only */ GTPA_O_TEI, /* for GTPv1 only */ GTPA_PAD, + GTPA_PDP_HASHSIZE, + GTPA_FD, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) -- 2.10.2 From aschultz at tpip.net Tue Mar 14 11:25:48 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 14 Mar 2017 12:25:48 +0100 Subject: [PATCH net-next 4/4] Extend Kernel GTP-U tunneling documentation In-Reply-To: <20170314112548.24027-1-aschultz@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> Message-ID: <20170314112548.24027-5-aschultz@tpip.net> * clarify specification references for v0/v1 * add section "APN vs. Network device" * add section "Local GTP-U entity and tunnel identification" Signed-off-by: Andreas Schultz Signed-off-by: Harald Welte --- Documentation/networking/gtp.txt | 103 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/gtp.txt b/Documentation/networking/gtp.txt index 93e9675..0d9c18f 100644 --- a/Documentation/networking/gtp.txt +++ b/Documentation/networking/gtp.txt @@ -1,6 +1,7 @@ The Linux kernel GTP tunneling module ====================================================================== -Documentation by Harald Welte +Documentation by Harald Welte and + Andreas Schultz In 'drivers/net/gtp.c' you are finding a kernel-level implementation of a GTP tunnel endpoint. @@ -91,9 +92,13 @@ http://git.osmocom.org/libgtpnl/ == Protocol Versions == -There are two different versions of GTP-U: v0 and v1. Both are -implemented in the Kernel GTP module. Version 0 is a legacy version, -and deprecated from recent 3GPP specifications. +There are two different versions of GTP-U: v0 [GSM TS 09.60] and v1 +[3GPP TS 29.281]. Both are implemented in the Kernel GTP module. +Version 0 is a legacy version, and deprecated from recent 3GPP +specifications. + +GTP-U uses UDP for transporting PDUs. The receiving UDP port is 2151 +for GTPv1-U and 3386 for GTPv0-U. There are three versions of GTP-C: v0, v1, and v2. As the kernel doesn't implement GTP-C, we don't have to worry about this. It's the @@ -133,3 +138,93 @@ doe to a lack of user interest, it never got merged. In 2015, Andreas Schultz came to the rescue and fixed lots more bugs, extended it with new features and finally pushed all of us to get it mainline, where it was merged in 4.7.0. + +== Architectural Details == + +=== Local GTP-U entity and tunnel identification === + +GTP-U uses UDP for transporting PDU's. The receiving UDP port is 2152 +for GTPv1-U and 3386 for GTPv0-U. + +There is only one GTP-U entity (and therefor SGSN/GGSN/S-GW/PDN-GW +instance) per IP address. Tunnel Endpoint Identifier (TEID) are unique +per GTP-U entity. + +A specific tunnel is only defined by the destination entity. Since the +destination port is constant, only the destination IP and TEID define +a tunnel. The source IP and Port have no meaning for the tunnel. + +Therefore: + + * when sending, the remote entity is defined by the remote IP and + the tunnel endpoint id. The source IP and port have no meaning and + can be changed at any time. + + * when receiving the local entity is defined by the local + destination IP and the tunnel endpoint id. The source IP and port + have no meaning and can change at any time. + +[3GPP TS 29.281] Section 4.3.0 defines this so: + +> The TEID in the GTP-U header is used to de-multiplex traffic +> incoming from remote tunnel endpoints so that it is delivered to the +> User plane entities in a way that allows multiplexing of different +> users, different packet protocols and different QoS levels. +> Therefore no two remote GTP-U endpoints shall send traffic to a +> GTP-U protocol entity using the same TEID value except +> for data forwarding as part of mobility procedures. + +The definition above only defines that two remote GTP-U endpoints +*should not* send to the same TEID, it *does not* forbid or exclude +such a scenario. In fact, the mentioned mobility procedures make it +necessary that the GTP-U entity accepts traffic for TEIDs from +multiple or unknown peers. + +Therefore, the receiving side identifies tunnels exclusively based on +TEIDs, not based on the source IP! + +== APN vs. Network Device == + +The GTP-U driver creates a Linux network device for each Gi/SGi +interface. + +[3GPP TS 29.281] calls the Gi/SGi reference point an interface. This +may lead to the impression that the GGSN/P-GW can have only one such +interface. + +Correct is that the Gi/SGi reference point defines the interworking +between +the 3GPP packet domain (PDN) based on GTP-U tunnel and IP +based networks. + +There is no provision in any of the 3GPP documents that limits the +number of Gi/SGi interfaces implemented by a GGSN/P-GW. + +[3GPP TS 29.061] Section 11.3 makes it clear that the selection of a +specific Gi/SGi interfaces is made through the Access Point Name +(APN): + +> 2. each private network manages its own addressing. In general this +> will result in different private networks having overlapping +> address ranges. A logically separate connection (e.g. an IP in IP +> tunnel or layer 2 virtual circuit) is used between the GGSN/P-GW +> and each private network. +> +> In this case the IP address alone is not necessarily unique. The +> pair of values, Access Point Name (APN) and IPv4 address and/or +> IPv6 prefixes, is unique. + +In order to support the overlapping address range use case, each APN +is mapped to a separate Gi/SGi interface (network device). + +NOTE: The Access Point Name is purely a control plane (GTP-C) concept. +At the GTP-U level, only Tunnel Endpoint Identifiers are present in +GTP-U packets and network devices are known + +Therefore for a given UE the mapping in IP to PDN network is: + * network device + MS IP -> Peer IP + Peer TEID, + +and from PDN to IP network: + * local GTP-U IP + TEID -> network device + +Furthermore, before a received T-PDU is injected into the network +device the MS IP is checked against the IP recorded in PDP context. -- 2.10.2 From pablo at netfilter.org Tue Mar 14 11:33:00 2017 From: pablo at netfilter.org (Pablo Neira Ayuso) Date: Tue, 14 Mar 2017 12:33:00 +0100 Subject: [PATCH net-next 1/4] gtp: move TEID hash to per socket structure In-Reply-To: <20170314112548.24027-2-aschultz@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314112548.24027-2-aschultz@tpip.net> Message-ID: <20170314113300.GA2992@salvia> On Tue, Mar 14, 2017 at 12:25:45PM +0100, Andreas Schultz wrote: > @@ -275,9 +280,9 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) > > gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr)); > > - pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid)); > + pctx = gtp1_pdp_find(gsk, ntohl(gtp1->tid)); > if (!pctx) { > - netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb); > + pr_debug("No PDP ctx to decap skb=%p\n", skb); > return 1; Again the pr_debug() change has resurrected. I already told you: If we are going to have more than one gtp device, then this doesn't make sense. I have to repeat things over and over again, just because you don't want to rebase your patchset for some reason. I don't find any other explaination for this. So please remove this debugging rather than rendering this completely useful. Moreover this change has nothing to this patch, so this doesn't break the one logical change per patch. From pablo at netfilter.org Tue Mar 14 11:43:30 2017 From: pablo at netfilter.org (Pablo Neira Ayuso) Date: Tue, 14 Mar 2017 12:43:30 +0100 Subject: [PATCH net-next 2/4] gtp: add genl cmd to enable GTP encapsulation on UDP socket In-Reply-To: <20170314112548.24027-3-aschultz@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314112548.24027-3-aschultz@tpip.net> Message-ID: <20170314114330.GB2992@salvia> On Tue, Mar 14, 2017 at 12:25:46PM +0100, Andreas Schultz wrote: > @@ -1254,6 +1293,8 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { > [GTPA_NET_NS_FD] = { .type = NLA_U32, }, > [GTPA_I_TEI] = { .type = NLA_U32, }, > [GTPA_O_TEI] = { .type = NLA_U32, }, > + [GTPA_PDP_HASHSIZE] = { .type = NLA_U32, }, This per PDP hashsize attribute clearly doesn't belong here. Moreover, we now have a rhashtable implementation, so we hopefully we can get rid of this. It should be very easy to convert this to use rhashtable, and it is very much desiderable. > + [GTPA_FD] = { .type = NLA_U32, }, This new atttribute has nothing to do with the PDP context. And enum gtp_attrs *only* describe a PDP context. Adding more attributes there to mix semantics is not the way to go. You likely have to inaugurate a new enum. This gtp_attrs enum only related to the PDP description. Why not add some interface to attach more sockets to the gtp device globally? So still the gtp device is the top-level structure. Then add a netlink attribute to specify to what VRF this tunnel belongs to, instead of implicitly using the socket to achieve this. Another possibility is to explicitly have an interface to add new/delete VRFs, attach sockets to them. In general, I'm still not convinced this is the right design for this. From pablo at netfilter.org Tue Mar 14 11:45:38 2017 From: pablo at netfilter.org (Pablo Neira Ayuso) Date: Tue, 14 Mar 2017 12:45:38 +0100 Subject: [PATCH net-next 0/4] gtp: support multiple APN's per GTP endpoint In-Reply-To: <20170314112548.24027-1-aschultz@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> Message-ID: <20170314114538.GC2992@salvia> On Tue, Mar 14, 2017 at 12:25:44PM +0100, Andreas Schultz wrote: [...] > API impact: > ----------- > > This is probably the most problematic part of this series... > > The removeal of the TEID form the netdevice also means that the gtp genl API > for retriving tunnel information and removing tunnels needs to be adjusted. > > Before this change it was possible to change a GTP tunnel using the gtp > netdevice id and the teid. The teid is no longer unique per gtp netdevice. > After this change it has to be either the netdevice and MS IP or the GTP > socket and teid. Then we have to introduce some explicit VRF concept or such to sort out this. It is definitely not acceptable to break the existing API. From aschultz at tpip.net Tue Mar 14 12:28:25 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 14 Mar 2017 13:28:25 +0100 (CET) Subject: [PATCH net-next 2/4] gtp: add genl cmd to enable GTP encapsulation on UDP socket In-Reply-To: <20170314114330.GB2992@salvia> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314112548.24027-3-aschultz@tpip.net> <20170314114330.GB2992@salvia> Message-ID: <1491326012.385002.1489494505868.JavaMail.zimbra@tpip.net> ----- On Mar 14, 2017, at 12:43 PM, pablo pablo at netfilter.org wrote: > On Tue, Mar 14, 2017 at 12:25:46PM +0100, Andreas Schultz wrote: > >> @@ -1254,6 +1293,8 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { >> [GTPA_NET_NS_FD] = { .type = NLA_U32, }, >> [GTPA_I_TEI] = { .type = NLA_U32, }, >> [GTPA_O_TEI] = { .type = NLA_U32, }, >> + [GTPA_PDP_HASHSIZE] = { .type = NLA_U32, }, > > This per PDP hashsize attribute clearly doesn't belong here. > > Moreover, we now have a rhashtable implementation, so we hopefully we > can get rid of this. It should be very easy to convert this to use > rhashtable, and it is very much desiderable. This would mean I have to mix the unrelated rhashtable change with moving the hash into the socket. This certainly is not desirable either. So, I'm going to have a look at the rhashtable thing and send a patch first to convert the hashes to it. >> + [GTPA_FD] = { .type = NLA_U32, }, > > This new atttribute has nothing to do with the PDP context. > And enum gtp_attrs *only* describe a PDP context. Adding more > attributes there to mix semantics is not the way to go. You seem to assume that the network device or the APN/VRF is the root entity for the GTP tunnels. That is IMHO wrong. The 3GPP specification clearly defines a GTP entity that is completely Independent from an APN or the local IP endpoint. A GTP entity serves multiple local IP endpoints, It manages outgoing tunnels by the local APN/VRF, source IP, destination IP and remote tunnel id, incoming tunnels are managed by the local destination IP, local tunnel id and VRF/APN. Therefor a PDP context needs the following attributes: * local source/destination IP (and port - but that's for different series) * remote destination IP * local and remote TEID * VRF/APN The local source and destination IP is implicitly contained in the socket, therefor the socket needs to part of the context. The VRF/APN is contained in the network device reference. So this also needs to part of the PDP context. Having either the socket or the network device as the sole root container for a GTP entity is wrong since the PDP context always refer both. > You likely have to inaugurate a new enum. This gtp_attrs enum only > related to the PDP description. > > Why not add some interface to attach more sockets to the gtp device > globally? So still the gtp device is the top-level structure. That is IMHO the wrong model. In a real live setup it likely to have a few GTP sockets and possibly hundreds if not thousands of network device attached to them (we already had the discussion why this kind of sharing makes sense). So from a resource perspective alone, having the network device as root makes no sense. > Then add > a netlink attribute to specify to what VRF this tunnel belongs to, > instead of implicitly using the socket to achieve this. You got that the wrong way arround. The VRF is already in the PDP context through the network device reference. The socket is added to the PDP context to select the outgoing source IP of the GTP tunnel in order to support multiple GTP source IP's per GTP entity. > Another possibility is to explicitly have an interface to add > new/delete VRFs, attach sockets to them. We already have that interface. It's the create a GTP network interface genl API. I explained a few lines above why I think that adding sockets to GTP network devices is wrong. > In general, I'm still not convinced this is the right design for this. Following your "add VRF" idea, I would end up with a pseudo network device that represents a GTP entity. This would be the root instance for all the VRF's and GTP sockets. Although being a network device, it would not behave in any way like a network device, it would not handle traffic or have IP(v6) addresses attached to it. I would then further have GTP VRF network devices. Those would be "real" network device that handle traffic and have IP addresses/route attached to them. I'm not sure if this pseudo GTP entity root device fits well with other networking concepts. And more over, I can't really see the need for such an construct. This need for an in-kernel root entity seem to come the concept that the kernel *owns* the tunnels and that tunnel a static and independent from the user space control instance. I think that the user space control instance should own the tunnels and only use the kernel facility to manage them. When the user space instance goes away, so should the tunnels. >From that perspective, I want to keep the kernel facilities to the absolute needed minimum. Regards Andreas From aschultz at tpip.net Tue Mar 14 12:32:35 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 14 Mar 2017 13:32:35 +0100 (CET) Subject: [PATCH net-next 1/4] gtp: move TEID hash to per socket structure In-Reply-To: <20170314113300.GA2992@salvia> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314112548.24027-2-aschultz@tpip.net> <20170314113300.GA2992@salvia> Message-ID: <687079207.385041.1489494755160.JavaMail.zimbra@tpip.net> ----- On Mar 14, 2017, at 12:33 PM, pablo pablo at netfilter.org wrote: > On Tue, Mar 14, 2017 at 12:25:45PM +0100, Andreas Schultz wrote: >> @@ -275,9 +280,9 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct >> sk_buff *skb) >> >> gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr)); >> >> - pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid)); >> + pctx = gtp1_pdp_find(gsk, ntohl(gtp1->tid)); >> if (!pctx) { >> - netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb); >> + pr_debug("No PDP ctx to decap skb=%p\n", skb); >> return 1; > > Again the pr_debug() change has resurrected. Yes, at that point in the code, there is now ways to resolve the network device. Therefore the netdev_dbg has to go. > I already told you: If we are going to have more than one gtp device, > then this doesn't make sense. I have to repeat things over and over > again, just because you don't want to rebase your patchset for some > reason. I don't find any other explaination for this. Without a PDP context, there is no network device, so netdev_dbg. > So please remove this debugging rather than rendering this completely > useful. ACK > Moreover this change has nothing to this patch, so this doesn't break > the one logical change per patch. This patch moves the incoming teid has from the network device to the socket. This means that gtp1_pdp_find needs to change. So this related. For the debug change, see above why it's related. Andreas From aschultz at tpip.net Tue Mar 14 12:42:44 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 14 Mar 2017 13:42:44 +0100 (CET) Subject: [PATCH net-next 0/4] gtp: support multiple APN's per GTP endpoint In-Reply-To: <20170314114538.GC2992@salvia> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314114538.GC2992@salvia> Message-ID: <2005226672.385248.1489495364893.JavaMail.zimbra@tpip.net> ----- On Mar 14, 2017, at 12:45 PM, pablo pablo at netfilter.org wrote: > On Tue, Mar 14, 2017 at 12:25:44PM +0100, Andreas Schultz wrote: > [...] >> API impact: >> ----------- >> >> This is probably the most problematic part of this series... >> >> The removeal of the TEID form the netdevice also means that the gtp genl API >> for retriving tunnel information and removing tunnels needs to be adjusted. >> >> Before this change it was possible to change a GTP tunnel using the gtp >> netdevice id and the teid. The teid is no longer unique per gtp netdevice. >> After this change it has to be either the netdevice and MS IP or the GTP >> socket and teid. > > Then we have to introduce some explicit VRF concept or such to sort > out this. > > It is definitely not acceptable to break the existing API. The specific use case of the API that is no longer supported was never used by anyone. The only supported and documented API for the GTP module is libgtpnl. libgtpnl has always required the now mandatory fields. Therefor the externally supported API does not change. Regards Andreas From pablo at netfilter.org Tue Mar 14 13:39:57 2017 From: pablo at netfilter.org (Pablo Neira Ayuso) Date: Tue, 14 Mar 2017 14:39:57 +0100 Subject: [PATCH net-next 2/4] gtp: add genl cmd to enable GTP encapsulation on UDP socket In-Reply-To: <1491326012.385002.1489494505868.JavaMail.zimbra@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314112548.24027-3-aschultz@tpip.net> <20170314114330.GB2992@salvia> <1491326012.385002.1489494505868.JavaMail.zimbra@tpip.net> Message-ID: <20170314133957.GA3838@salvia> On Tue, Mar 14, 2017 at 01:28:25PM +0100, Andreas Schultz wrote: > ----- On Mar 14, 2017, at 12:43 PM, pablo pablo at netfilter.org wrote: [...] > A GTP entity serves multiple local IP endpoints, It manages outgoing tunnels > by the local APN/VRF, source IP, destination IP and remote tunnel id, incoming > tunnels are managed by the local destination IP, local tunnel id and VRF/APN. > > Therefor a PDP context needs the following attributes: > > * local source/destination IP (and port - but that's for different series) > * remote destination IP > * local and remote TEID > * VRF/APN [...] > I'm not sure if this pseudo GTP entity root device fits well with > other networking concepts. And more over, I can't really see the need > for such an construct. Some sort of top-level structure that wraps all these objects is needed, and that can be a new VRF object itself. You can add a netlink interface to add/dump/delete VRFs, this VRF database would be *global* to the GSN. At VRF creation, you attach the socket and the GTP device. You can share sockets between VRFs. PDP context objects would be added to the corresponding VRF *not to the socket*, but actually this will result in inserting this PDP context into the socket hashtable and the GTP device hashtable. We need to introduce a default VRF that is assumed to always exist, and that userspace cannot remove, so things don't break backward. If no VRF is specified, then we attach things to this default VRF. Actually, look at this from a different angle: the existing driver is just supporting *one single VRF* at this moment so we just have to represent this explicitly. Breaking existing API is a no-go. This explicit VRF concept would also allow us to dump PDP contexts that belong to a given VRF, by simply indicating the VRF unique id. Jamal already requested that we extend iproute2 to have command to inspect the gtp driver we cannot escape this, we should allow standalone tools to inspect the gtp datapath as we do with other existing tunnel drivers, no matter what daemon in userspace implements the control plane. [...] > I think that the user space control instance should own the tunnels and > only use the kernel facility to manage them. When the user space instance > goes away, so should the tunnels. This doesn't allow daemon hot restart for whatever administrative reason without affecting existing traffic. The kernel owns the datapath indeed, that include tunnels. > From that perspective, I want to keep the kernel facilities to the > absolute needed minimum. If some simple abstraction that we can insert makes this whole thing more maintainable, then it makes sense to consider it. This is all about not exposing the internal layout of the representation you use for a very specific reason: The more you expose internal details to userspace, the more problems we'll have to extend things later on in the future. And don't try to be smart and say: "Hey, I already know every usecase we will have in the future" because that is not true. From pablo at netfilter.org Tue Mar 14 13:42:16 2017 From: pablo at netfilter.org (Pablo Neira Ayuso) Date: Tue, 14 Mar 2017 14:42:16 +0100 Subject: [PATCH net-next 0/4] gtp: support multiple APN's per GTP endpoint In-Reply-To: <2005226672.385248.1489495364893.JavaMail.zimbra@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314114538.GC2992@salvia> <2005226672.385248.1489495364893.JavaMail.zimbra@tpip.net> Message-ID: <20170314134216.GA4170@salvia> On Tue, Mar 14, 2017 at 01:42:44PM +0100, Andreas Schultz wrote: > > It is definitely not acceptable to break the existing API. > > The specific use case of the API that is no longer supported was never used by > anyone. [...] Yes, this was used openggsn and I tested this with a full blown FOSS setup. Yes, a toy thing compared to the proprietary equipment you deal with, but we always started with things like this. > The only supported and documented API for the GTP module is libgtpnl. No, the netlink interface itself if the API. Stopping trying to find a reason to break API, that is a no-go. From laforge at gnumonks.org Tue Mar 14 13:52:59 2017 From: laforge at gnumonks.org (Harald Welte) Date: Tue, 14 Mar 2017 14:52:59 +0100 Subject: [PATCH net-next 0/4] gtp: support multiple APN's per GTP endpoint In-Reply-To: <20170314134216.GA4170@salvia> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314114538.GC2992@salvia> <2005226672.385248.1489495364893.JavaMail.zimbra@tpip.net> <20170314134216.GA4170@salvia> Message-ID: <20170314135259.xcu6d24higtla7k5@nataraja> Hi Andreas, On Tue, Mar 14, 2017 at 02:42:16PM +0100, Pablo Neira Ayuso wrote: > On Tue, Mar 14, 2017 at 01:42:44PM +0100, Andreas Schultz wrote: > > The only supported and documented API for the GTP module is libgtpnl. > > No, the netlink interface itself if the API. > > Stopping trying to find a reason to break API, that is a no-go. As much as one might dislike it as a developer in this particular case, the Linux kernel has the very well communicated rule: All userspace visible interfaces must not change in an incompatible way. This includes of course all the syscalls, the ioctl() parameters but also the netlink interfaces of the networking stack. The statement "nobody ever used it" is a statement you can never make in FOSS software, as you don't know of 99.9999999% of all the users of your software. The fact that none of the FOSS projects that any of us was involved in may not have used a certain feature doesn't mean nobody else has been using it privately, quietly. Keep in mind that several Linux distributions have already been shipping the gtp module as part of their stable releases meanwhile. Also, no matter what Pablo or I may think about, there are general rules about how Linux kernel development is done (from coding style to merge windows, and also userspace compatibility), and we all have to obey them. There's little point in discussing about them, we all just have to live with them. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From davem at davemloft.net Tue Mar 14 18:32:09 2017 From: davem at davemloft.net (David Miller) Date: Tue, 14 Mar 2017 11:32:09 -0700 (PDT) Subject: [PATCH net-next 0/4] gtp: support multiple APN's per GTP endpoint In-Reply-To: <2005226672.385248.1489495364893.JavaMail.zimbra@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> <20170314114538.GC2992@salvia> <2005226672.385248.1489495364893.JavaMail.zimbra@tpip.net> Message-ID: <20170314.113209.1471920938953197702.davem@davemloft.net> From: Andreas Schultz Date: Tue, 14 Mar 2017 13:42:44 +0100 (CET) > The specific use case of the API that is no longer supported was never used by > anyone. The only supported and documented API for the GTP module is libgtpnl. > libgtpnl has always required the now mandatory fields. Therefor the externally > supported API does not change. That's not how kernel development works, sorry. Any user visible interface the kernel exports is not to be broken, even if you think you control the one library that makes use of it. This is especially important for netlink because netlink is more like a networking protocol, that arbitrary programs can listen to for events. From laforge at netfilter.org Wed Mar 15 19:10:38 2017 From: laforge at netfilter.org (Harald Welte) Date: Wed, 15 Mar 2017 20:10:38 +0100 Subject: [PATCH 1/1] gtp: support SGSN-side tunnels In-Reply-To: <20170315172348.GA30592@salvia> References: <20170203091231.10142-1-jonas@southpole.se> <20170315163916.gins7lzzqhwkvfrc@nataraja> <20170315172348.GA30592@salvia> Message-ID: <20170315191038.nco2icu6e545rzlu@nataraja> Hi Pablo, On Wed, Mar 15, 2017 at 06:23:48PM +0100, Pablo Neira Ayuso wrote: > On Wed, Mar 15, 2017 at 05:39:16PM +0100, Harald Welte wrote: > > > > I would definitely like to see this move forward, particularly in order > > to test the GGSN-side code. > > Agreed. I've modified the patch slightly, see below (compile-tested, but not otherwise tested yet). Basically rename the flags attribute to 'role', expand the commit log and removed unrelated cosmetic changes. I've also prepared a corresponding change to libgtpnl into the laforge/sgsn-rol branch, see http://git.osmocom.org/libgtpnl/commit/?h=laforge/sgsn-role This is not yet tested in any way, but I'm planning to add some associated support to the command line tools and then give it some testing (both against the kernel GTP in GGSN mode, as well as an independent userspace GTP implementation). > It would be good if we provide a way to configure GTP via iproute2 for > testing purposes. I don't really care about which tool is used, as long as it is easily available [and FOSS, of course]. > We would need to create some dummy socket from > kernel too though so we don't need any userspace daemon for this > testing mode. I don't really like that latter idea. It sounds too much like a hack to me. But then, I don't have enough phantasy right now ti imagine how an actual implementation would look like. To me, it is perfectly fine to run a simple, small utility in userspace even for testing. Regards, Harald >From 63920950f9498069993def78e178bde85c174e0c Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Wed, 15 Mar 2017 17:52:28 +0100 Subject: [PATCH] gtp: support SGSN-side tunnels The GTP-tunnel driver is explicitly GGSN-side as it searches for PDP contexts based on the incoming packets _destination_ address. For real-world use cases, this is sufficient, as the other side of a GTP tunnel is not in fact implemented by GTP, but by the protocol stacking of a mobile station / user equipment on the radio interface (like PDCP, SNDCP). However, if we want to simulate the mobile station, radio access network and SGSN (for example to test the GGSN side implementation), then we want to be identifying PDP contexts based on _source_ address. This patch adds a "role" attribute at GTP-link creation time to specify whether we behave like the GGSN or SGSN role of the tunnel; this attribute is then used to determine which part of the IP packet to use in determining the PDP context. Signed-off-by: Jonas Bonn Signed-off-by: Harald Welte diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 99d3df788ce8..9aef4217f6e1 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -71,6 +71,7 @@ struct gtp_dev { struct net_device *dev; + enum ifla_gtp_role role; unsigned int hash_size; struct hlist_head *tid_hash; struct hlist_head *addr_hash; @@ -149,8 +150,8 @@ static struct pdp_ctx *ipv4_pdp_find(struct gtp_dev *gtp, __be32 ms_addr) return NULL; } -static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx, - unsigned int hdrlen) +static bool gtp_check_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx, + unsigned int hdrlen, enum ifla_gtp_role role) { struct iphdr *iph; @@ -159,18 +160,21 @@ static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx, iph = (struct iphdr *)(skb->data + hdrlen); - return iph->saddr == pctx->ms_addr_ip4.s_addr; + if (role == GTP_ROLE_SGSN) + return iph->daddr == pctx->ms_addr_ip4.s_addr; + else + return iph->saddr == pctx->ms_addr_ip4.s_addr; } /* Check if the inner IP source address in this packet is assigned to any * existing mobile subscriber. */ -static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx, - unsigned int hdrlen) +static bool gtp_check_ms(struct sk_buff *skb, struct pdp_ctx *pctx, + unsigned int hdrlen, enum ifla_gtp_role role) { switch (ntohs(skb->protocol)) { case ETH_P_IP: - return gtp_check_src_ms_ipv4(skb, pctx, hdrlen); + return gtp_check_ms_ipv4(skb, pctx, hdrlen, role); } return false; } @@ -204,7 +208,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, goto out_rcu; } - if (!gtp_check_src_ms(skb, pctx, hdrlen)) { + if (!gtp_check_ms(skb, pctx, hdrlen, gtp->role)) { netdev_dbg(gtp->dev, "No PDP ctx for this MS\n"); ret = -1; goto out_rcu; @@ -261,7 +265,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb, goto out_rcu; } - if (!gtp_check_src_ms(skb, pctx, hdrlen)) { + if (!gtp_check_ms(skb, pctx, hdrlen, gtp->role)) { netdev_dbg(gtp->dev, "No PDP ctx for this MS\n"); ret = -1; goto out_rcu; @@ -490,7 +494,11 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, * Prepend PDP header with TEI/TID from PDP ctx. */ iph = ip_hdr(skb); - pctx = ipv4_pdp_find(gtp, iph->daddr); + if (gtp->role == GTP_ROLE_SGSN) + pctx = ipv4_pdp_find(gtp, iph->saddr); + else + pctx = ipv4_pdp_find(gtp, iph->daddr); + if (!pctx) { netdev_dbg(dev, "no PDP ctx found for %pI4, skip\n", &iph->daddr); @@ -665,12 +673,26 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, int hashsize, err, fd0, fd1; struct gtp_dev *gtp; struct gtp_net *gn; + unsigned int role; + + /* The default role is GGSN, and for backwards compatibility + * reasons, the lack of a IFLA_GTP_ROLE IE means that we're + * operating in GGSN role. */ + if (data[IFLA_GTP_ROLE]) { + role = nla_get_u32(data[IFLA_GTP_ROLE]); + if (role != GTP_ROLE_GGSN && + role != GTP_ROLE_SGSN) + return -EINVAL; + } else + role = GTP_ROLE_GGSN; if (!data[IFLA_GTP_FD0] || !data[IFLA_GTP_FD1]) return -EINVAL; gtp = netdev_priv(dev); + gtp->role = role; + fd0 = nla_get_u32(data[IFLA_GTP_FD0]); fd1 = nla_get_u32(data[IFLA_GTP_FD1]); @@ -722,6 +744,7 @@ static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = { [IFLA_GTP_FD0] = { .type = NLA_U32 }, [IFLA_GTP_FD1] = { .type = NLA_U32 }, [IFLA_GTP_PDP_HASHSIZE] = { .type = NLA_U32 }, + [IFLA_GTP_ROLE] = { .type = NLA_U32 }, }; static int gtp_validate(struct nlattr *tb[], struct nlattr *data[]) diff --git a/include/uapi/linux/gtp.h b/include/uapi/linux/gtp.h index 72a04a0e8cce..79037cca6b51 100644 --- a/include/uapi/linux/gtp.h +++ b/include/uapi/linux/gtp.h @@ -19,7 +19,7 @@ enum gtp_attrs { GTPA_LINK, GTPA_VERSION, GTPA_TID, /* for GTPv0 only */ - GTPA_SGSN_ADDRESS, + GTPA_SGSN_ADDRESS, /* Remote GSN, either SGSN or GGSN */ GTPA_MS_ADDRESS, GTPA_FLOW, GTPA_NET_NS_FD, diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 6b13e591abc9..de7bea223749 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -536,11 +536,18 @@ enum { #define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1) /* GTP section */ + +enum ifla_gtp_role { + GTP_ROLE_GGSN = 0, + GTP_ROLE_SGSN, +}; + enum { IFLA_GTP_UNSPEC, IFLA_GTP_FD0, IFLA_GTP_FD1, IFLA_GTP_PDP_HASHSIZE, + IFLA_GTP_ROLE, __IFLA_GTP_MAX, }; #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1) -- 2.11.0 -- - Harald Welte http://netfilter.org/ ============================================================================ "Fragmentation is like classful addressing -- an interesting early architectural error that shows how much experimentation was going on while IP was being designed." -- Paul Vixie From laforge at netfilter.org Wed Mar 15 19:27:47 2017 From: laforge at netfilter.org (Harald Welte) Date: Wed, 15 Mar 2017 20:27:47 +0100 Subject: [PATCH 1/1] gtp: support SGSN-side tunnels In-Reply-To: <20170315191038.nco2icu6e545rzlu@nataraja> References: <20170203091231.10142-1-jonas@southpole.se> <20170315163916.gins7lzzqhwkvfrc@nataraja> <20170315172348.GA30592@salvia> <20170315191038.nco2icu6e545rzlu@nataraja> Message-ID: <20170315192747.3oj2ro23qkbhe6iy@nataraja> On Wed, Mar 15, 2017 at 08:10:38PM +0100, Harald Welte wrote: > I've modified the patch slightly, see below (compile-tested, but not > otherwise tested yet). Basically rename the flags attribute to 'role', > expand the commit log and removed unrelated cosmetic changes. I also have a version against current net-next/master, in case anyone is interested.. >From 3274a3303d1ec997392a07a92666d57b13997658 Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Wed, 15 Mar 2017 20:24:28 +0100 Subject: [PATCH] gtp: support SGSN-side tunnels The GTP-tunnel driver is explicitly GGSN-side as it searches for PDP contexts based on the incoming packets _destination_ address. For real-world use cases, this is sufficient, as the other side of a GTP tunnel is not in fact implemented by GTP, but by the protocol stacking of a mobile station / user equipment on the radio interface (like PDCP, SNDCP). However, if we want to simulate the mobile station, radio access network and SGSN (for example to test the GGSN side implementation), then we want to be identifying PDP contexts based on _source_ address. This patch adds a "role" attribute at GTP-link creation time to specify whether we behave like the GGSN or SGSN role of the tunnel; this attribute is then used to determine which part of the IP packet to use in determining the PDP context. Signed-off-by: Jonas Bonn Signed-off-by: Harald Welte --- drivers/net/gtp.c | 46 +++++++++++++++++++++++++++++++++----------- include/uapi/linux/gtp.h | 2 +- include/uapi/linux/if_link.h | 7 +++++++ 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 3e1854f34420..3ab593b9be85 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -74,6 +74,7 @@ struct gtp_dev { struct net_device *dev; + enum ifla_gtp_role role; unsigned int hash_size; struct hlist_head *tid_hash; struct hlist_head *addr_hash; @@ -154,8 +155,8 @@ static struct pdp_ctx *ipv4_pdp_find(struct gtp_dev *gtp, __be32 ms_addr) return NULL; } -static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx, - unsigned int hdrlen) +static bool gtp_check_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx, + unsigned int hdrlen, enum ifla_gtp_role role) { struct iphdr *iph; @@ -164,27 +165,31 @@ static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx, iph = (struct iphdr *)(skb->data + hdrlen); - return iph->saddr == pctx->ms_addr_ip4.s_addr; + if (role == GTP_ROLE_SGSN) + return iph->daddr == pctx->ms_addr_ip4.s_addr; + else + return iph->saddr == pctx->ms_addr_ip4.s_addr; } /* Check if the inner IP source address in this packet is assigned to any * existing mobile subscriber. */ -static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx, - unsigned int hdrlen) +static bool gtp_check_ms(struct sk_buff *skb, struct pdp_ctx *pctx, + unsigned int hdrlen, enum ifla_gtp_role role) { switch (ntohs(skb->protocol)) { case ETH_P_IP: - return gtp_check_src_ms_ipv4(skb, pctx, hdrlen); + return gtp_check_ms_ipv4(skb, pctx, hdrlen, role); } return false; } -static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen) +static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, unsigned int hdrlen, + enum ifla_gtp_role role) { struct pcpu_sw_netstats *stats; - if (!gtp_check_src_ms(skb, pctx, hdrlen)) { + if (!gtp_check_ms(skb, pctx, hdrlen, role)) { netdev_dbg(pctx->dev, "No PDP ctx for this MS\n"); return 1; } @@ -239,7 +244,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) return 1; } - return gtp_rx(pctx, skb, hdrlen); + return gtp_rx(pctx, skb, hdrlen, gtp->role); } static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) @@ -281,7 +286,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) return 1; } - return gtp_rx(pctx, skb, hdrlen); + return gtp_rx(pctx, skb, hdrlen, gtp->role); } static void gtp_encap_destroy(struct sock *sk) @@ -481,7 +486,11 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, * Prepend PDP header with TEI/TID from PDP ctx. */ iph = ip_hdr(skb); - pctx = ipv4_pdp_find(gtp, iph->daddr); + if (gtp->role == GTP_ROLE_SGSN) + pctx = ipv4_pdp_find(gtp, iph->saddr); + else + pctx = ipv4_pdp_find(gtp, iph->daddr); + if (!pctx) { netdev_dbg(dev, "no PDP ctx found for %pI4, skip\n", &iph->daddr); @@ -631,13 +640,27 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, { struct gtp_dev *gtp; struct gtp_net *gn; + unsigned int role; int hashsize, err; + /* The default role is GGSN, and for backwards compatibility + * reasons, the lack of a IFLA_GTP_ROLE IE means that we're + * operating in GGSN role. */ + if (data[IFLA_GTP_ROLE]) { + role = nla_get_u32(data[IFLA_GTP_ROLE]); + if (role != GTP_ROLE_GGSN && + role != GTP_ROLE_SGSN) + return -EINVAL; + } else + role = GTP_ROLE_GGSN; + if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) return -EINVAL; gtp = netdev_priv(dev); + gtp->role = role; + err = gtp_encap_enable(gtp, data); if (err < 0) return err; @@ -685,6 +708,7 @@ static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = { [IFLA_GTP_FD0] = { .type = NLA_U32 }, [IFLA_GTP_FD1] = { .type = NLA_U32 }, [IFLA_GTP_PDP_HASHSIZE] = { .type = NLA_U32 }, + [IFLA_GTP_ROLE] = { .type = NLA_U32 }, }; static int gtp_validate(struct nlattr *tb[], struct nlattr *data[]) diff --git a/include/uapi/linux/gtp.h b/include/uapi/linux/gtp.h index 72a04a0e8cce..79037cca6b51 100644 --- a/include/uapi/linux/gtp.h +++ b/include/uapi/linux/gtp.h @@ -19,7 +19,7 @@ enum gtp_attrs { GTPA_LINK, GTPA_VERSION, GTPA_TID, /* for GTPv0 only */ - GTPA_SGSN_ADDRESS, + GTPA_SGSN_ADDRESS, /* Remote GSN, either SGSN or GGSN */ GTPA_MS_ADDRESS, GTPA_FLOW, GTPA_NET_NS_FD, diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 320fc1e747ee..8b405afb2376 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -538,11 +538,18 @@ enum { #define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1) /* GTP section */ + +enum ifla_gtp_role { + GTP_ROLE_GGSN = 0, + GTP_ROLE_SGSN, +}; + enum { IFLA_GTP_UNSPEC, IFLA_GTP_FD0, IFLA_GTP_FD1, IFLA_GTP_PDP_HASHSIZE, + IFLA_GTP_ROLE, __IFLA_GTP_MAX, }; #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1) -- 2.11.0 -- - Harald Welte http://netfilter.org/ ============================================================================ "Fragmentation is like classful addressing -- an interesting early architectural error that shows how much experimentation was going on while IP was being designed." -- Paul Vixie From pablo at netfilter.org Wed Mar 15 21:42:33 2017 From: pablo at netfilter.org (Pablo Neira Ayuso) Date: Wed, 15 Mar 2017 22:42:33 +0100 Subject: [PATCH 1/1] gtp: support SGSN-side tunnels In-Reply-To: <20170315191038.nco2icu6e545rzlu@nataraja> References: <20170203091231.10142-1-jonas@southpole.se> <20170315163916.gins7lzzqhwkvfrc@nataraja> <20170315172348.GA30592@salvia> <20170315191038.nco2icu6e545rzlu@nataraja> Message-ID: <20170315214233.GA1189@salvia> Hi Harald, On Wed, Mar 15, 2017 at 08:10:38PM +0100, Harald Welte wrote: > I've modified the patch slightly, see below (compile-tested, but not > otherwise tested yet). Basically rename the flags attribute to 'role', > expand the commit log and removed unrelated cosmetic changes. > > I've also prepared a corresponding change to libgtpnl into the > laforge/sgsn-rol branch, see > http://git.osmocom.org/libgtpnl/commit/?h=laforge/sgsn-role > > This is not yet tested in any way, but I'm planning to add some > associated support to the command line tools and then give it some > testing (both against the kernel GTP in GGSN mode, as well as an > independent userspace GTP implementation). Thanks Harald. > > It would be good if we provide a way to configure GTP via iproute2 for > > testing purposes. > > I don't really care about which tool is used, as long as it is easily > available [and FOSS, of course]. > > > We would need to create some dummy socket from > > kernel too though so we don't need any userspace daemon for this > > testing mode. > > I don't really like that latter idea. It sounds too much like a hack to > me. But then, I don't have enough phantasy right now ti imagine how an > actual implementation would look like. It's not that far away, we can just create the udp socket from kernelspace via udp_sock_create() in the test mode. So we don't need to pass the file descriptor from userspace. But not asking you to work on this, just an idea. > To me, it is perfectly fine to run a simple, small utility in userspace > even for testing. No problem. From laforge at gnumonks.org Fri Mar 17 20:17:19 2017 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 17 Mar 2017 21:17:19 +0100 Subject: git.osmocom.org cgit improvements Message-ID: <20170317201719.r3d6n3ab35wke4mu@nataraja> Hi all, today I've deployed some cgit improvements on https://git.osmocom.org/, in the hope that it makes this tool even more useful: 1) syntax highlighting of source code (requested by Hoernchen) The source code is now highlighted by pygments. I don't really understand why somebody would want to look at source code a lot in a browser, but well, it was as easy as to enable the existing pygments based filter plugin. 2) rendering of "about" page from README.md As you might have noticed, I've introduced a README.md in a number of repositoires, and cgit is now rendering an about page for every repository, e.g. at http://git.osmocom.org/libosmo-abis/about/ 3) gerrit change-ID hyperlink generation All gerrit Change-IDs in commit messages are now automatically converted to hyperlinks to the respective gerrit change, see e.g. the below example: http://git.osmocom.org/openbsc/commit/?id=6dd0fc685b7149f67a5fe17a5bce55c446aa563c Please note that this works for the "Change-Id" line of the actual change, but also for change-ids in the free text (e.g. "this depends on change-id ... in libosmocore") 4) Osmocom ticket/issue hyperlink generation Any Line that matches the "^((Relate|Close|Fixe)[ds]):" prefix is scanned for occurrences of "OS#(\d+)" which are then amended with hyperlinks to the respective issue on osmocom.org Please note the OS# prefix is mandatory, so things like "OS#1614, 1615" will not work, as can be seen at http://git.osmocom.org/osmo-pcu/commit/?id=0a8fae8d141c2cfa4387ffe9b35402d5b8cc85cd Please format your commit messages accordingly. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Sat Mar 18 15:09:31 2017 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sat, 18 Mar 2017 16:09:31 +0100 Subject: git.osmocom.org cgit improvements In-Reply-To: <20170317201719.r3d6n3ab35wke4mu@nataraja> References: <20170317201719.r3d6n3ab35wke4mu@nataraja> Message-ID: <20170318150931.GB3272@my.box> On Fri, Mar 17, 2017 at 09:17:19PM +0100, Harald Welte wrote: > 2) rendering of "about" page from README.md > > As you might have noticed, I've introduced a README.md in a number of > repositoires, and cgit is now rendering an about page for every > repository, e.g. at http://git.osmocom.org/libosmo-abis/about/ It seems like these need some follow-ups in the debian packaging instructions -- i.e. update to the new .md suffix or mark as installation (or ignore, but I guess rather installation) file. > 4) Osmocom ticket/issue hyperlink generation > > Any Line that matches the "^((Relate|Close|Fixe)[ds]):" prefix is > scanned for occurrences of "OS#(\d+)" which are then amended with > hyperlinks to the respective issue on osmocom.org Ah, so when OS#123 appears in the commit log's free text, it isn't linked? Can we just scan everything for "\"? All in all these are excellent improvements! Holger, what's the status of your promise, made one day in a chat, to make redmine catch the OS#123s? ~N -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Sun Mar 19 20:57:57 2017 From: holger at freyther.de (Holger Freyther) Date: Sun, 19 Mar 2017 21:57:57 +0100 Subject: git.osmocom.org cgit improvements In-Reply-To: <20170318150931.GB3272@my.box> References: <20170317201719.r3d6n3ab35wke4mu@nataraja> <20170318150931.GB3272@my.box> Message-ID: <9437479C-B7C9-4603-B01D-EC775130F164@freyther.de> > On 18 Mar 2017, at 16:09, Neels Hofmeyr wrote: > > Hi, > All in all these are excellent improvements! > Holger, what's the status of your promise, made one day in a chat, to make > redmine catch the OS#123s? lol, I love how we go from a private chat to this CC list. I have not looked at it but maybe this is something for an afternoon at Osmodevcon. It should be fairly simple with redmine. holger From nhofmeyr at sysmocom.de Mon Mar 20 04:36:31 2017 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 20 Mar 2017 05:36:31 +0100 Subject: git.osmocom.org cgit improvements In-Reply-To: <9437479C-B7C9-4603-B01D-EC775130F164@freyther.de> References: <20170317201719.r3d6n3ab35wke4mu@nataraja> <20170318150931.GB3272@my.box> <9437479C-B7C9-4603-B01D-EC775130F164@freyther.de> Message-ID: <20170320043631.GC12441@my.box> On Sun, Mar 19, 2017 at 09:57:57PM +0100, Holger Freyther wrote: > > Holger, what's the status of your promise, made one day in a chat, to make > > redmine catch the OS#123s? > > lol, I love how we go from a private chat to this CC list. Hey, if you love it that much, I can come up with plenty more private conversations between us I could Cc around... ;) In other words, sorry about disclosing. I kind of remembered it was a public commitment. And it doesn't need to stick, either, anyone could take a look if you're busy. ~N -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From arnaud.zanetti at free.fr Fri Mar 24 09:53:53 2017 From: arnaud.zanetti at free.fr (Arnaud ZANETTI) Date: Fri, 24 Mar 2017 10:53:53 +0100 Subject: [osmo-pcu 0.2.896-0a8f] testsuite: 4 failed Message-ID: Hi, building osmo-pcu on a raspberry Pi 3, I noticed a failure in make check: ## --------------------------------- ## ## osmo-pcu 0.2.896-0a8f test suite. ## ## --------------------------------- ## Regression tests 1: rlcmac ok 2: ts_alloc ok 3: tbf ok 4: bitcomp FAILED (testsuite.at:30) 5: edge ok 6: types ok 7: ms ok 8: llc ok 9: llist ok 10: codel ok 11: fn ok ## ------------- ## ## Test results. ## ## ------------- ## ERROR: All 11 tests were run, 1 failed unexpectedly. ## -------------------------- ## ## testsuite.log was created. ## ## -------------------------- ## The exact same test also fails on a raspberry Pi 2, with the same osmo-pcu and gcc versions but succeeds on an old Pentium4 Feel free to contact me if you need further informations. ----- Arnaud ZANETTI -------------- next part -------------- A non-text attachment was scrubbed... Name: testsuite.log Type: text/x-log Size: 39149 bytes Desc: not available URL: From jonas at southpole.se Fri Mar 24 14:19:18 2017 From: jonas at southpole.se (Jonas Bonn) Date: Fri, 24 Mar 2017 15:19:18 +0100 Subject: [PATCH 0/2] libgtpnl patches Message-ID: <20170324141920.27299-1-jonas@southpole.se> Here are two small patches for libgtpnl. They both apply to the laforge/sgsn-role branch (although patch 2/2 could be taken separately into the main branch, too). Patch 1/2 is a small fixup for a netlink parameter rename in a kernel patch. Patch 2/2 is a trivial include file addition to prevent some warnings. Jonas Bonn (2): Rename netlink attribute Provide declaration for struct in_addr include/libgtpnl/gtp.h | 1 + include/linux/gtp.h | 2 +- src/gtp-genl.c | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) -- 2.9.3 From jonas at southpole.se Fri Mar 24 14:19:20 2017 From: jonas at southpole.se (Jonas Bonn) Date: Fri, 24 Mar 2017 15:19:20 +0100 Subject: [PATCH 2/2] Provide declaration for struct in_addr In-Reply-To: <20170324141920.27299-1-jonas@southpole.se> References: <20170324141920.27299-1-jonas@southpole.se> Message-ID: <20170324141920.27299-3-jonas@southpole.se> --- include/libgtpnl/gtp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/libgtpnl/gtp.h b/include/libgtpnl/gtp.h index 521339d..a6cd8e2 100644 --- a/include/libgtpnl/gtp.h +++ b/include/libgtpnl/gtp.h @@ -2,6 +2,7 @@ #define _LIBGTP_H_ #include +#include struct gtp_tunnel; -- 2.9.3 From jonas at southpole.se Fri Mar 24 14:19:19 2017 From: jonas at southpole.se (Jonas Bonn) Date: Fri, 24 Mar 2017 15:19:19 +0100 Subject: [PATCH 1/2] Rename netlink attribute In-Reply-To: <20170324141920.27299-1-jonas@southpole.se> References: <20170324141920.27299-1-jonas@southpole.se> Message-ID: <20170324141920.27299-2-jonas@southpole.se> This aligns with a kernel patch that renames the netlink parameter to emphasize that it refers to the remote peer which may be either a GGSN or an SGSN. The upstream kernel include file retains the legacy name as a define but we don't need that in our internal library since we are no longer using it anywhere. --- include/linux/gtp.h | 2 +- src/gtp-genl.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/gtp.h b/include/linux/gtp.h index ca1054d..c525cb3 100644 --- a/include/linux/gtp.h +++ b/include/linux/gtp.h @@ -19,7 +19,7 @@ enum gtp_attrs { GTPA_LINK, GTPA_VERSION, GTPA_TID, /* for GTPv0 only */ - GTPA_SGSN_ADDRESS, + GTPA_PEER_ADDRESS, GTPA_MS_ADDRESS, GTPA_FLOW, GTPA_NET_NS_FD, diff --git a/src/gtp-genl.c b/src/gtp-genl.c index 24a640d..1e48020 100644 --- a/src/gtp-genl.c +++ b/src/gtp-genl.c @@ -48,7 +48,7 @@ static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t) if (t->ifns >= 0) mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns); mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx); - mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, t->sgsn_addr.s_addr); + mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, t->sgsn_addr.s_addr); mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr); if (t->gtp_version == GTP_V0) { mnl_attr_put_u64(nlh, GTPA_TID, t->u.v0.tid); @@ -131,7 +131,7 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data) break; case GTPA_O_TEI: case GTPA_I_TEI: - case GTPA_SGSN_ADDRESS: + case GTPA_PEER_ADDRESS: case GTPA_MS_ADDRESS: case GTPA_VERSION: if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { @@ -160,9 +160,9 @@ static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data) pdp.u.v1.i_tei = mnl_attr_get_u32(tb[GTPA_I_TEI]); if (tb[GTPA_O_TEI]) pdp.u.v1.o_tei = mnl_attr_get_u32(tb[GTPA_O_TEI]); - if (tb[GTPA_SGSN_ADDRESS]) { + if (tb[GTPA_PEER_ADDRESS]) { pdp.sgsn_addr.s_addr = - mnl_attr_get_u32(tb[GTPA_SGSN_ADDRESS]); + mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]); } if (tb[GTPA_MS_ADDRESS]) { pdp.ms_addr.s_addr = mnl_attr_get_u32(tb[GTPA_MS_ADDRESS]); -- 2.9.3 From laforge at gnumonks.org Fri Mar 24 15:09:43 2017 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 24 Mar 2017 16:09:43 +0100 Subject: [PATCH 0/2] libgtpnl patches In-Reply-To: <20170324141920.27299-1-jonas@southpole.se> References: <20170324141920.27299-1-jonas@southpole.se> Message-ID: <20170324150943.5256gufi34eu5r5t@nataraja> Hi Jonas, On Fri, Mar 24, 2017 at 03:19:18PM +0100, Jonas Bonn wrote: > Patch 1/2 is a small fixup for a netlink parameter rename in a kernel patch. > Patch 2/2 is a trivial include file addition to prevent some warnings. thanks, both merged. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Sun Mar 26 22:34:11 2017 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 27 Mar 2017 00:34:11 +0200 Subject: [osmo-pcu 0.2.896-0a8f] testsuite: 4 failed In-Reply-To: References: Message-ID: <20170326223411.GA2441@my.box> On Fri, Mar 24, 2017 at 10:53:53AM +0100, Arnaud ZANETTI wrote: > 4: bitcomp FAILED (testsuite.at:30) > 4. testsuite.at:26: testing bitcomp ... > ./testsuite.at:30: $OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest > --- experr 2017-03-24 10:43:11.086019127 +0100 > +++ /home/pi/Src/osmo/src/osmo-pcu/tests/testsuite.dir/at-groups/4/stderr 2017-03-24 10:43:11.096019097 +0100 > @@ -11,9 +11,9 @@ > Run_length = 19 > Run_length = 32 > > -expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db > +expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff c0 > expected len = 194 > -decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db > +decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff c0 > decoded len = 194 Arnaud, many thanks for submitting your report! I took a look, and it actually is an amazingly stupid bug in the test itself. In fact 0xc0 is the correct expected result, which our decoding routines also actually return, but the author of the test has put two osmo_hexdump() calls into the same log line. Since osmo_hexdump() uses an internal static buffer, that can't work: one of the two hexdumps wins, so that both dumped strings are the same. m( On our "usual" systems, the expected hexdump wins and it prints them both as the expected value. On the pi, the actually decoded hexdump wins, and it prints both "expected" and "decoded" data as what the decoding routine returns. In other words, the test never before printed expected vs. decoded results, and the author has never properly checked the stdout / stderr results. The test does check expected results, but not the remaining bits after the decoded data. In my/our review, we oversaw the double osmo_hexdump() and a bunch of other issues. Looking into this triggered a whole series of fixes, more explanations in the commit logs: https://gerrit.osmocom.org/#/q/topic:bitcomp_test The last one also uncovers a test marked "invalid" which seems to be valid, or fails to be detected as invalid. I don't have a fix for that, would be good if someone else could look into that. ~N -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From ouyangj at fb.com Mon Mar 27 05:16:10 2017 From: ouyangj at fb.com (Jiannan Ouyang) Date: Mon, 27 Mar 2017 05:16:10 +0000 Subject: allow gtp tunnel updating in libgtpnl: gtp_add_tunnel() In-Reply-To: <5B2C1121-EACB-44CE-83A3-4FD70FDB7368@fb.com> References: <5B2C1121-EACB-44CE-83A3-4FD70FDB7368@fb.com> Message-ID: <06D4128F-F296-4A99-B375-9C962DFC5A0E@fb.com> Hi All, In current OAI implementation, we found that there are cases SPGW is out-of-sync with MME, because of the delete_session_request is not received by the SPGW because of some errors, however MME has cleared the state of that session. Then when the UE re-attaches, a new create_session_request is sent to SPGW; and because we try to allocate the same IP for the same IMSI (local change), the SPGW will result out in trying to update an existing GTP tunnel. According to http://lxr.free-electrons.com/source/drivers/net/gtp.c#L937 and https://github.com/RoadRunnr/osmo-ggsn/blob/master/libgtnl/src/gtp-genl.c#L73, the NLM_F_EXCL flag is used to prevent updating an existing tunnel. I?m is wondering what is the reason of preventing updating? While we are actively investigating sending delete_session_request properly, as temporary workaround, I?m thinking to recovery from the out-of-sync problem, we can allow the new GTP tunnel to overwrite the old one in libgtpnl. Your suggestions are welcomed. Thanks. Regards, -Jiannan -------------- next part -------------- An HTML attachment was scrubbed... URL: From aschultz at tpip.net Mon Mar 27 08:30:32 2017 From: aschultz at tpip.net (Andreas Schultz) Date: Mon, 27 Mar 2017 10:30:32 +0200 (CEST) Subject: allow gtp tunnel updating in libgtpnl: gtp_add_tunnel() In-Reply-To: <06D4128F-F296-4A99-B375-9C962DFC5A0E@fb.com> References: <5B2C1121-EACB-44CE-83A3-4FD70FDB7368@fb.com> <06D4128F-F296-4A99-B375-9C962DFC5A0E@fb.com> Message-ID: <1665555025.640587.1490603432398.JavaMail.zimbra@tpip.net> Hi Jiannan, ----- On Mar 27, 2017, at 7:16 AM, Jiannan Ouyang wrote: > Hi All, > In current OAI implementation, we found that there are cases SPGW is out-of-sync > with MME, because of the delete_session_request is not received by the SPGW > because of some errors, however MME has cleared the state of that session. Then > when the UE re-attaches, a new create_session_request is sent to SPGW; and > because we try to allocate the same IP for the same IMSI (local change), the > SPGW will result out in trying to update an existing GTP tunnel. > According to [ http://lxr.free-electrons.com/source/drivers/net/gtp.c#L937 | > http://lxr.free-electrons.com/source/drivers/net/gtp.c#L937 ] and [ > https://github.com/RoadRunnr/osmo-ggsn/blob/master/libgtnl/src/gtp-genl.c#L73 | > https://github.com/RoadRunnr/osmo-ggsn/blob/master/libgtnl/src/gtp-genl.c#L73 ] > , the NLM_F_EXCL flag is used to prevent updating an existing tunnel. I?m is > wondering what is the reason of preventing updating? The correct repository for libgtnl is: http://git.osmocom.org/libgtpnl/, my github tree of osmo-ggsn is outdated and shouldn't be used. > While we are actively investigating sending delete_session_request properly, as > temporary workaround, I?m thinking to recovery from the out-of-sync problem, we > can allow the new GTP tunnel to overwrite the old one in libgtpnl. Your > suggestions are welcomed. Thanks. It should be possible to update an existing PDP context as long as you don't change any of the hash keys. That would be GTP version, GTP socket, ms_addr, and i_tei. The validation of those values for updating is a bit weak in the kernel. Currently, it would to possible change any of the hash keys without the hash being updated. Adding gtp_update_tunnel to libgtpnl should be simple (but beware of the hash key changes). A gtp_update_tunnel that supports changing any the hash keys would have to set the NLM_F_REPLACE flag. That is currently not supported by the kernel implementation and libgtnl is not setting that flag. I found an old, untested, and most likely incomplete version of an update pdp implementation for the kernel in my repository at https://github.com/RoadRunnr/osmo-ggsn/commit/398199135a6009dcbd421d7a330a5af2d36dda8d You are welcome to forward port, fix, test, and submit that to the kernel. Regards Andreas > Regards, > -Jiannan -------------- next part -------------- An HTML attachment was scrubbed... URL: From laforge at gnumonks.org Mon Mar 27 08:33:00 2017 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 27 Mar 2017 10:33:00 +0200 Subject: allow gtp tunnel updating in libgtpnl: gtp_add_tunnel() In-Reply-To: <06D4128F-F296-4A99-B375-9C962DFC5A0E@fb.com> References: <5B2C1121-EACB-44CE-83A3-4FD70FDB7368@fb.com> <06D4128F-F296-4A99-B375-9C962DFC5A0E@fb.com> Message-ID: <20170327083300.lyp6eqykp6umzmtr@nataraja> Hi Jiannan, On Mon, Mar 27, 2017 at 05:16:10AM +0000, Jiannan Ouyang wrote: > According to > http://lxr.free-electrons.com/source/drivers/net/gtp.c#L937 and > https://github.com/RoadRunnr/osmo-ggsn/blob/master/libgtnl/src/gtp-genl.c#L73, > the NLM_F_EXCL flag is used to prevent updating an existing tunnel. > I?m is wondering what is the reason of preventing updating? As a minor side note: Please note the authoritative source for libgtpnl is at git.osmocom.org http://git.osmocom.org/libgtpnl/tree/src/gtp-genl.c To me it's quite obvious that a function called "gtp_add_tunnel()" should only add a new tunnel and hence I think the current behavior is correct. However, I guess you could simply submit a patch with "gtp_update_tunnel()" or "gtp_modify_tunnel()" which can modify an existing tunnel. The latter might probably be required anyway in other cases? -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Mon Mar 27 13:14:10 2017 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 27 Mar 2017 15:14:10 +0200 Subject: Updates on Osmocom Conference 2017 Message-ID: <20170327131410.rqtqkrqxqz2lwmwa@nataraja> OsmoCon 2017 updates There are some updates related to OsmoCon2017, the first Osmocom Conference, held on April 21st, 2017 in Berlin, Germany. See http://osmocom.org/news/68 for the web version of this announcement. == Summary == Summary (for those too busy to read the full post): * Schedule of talks has been released http://osmocom.org/projects/osmo-dev-con/wiki/OsmoCon2017#Schedule * Travel Grants available for participants who are otherwise unable to travel to Berlin: http://osmocom.org/projects/osmo-dev-con/wiki/OsmoCon2017_TravelGrants * Social Event details available, including menu: http://osmocom.org/projects/osmo-dev-con/wiki/OsmoCon2017_SocialEvent * April 21st is approaching fast, make sure you get your Ticket in time. Limited number of seats available http://shop.sysmocom.de/products/ticket-for-osmocon-2017 == Details == === Schedule has been released === The list of talks with their abstracts has been on the website for quite some time, but now we actually have put together a schedule based on those talks. Please see http://osmocom.org/projects/osmo-dev-con/wiki/OsmoCon2017#Schedule for the schedule. As you can see, the day is fully packed with talks about Osmocom cellular infrastructure projects. We had to cut some talk slots short (30min instead of 45min), but I'm confident that it is good to cover a wider range of topics, while at the same time avoiding fragmenting the audience with multiple tracks. === Travel Grants === We are happy to announce that we have received donations to permit for providing travel grants! This means that any attendee who is otherwise not able to cover their travel to OsmoCon 2017 (e.g. because their interest in Osmocom is not related to their work, or because their employer doesn't pay the travel expenses) can now apply for such a travel grant. For more details see http://osmocom.org/projects/osmo-dev-con/wiki/OsmoCon2017_TravelGrants and/or constact osmocon2017 at sysmocom.de. === Social Event === Tech Talks are nice and fine, but what many people enjoy even more at conferences is the informal networking combined with good food. For this, we have the social event at night, which is open to all attendees. See more details about it at http://osmocom.org/projects/osmo-dev-con/wiki/OsmoCon2017_SocialEvent -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From ouyangj at fb.com Tue Mar 28 22:13:18 2017 From: ouyangj at fb.com (Jiannan Ouyang) Date: Tue, 28 Mar 2017 22:13:18 +0000 Subject: allow gtp tunnel updating in libgtpnl: gtp_add_tunnel() In-Reply-To: <20170327083300.lyp6eqykp6umzmtr@nataraja> References: <5B2C1121-EACB-44CE-83A3-4FD70FDB7368@fb.com> <06D4128F-F296-4A99-B375-9C962DFC5A0E@fb.com> <20170327083300.lyp6eqykp6umzmtr@nataraja> Message-ID: <62690611-4298-4EF9-8E38-AB2D222AEF6D@fb.com> Hi Harald, On 3/27/17, 1:33 AM, "Harald Welte" wrote: > As a minor side note: Please note the authoritative source for libgtpnl > is at git.osmocom.org https://urldefense.proofpoint.com/v2/url?u=http-3A__git.osmocom.org_libgtpnl_tree_src_gtp-2Dgenl.c&d=DwIDaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=DlEiPn-jT33DcPoRArwOWA&m=jcvVBVPs-> 2A84uHXjAGh8m2cXdeZHZX8UmaRo4fZvXY&s=ZqNrEp-B5LpzCqShvyFFtEFsBy-Bnzm9SGhEFjbXysY&e= Got it, thanks! > To me it's quite obvious that a function called "gtp_add_tunnel()" > should only add a new tunnel and hence I think the current behavior is > correct. > However, I guess you could simply submit a patch with > "gtp_update_tunnel()" or "gtp_modify_tunnel()" which can modify an > existing tunnel. The latter might probably be required anyway in other > cases? Yeah, I agree current behavior is correct, though the ?right fix? would require changes to the kernel module, libgtpnl, and OAI. If we are going down that path, I would like to first have a more comprehensive plan on what features we want, and what changes are needed. Once we have that, I can work with the community on the implementation. Thank you! Regards, -Jiannan From ouyangj at fb.com Tue Mar 28 22:00:32 2017 From: ouyangj at fb.com (Jiannan Ouyang) Date: Tue, 28 Mar 2017 22:00:32 +0000 Subject: allow gtp tunnel updating in libgtpnl: gtp_add_tunnel() In-Reply-To: <1665555025.640587.1490603432398.JavaMail.zimbra@tpip.net> References: <5B2C1121-EACB-44CE-83A3-4FD70FDB7368@fb.com> <06D4128F-F296-4A99-B375-9C962DFC5A0E@fb.com> <1665555025.640587.1490603432398.JavaMail.zimbra@tpip.net> Message-ID: <62AC8117-26D1-4297-9524-3DF1FFED860E@fb.com> Hi Andreas, From: Andreas Schultz Date: Monday, March 27, 2017 at 1:30 AM To: Jiannan Ouyang Cc: osmocom-net-gprs , Anoop Singh Tomar , Amar Padmanabhan Subject: Re: allow gtp tunnel updating in libgtpnl: gtp_add_tunnel() > The correct repository for libgtnl is: http://git.osmocom.org/libgtpnl/, my github tree of osmo-ggsn is outdated and shouldn't > be used. Thanks for letting me know. > A gtp_update_tunnel that supports changing any the hash keys would have to set the NLM_F_REPLACE flag. > That is currently not supported by the kernel implementation and libgtnl is not setting that flag. > I found an old, untested, and most likely incomplete version of an update pdp implementation for the > kernel in my repository at https://github.com/RoadRunnr/osmo-ggsn/commit/398199135a6009dcbd421d7a330a5af2d36dda8d > You are welcome to forward port, fix, test, and submit that to the kernel. This reference implementation is very helpful, thank you! Regards, -Jiannan -------------- next part -------------- An HTML attachment was scrubbed... URL: