All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v4 0/7] gtp: misc improvements
@ 2017-02-21 10:18 Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 1/7] gtp: switch from struct socket to struct sock for the GTP sockets Andreas Schultz
                   ` (8 more replies)
  0 siblings, 9 replies; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 10:18 UTC (permalink / raw)
  To: Pablo Neira; +Cc: netdev, Harald Welte, osmocom-net-gprs

Hi Pablo,

This is v4 of the GTP improvements. 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
overlaping IP addresse spaces attached to the same GTP-U entity (needed for
multi APN support, comming 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.

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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH net-next v4 1/7] gtp: switch from struct socket to struct sock for the GTP sockets
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
@ 2017-02-21 10:18 ` Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 2/7] gtp: make GTP sockets in gtp_newlink optional Andreas Schultz
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 10:18 UTC (permalink / raw)
  To: Pablo Neira; +Cc: netdev, Harald Welte, osmocom-net-gprs

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 <aschultz@tpip.net>
---
 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 bda0c64..a8ce8c7 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

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next v4 2/7] gtp: make GTP sockets in gtp_newlink optional
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 1/7] gtp: switch from struct socket to struct sock for the GTP sockets Andreas Schultz
@ 2017-02-21 10:18 ` Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 3/7] gtp: merge gtp_get_net and gtp_genl_find_dev Andreas Schultz
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 10:18 UTC (permalink / raw)
  To: Pablo Neira; +Cc: netdev, Harald Welte, osmocom-net-gprs

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 <aschultz@tpip.net>
---
 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 a8ce8c7..96bb89b 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

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next v4 3/7] gtp: merge gtp_get_net and gtp_genl_find_dev
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 1/7] gtp: switch from struct socket to struct sock for the GTP sockets Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 2/7] gtp: make GTP sockets in gtp_newlink optional Andreas Schultz
@ 2017-02-21 10:18 ` Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path Andreas Schultz
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 10:18 UTC (permalink / raw)
  To: Pablo Neira; +Cc: netdev, Harald Welte, osmocom-net-gprs

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 <aschultz@tpip.net>
---
 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 96bb89b..961fb3c 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 == &gtp_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

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
                   ` (2 preceding siblings ...)
  2017-02-21 10:18 ` [PATCH net-next v4 3/7] gtp: merge gtp_get_net and gtp_genl_find_dev Andreas Schultz
@ 2017-02-21 10:18 ` Andreas Schultz
  2017-02-22 17:41   ` Tom Herbert
  2017-02-21 10:18 ` [PATCH net-next v4 5/7] gtp: unify genl_find_pdp and prepare for per socket lookup Andreas Schultz
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 10:18 UTC (permalink / raw)
  To: Pablo Neira; +Cc: netdev, Harald Welte, osmocom-net-gprs

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 <aschultz@tpip.net>
---
 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 961fb3c..fc0fff5 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

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next v4 5/7] gtp: unify genl_find_pdp and prepare for per socket lookup
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
                   ` (3 preceding siblings ...)
  2017-02-21 10:18 ` [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path Andreas Schultz
@ 2017-02-21 10:18 ` Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 6/7] gtp: consolidate pdp context destruction into helper Andreas Schultz
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 10:18 UTC (permalink / raw)
  To: Pablo Neira; +Cc: netdev, Harald Welte, osmocom-net-gprs

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 <aschultz@tpip.net>
---
 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 fc0fff5..f529d1e 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

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next v4 6/7] gtp: consolidate pdp context destruction into helper
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
                   ` (4 preceding siblings ...)
  2017-02-21 10:18 ` [PATCH net-next v4 5/7] gtp: unify genl_find_pdp and prepare for per socket lookup Andreas Schultz
@ 2017-02-21 10:18 ` Andreas Schultz
  2017-02-21 10:18 ` [PATCH net-next v4 7/7] gtp: add socket to pdp context Andreas Schultz
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 10:18 UTC (permalink / raw)
  To: Pablo Neira; +Cc: netdev, Harald Welte, osmocom-net-gprs

Consolidate duplicate code into helper.

Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
 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 f529d1e..b6aae68 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, &gtp->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, &gtp->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

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next v4 7/7] gtp: add socket to pdp context
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
                   ` (5 preceding siblings ...)
  2017-02-21 10:18 ` [PATCH net-next v4 6/7] gtp: consolidate pdp context destruction into helper Andreas Schultz
@ 2017-02-21 10:18 ` Andreas Schultz
  2017-02-21 11:13 ` [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
  2017-02-21 18:15 ` David Miller
  8 siblings, 0 replies; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 10:18 UTC (permalink / raw)
  To: Pablo Neira; +Cc: netdev, Harald Welte, osmocom-net-gprs

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 <aschultz@tpip.net>
---
 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 b6aae68..ea868de 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

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next v4 0/7] gtp: misc improvements
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
                   ` (6 preceding siblings ...)
  2017-02-21 10:18 ` [PATCH net-next v4 7/7] gtp: add socket to pdp context Andreas Schultz
@ 2017-02-21 11:13 ` Andreas Schultz
  2017-02-21 18:15 ` David Miller
  8 siblings, 0 replies; 16+ messages in thread
From: Andreas Schultz @ 2017-02-21 11:13 UTC (permalink / raw)
  To: osmocom-net-gprs; +Cc: laforge, pablo, netdev

Hi,

In case anyone want's to have a look at the changes that I'm working
on for follow up series can find them at:

  https://github.com/RoadRunnr/net-next/tree/gtp

Regards
Andreas

----- On Feb 21, 2017, at 11:18 AM, Andreas Schultz aschultz@tpip.net wrote:

> Hi Pablo,
> 
> This is v4 of the GTP improvements. 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
> overlaping IP addresse spaces attached to the same GTP-U entity (needed for
> multi APN support, comming 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.
> 
> 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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next v4 0/7] gtp: misc improvements
  2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
                   ` (7 preceding siblings ...)
  2017-02-21 11:13 ` [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
@ 2017-02-21 18:15 ` David Miller
  8 siblings, 0 replies; 16+ messages in thread
From: David Miller @ 2017-02-21 18:15 UTC (permalink / raw)
  To: aschultz; +Cc: pablo, netdev, laforge, osmocom-net-gprs


The net-next tree is closed at this time, you'll need to resubmit this series
when the net-next tree opens back up after the merge window.

Thanks.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path
  2017-02-21 10:18 ` [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path Andreas Schultz
@ 2017-02-22 17:41   ` Tom Herbert
  2017-02-23  9:19     ` Andreas Schultz
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Herbert @ 2017-02-22 17:41 UTC (permalink / raw)
  To: Andreas Schultz
  Cc: Pablo Neira, Linux Kernel Network Developers, Harald Welte,
	osmocom-net-gprs

On Tue, Feb 21, 2017 at 2:18 AM, Andreas Schultz <aschultz@tpip.net> wrote:
> 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.
>
Andeas,

How are these GTP kernel patches being tested? Is it possible to
create some sort of GTP network device that separates out just the
datapath for development in the same way that VXLAN did this?

Tom

> Signed-off-by: Andreas Schultz <aschultz@tpip.net>
> ---
>  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 961fb3c..fc0fff5 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
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path
  2017-02-22 17:41   ` Tom Herbert
@ 2017-02-23  9:19     ` Andreas Schultz
  2017-02-23 16:28       ` Tom Herbert
  0 siblings, 1 reply; 16+ messages in thread
From: Andreas Schultz @ 2017-02-23  9:19 UTC (permalink / raw)
  To: Tom Herbert; +Cc: pablo, netdev, laforge, osmocom-net-gprs, timo lindhorst

Hi Tom,

----- On Feb 22, 2017, at 6:41 PM, Tom Herbert tom@herbertland.com wrote:

> On Tue, Feb 21, 2017 at 2:18 AM, Andreas Schultz <aschultz@tpip.net> wrote:
>> 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.
>>
> Andeas,
> 
> How are these GTP kernel patches being tested?

We rn each version in a test setup with a ePDG and a SGW that
connects to a full GGSN/P-GW instance (based on erGW).
We also run performance test (less often) with a commercial
test software.

> Is it possible to > create some sort of GTP network device
> that separates out just the datapath for development in the
> same way that VXLAN did this?

We had this discussion about another patch:
(http://marc.info/?l=linux-netdev&m=148611438811696&w=2)

Currently the kernel module only supports the GGSN/P-GW side
of the GTP tunnel. This is because we check the UE IP address
in the GTP socket and use the destination IP in the network
interface to find the PDP context.

For a deployment in a real EPC, doing it the other way makes no
sense with the current code. However for a test setup it makes
perfect sense (either to use it as a driver to test other GTP
nodes or to test out own implementation).

So, I hope that we can integrate this soonish.

libgtpnl contains two tools that be used for testing. gtp-link
creates a network device and GTP sockets and keeps them alive.
gtp-tunnel can then be used add PDP context to that. The only
missing part for a bidirectional test setup is the above
mentioned patch with the direction flag and support for that
in the libgtpnl tools.

Adding static tunnel support into the kernel module in any form
makes IMHO no sense. GTP as defined by 3GPP always need a control
instance and there are much better options for static tunnel
encapsulations.

Andreas

> 
> Tom
> 
>> Signed-off-by: Andreas Schultz <aschultz@tpip.net>
>> ---
>>  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 961fb3c..fc0fff5 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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path
  2017-02-23  9:19     ` Andreas Schultz
@ 2017-02-23 16:28       ` Tom Herbert
  2017-02-23 16:46         ` Harald Welte
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Herbert @ 2017-02-23 16:28 UTC (permalink / raw)
  To: Andreas Schultz; +Cc: pablo, netdev, laforge, osmocom-net-gprs, timo lindhorst

On Thu, Feb 23, 2017 at 1:19 AM, Andreas Schultz <aschultz@tpip.net> wrote:
> Hi Tom,
>
> ----- On Feb 22, 2017, at 6:41 PM, Tom Herbert tom@herbertland.com wrote:
>
>> On Tue, Feb 21, 2017 at 2:18 AM, Andreas Schultz <aschultz@tpip.net> wrote:
>>> 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.
>>>
>> Andeas,
>>
>> How are these GTP kernel patches being tested?
>
> We rn each version in a test setup with a ePDG and a SGW that
> connects to a full GGSN/P-GW instance (based on erGW).
> We also run performance test (less often) with a commercial
> test software.
>
>> Is it possible to > create some sort of GTP network device
>> that separates out just the datapath for development in the
>> same way that VXLAN did this?
>
> We had this discussion about another patch:
> (http://marc.info/?l=linux-netdev&m=148611438811696&w=2)
>
> Currently the kernel module only supports the GGSN/P-GW side
> of the GTP tunnel. This is because we check the UE IP address
> in the GTP socket and use the destination IP in the network
> interface to find the PDP context.
>
> For a deployment in a real EPC, doing it the other way makes no
> sense with the current code. However for a test setup it makes
> perfect sense (either to use it as a driver to test other GTP
> nodes or to test out own implementation).
>
> So, I hope that we can integrate this soonish.
>
> libgtpnl contains two tools that be used for testing. gtp-link
> creates a network device and GTP sockets and keeps them alive.
> gtp-tunnel can then be used add PDP context to that. The only
> missing part for a bidirectional test setup is the above
> mentioned patch with the direction flag and support for that
> in the libgtpnl tools.
>
If there is a way for us to test this without setting up a full mobile
network please provide details on how to do that in the commit log.

> Adding static tunnel support into the kernel module in any form
> makes IMHO no sense. GTP as defined by 3GPP always need a control
> instance and there are much better options for static tunnel
> encapsulations.
>
That misses the point. From the kernel point of view GTP is just
another encapsulation protocol and we now have a lot of experience
with those. The problem is when you post patches to improve it or fix
issues, if there is no practical way to perform independent  analysis
or investigation. This makes GTP no different than a proprietary
protocol to us and that severely limits the value of trying to work
with the community.

Tom

> Andreas
>
>>
>> Tom
>>
>>> Signed-off-by: Andreas Schultz <aschultz@tpip.net>
>>> ---
>>>  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 961fb3c..fc0fff5 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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path
  2017-02-23 16:28       ` Tom Herbert
@ 2017-02-23 16:46         ` Harald Welte
  2017-02-23 18:07           ` Tom Herbert
  0 siblings, 1 reply; 16+ messages in thread
From: Harald Welte @ 2017-02-23 16:46 UTC (permalink / raw)
  To: Tom Herbert
  Cc: Andreas Schultz, pablo, netdev, osmocom-net-gprs, timo lindhorst

Hi Tom,

On Thu, Feb 23, 2017 at 08:28:47AM -0800, Tom Herbert wrote:

> If there is a way for us to test this without setting up a full mobile
> network please provide details on how to do that in the commit log.

There are different ways how to do this.  With the existing in-kernel
code (that lacks the "SGSN role" patch which would be for testing only),
you can e.g. use two relatively small C-language programs from the
openggnsn package [http://git.osmocom.org/openggsn/]:

* OpenGGSN with support for libgtpnl and the kernel GTP-U module
* sgsnemu (included in openggsn source tree) which implements a minimal
  SGSN-side of the tunnel.  It will
  * perform the GTP-C signaling required with OpenGGSN (which in turn
    will then instruct the kernel to open a  tunnel via the netlink
    interface).
  * start a tun/tap device for the "mobile station end" of the tunnel
    perform en/decapsulation of data between that tun/tap device and GTP
    in userspace

The wiki at https://osmocom.org/projects/openggsn/wiki/OpenGGSN contains
step-by-step instructions how to build and configure OpenGGSN with
support for kernel GTP-U. It's nothing more than autotools based
compile+install of libgtpnl followed by "./configure --enable-gtp-linux"
and "make" for OpenGGSN 

What is not described on the above page is how to use sgsnemu to
simulate the SGSN side, as within Osmocom we typically run the open
source OsmoSGSN (a more "real" SGSN).

So using two small binaries that can be compiled without much external
dependencies (and very few lines of configuration), it is possible to do
some functional testing of the kernel GTP module.  For performance
testing this of course won't work, as sgsnemu is running entirely in
userspace.

For performance testing, you would need a SGSN-side implementation of
GTP-U that performs equally well or better than the GGSN-side
implementation in the kernel.  One option is the patch that has recently
been submitted to netdev and which is under discussion.  However, then
you simply test one implementation against itself, which provides no
interoperability guarantees with other implementations, and thus also
limited in different regards.

> > Adding static tunnel support into the kernel module in any form
> > makes IMHO no sense. GTP as defined by 3GPP always need a control
> > instance and there are much better options for static tunnel
> > encapsulations.
> >
> That misses the point. From the kernel point of view GTP is just
> another encapsulation protocol and we now have a lot of experience
> with those. The problem is when you post patches to improve it or fix
> issues, if there is no practical way to perform independent  analysis
> or investigation. This makes GTP no different than a proprietary
> protocol to us and that severely limits the value of trying to work
> with the community.

I wholeheartedly agree.  That's one of the reasons why I recently posted
a RFC about what to do for (regression and other) testing of the kernel
GTP-U module.

I'll try to cook up some instructions extending
https://osmocom.org/projects/openggsn/wiki/OpenGGSN to cover also
sgsnemu for a basic use case of establishing one single tunnel.  That's
of course like a manual "HOWTO" and not yet anything that can be tested
automatically.

Regards,
	Harald

-- 
- Harald Welte <laforge@gnumonks.org>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path
  2017-02-23 16:46         ` Harald Welte
@ 2017-02-23 18:07           ` Tom Herbert
  2017-02-23 21:17             ` Harald Welte
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Herbert @ 2017-02-23 18:07 UTC (permalink / raw)
  To: Harald Welte
  Cc: Andreas Schultz, pablo, netdev, osmocom-net-gprs, timo lindhorst

On Thu, Feb 23, 2017 at 8:46 AM, Harald Welte <laforge@gnumonks.org> wrote:
> Hi Tom,
>
> On Thu, Feb 23, 2017 at 08:28:47AM -0800, Tom Herbert wrote:
>
>> If there is a way for us to test this without setting up a full mobile
>> network please provide details on how to do that in the commit log.
>
> There are different ways how to do this.  With the existing in-kernel
> code (that lacks the "SGSN role" patch which would be for testing only),
> you can e.g. use two relatively small C-language programs from the
> openggnsn package [http://git.osmocom.org/openggsn/]:
>
> * OpenGGSN with support for libgtpnl and the kernel GTP-U module
> * sgsnemu (included in openggsn source tree) which implements a minimal
>   SGSN-side of the tunnel.  It will
>   * perform the GTP-C signaling required with OpenGGSN (which in turn
>     will then instruct the kernel to open a  tunnel via the netlink
>     interface).
>   * start a tun/tap device for the "mobile station end" of the tunnel
>     perform en/decapsulation of data between that tun/tap device and GTP
>     in userspace
>
> The wiki at https://osmocom.org/projects/openggsn/wiki/OpenGGSN contains
> step-by-step instructions how to build and configure OpenGGSN with
> support for kernel GTP-U. It's nothing more than autotools based
> compile+install of libgtpnl followed by "./configure --enable-gtp-linux"
> and "make" for OpenGGSN
>
> What is not described on the above page is how to use sgsnemu to
> simulate the SGSN side, as within Osmocom we typically run the open
> source OsmoSGSN (a more "real" SGSN).
>
> So using two small binaries that can be compiled without much external
> dependencies (and very few lines of configuration), it is possible to do
> some functional testing of the kernel GTP module.  For performance
> testing this of course won't work, as sgsnemu is running entirely in
> userspace.
>
I'm looking at the GTP encapsulation, it's not particularly complex.
Is there any real reason why we can't just implement a netdev
interface with static tunnels and configuration to do performance
testing and development? For instance, if we want to add GSO/GRO
support to GTP that's all we really need, the control plane should be
inconsequential in that case.

> For performance testing, you would need a SGSN-side implementation of
> GTP-U that performs equally well or better than the GGSN-side
> implementation in the kernel.  One option is the patch that has recently
> been submitted to netdev and which is under discussion.  However, then
> you simply test one implementation against itself, which provides no
> interoperability guarantees with other implementations, and thus also
> limited in different regards.
>
That's always true of any protocol we implement-- you can only show
interoperability with what you test against. The best thing we can do
to help GTP is not treat it as being something special! Treat it like
any another encapsulation protocol to support in the kernel that needs
to be tested, maintained, have good performance, be interoperable,
etc.

>> > Adding static tunnel support into the kernel module in any form
>> > makes IMHO no sense. GTP as defined by 3GPP always need a control
>> > instance and there are much better options for static tunnel
>> > encapsulations.
>> >
>> That misses the point. From the kernel point of view GTP is just
>> another encapsulation protocol and we now have a lot of experience
>> with those. The problem is when you post patches to improve it or fix
>> issues, if there is no practical way to perform independent  analysis
>> or investigation. This makes GTP no different than a proprietary
>> protocol to us and that severely limits the value of trying to work
>> with the community.
>
> I wholeheartedly agree.  That's one of the reasons why I recently posted
> a RFC about what to do for (regression and other) testing of the kernel
> GTP-U module.
>
> I'll try to cook up some instructions extending
> https://osmocom.org/projects/openggsn/wiki/OpenGGSN to cover also
> sgsnemu for a basic use case of establishing one single tunnel.  That's
> of course like a manual "HOWTO" and not yet anything that can be tested
> automatically.
>
That would be good. Thanks!

> Regards,
>         Harald
>
> --
> - Harald Welte <laforge@gnumonks.org>           http://laforge.gnumonks.org/
> ============================================================================
> "Privacy in residential applications is a desirable marketing option."
>                                                   (ETSI EN 300 175-7 Ch. A6)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path
  2017-02-23 18:07           ` Tom Herbert
@ 2017-02-23 21:17             ` Harald Welte
  0 siblings, 0 replies; 16+ messages in thread
From: Harald Welte @ 2017-02-23 21:17 UTC (permalink / raw)
  To: Tom Herbert
  Cc: netdev, osmocom-net-gprs, timo lindhorst, Andreas Schultz, pablo

Hi Tom,

On Thu, Feb 23, 2017 at 10:07:03AM -0800, Tom Herbert wrote:
> I'm looking at the GTP encapsulation, it's not particularly complex.
> Is there any real reason why we can't just implement a netdev
> interface with static tunnels and configuration to do performance
> testing and development? For instance, if we want to add GSO/GRO
> support to GTP that's all we really need, the control plane should be
> inconsequential in that case.

As outlined several times in this thread, GTP tunneling is not
symmetric.  The current mainline code can only act as one of the two
roles (GGSN/G-GW), not as the other one.  The rationale is that in 3GPP
networks, that is the only point in the network that takes native IP
data (e.g.from the internet) and puts it into GTP.  At all other places
in the network, you don't have this combination.  By the time the inner
IP data arrives at the mobile phone, it is no longer encapsulated in
GTP, as the lower layers have been adapted one or multiple times to
other protocols by other network elements.

There's a patch that has recently been submitted which adds the
capability for the SGSN/S-GW side of a GTP-U tunnel, but that patch has
so far not been merged (due to concersn about its netlink interface),
and the patch *only* exists for testing, it has no real-world
application in 3GPP networks.

So as of now, it is not possible to run both endpoints of a tunnel in
Linux.

> > For performance testing, you would need a SGSN-side implementation of
> > I'll try to cook up some instructions extending
> > https://osmocom.org/projects/openggsn/wiki/OpenGGSN to cover also
> > sgsnemu for a basic use case of establishing one single tunnel.  That's
> > of course like a manual "HOWTO" and not yet anything that can be tested
> > automatically.
> >
> That would be good. Thanks!

I've spent some hours earlier today on this, I expect the document to be
ready at some point over the weekend.

-- 
- Harald Welte <laforge@gnumonks.org>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2017-02-24  7:15 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-21 10:18 [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
2017-02-21 10:18 ` [PATCH net-next v4 1/7] gtp: switch from struct socket to struct sock for the GTP sockets Andreas Schultz
2017-02-21 10:18 ` [PATCH net-next v4 2/7] gtp: make GTP sockets in gtp_newlink optional Andreas Schultz
2017-02-21 10:18 ` [PATCH net-next v4 3/7] gtp: merge gtp_get_net and gtp_genl_find_dev Andreas Schultz
2017-02-21 10:18 ` [PATCH net-next v4 4/7] gtp: consolidate gtp socket rx path Andreas Schultz
2017-02-22 17:41   ` Tom Herbert
2017-02-23  9:19     ` Andreas Schultz
2017-02-23 16:28       ` Tom Herbert
2017-02-23 16:46         ` Harald Welte
2017-02-23 18:07           ` Tom Herbert
2017-02-23 21:17             ` Harald Welte
2017-02-21 10:18 ` [PATCH net-next v4 5/7] gtp: unify genl_find_pdp and prepare for per socket lookup Andreas Schultz
2017-02-21 10:18 ` [PATCH net-next v4 6/7] gtp: consolidate pdp context destruction into helper Andreas Schultz
2017-02-21 10:18 ` [PATCH net-next v4 7/7] gtp: add socket to pdp context Andreas Schultz
2017-02-21 11:13 ` [PATCH net-next v4 0/7] gtp: misc improvements Andreas Schultz
2017-02-21 18:15 ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.