All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonas Bonn <jonas@norrbonn.se>
To: laforge@gnumonks.org, netdev@vger.kernel.org, pbshelar@fb.com,
	kuba@kernel.org
Cc: pablo@netfilter.org, Jonas Bonn <jonas@norrbonn.se>
Subject: [RFC PATCH 14/16] gtp: add support for flow based tunneling
Date: Sat, 23 Jan 2021 20:59:14 +0100	[thread overview]
Message-ID: <20210123195916.2765481-15-jonas@norrbonn.se> (raw)
In-Reply-To: <20210123195916.2765481-1-jonas@norrbonn.se>

From: Pravin B Shelar <pbshelar@fb.com>

This patch adds support for flow based tunneling, allowing to send and
receive GTP tunneled packets via the (lightweight) tunnel metadata
mechanism.  This would allow integration with OVS and eBPF using flow
based tunneling APIs.

The mechanism used here is to get the required GTP tunnel parameters
from the tunnel metadata instead of looking up a pre-configured PDP
context.  The tunnel metadata contains the necessary information for
creating the GTP header.

Signed-off-by: Jonas Bonn <jonas@norrbonn.se>
---
 drivers/net/gtp.c                  | 160 +++++++++++++++++++++++++----
 include/uapi/linux/gtp.h           |  12 +++
 include/uapi/linux/if_tunnel.h     |   1 +
 tools/include/uapi/linux/if_link.h |   1 +
 4 files changed, 156 insertions(+), 18 deletions(-)

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 8aab46ec8a94..668ed8a4836e 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -21,6 +21,7 @@
 #include <linux/file.h>
 #include <linux/gtp.h>
 
+#include <net/dst_metadata.h>
 #include <net/net_namespace.h>
 #include <net/protocol.h>
 #include <net/ip.h>
@@ -74,6 +75,9 @@ struct gtp_dev {
 	unsigned int		hash_size;
 	struct hlist_head	*tid_hash;
 	struct hlist_head	*addr_hash;
+	/* Used by LWT tunnel. */
+	bool			collect_md;
+	struct socket		*collect_md_sock;
 };
 
 static unsigned int gtp_net_id __read_mostly;
@@ -224,6 +228,51 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb,
 	return -1;
 }
 
+static int gtp_set_tun_dst(struct pdp_ctx *pctx, struct sk_buff *skb,
+			   unsigned int hdrlen)
+{
+	struct metadata_dst *tun_dst;
+	struct gtp1_header *gtp1;
+	int opts_len = 0;
+	__be64 tid;
+
+	gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
+
+	tid = key32_to_tunnel_id(gtp1->tid);
+
+	if (unlikely(gtp1->flags & GTP1_F_MASK))
+		opts_len = sizeof(struct gtpu_metadata);
+
+	tun_dst = udp_tun_rx_dst(skb,
+			pctx->sk->sk_family, TUNNEL_KEY, tid, opts_len);
+	if (!tun_dst) {
+		netdev_dbg(pctx->dev, "Failed to allocate tun_dst");
+		goto err;
+	}
+
+	netdev_dbg(pctx->dev, "attaching metadata_dst to skb, gtp ver %d hdrlen %d\n",
+		   pctx->gtp_version, hdrlen);
+	if (unlikely(opts_len)) {
+		struct gtpu_metadata *opts;
+
+		opts = ip_tunnel_info_opts(&tun_dst->u.tun_info);
+		opts->ver = GTP_METADATA_V1;
+		opts->flags = gtp1->flags;
+		opts->type = gtp1->type;
+		netdev_dbg(pctx->dev, "recved control pkt: flag %x type: %d\n",
+			   opts->flags, opts->type);
+		tun_dst->u.tun_info.key.tun_flags |= TUNNEL_GTPU_OPT;
+		tun_dst->u.tun_info.options_len = opts_len;
+		skb->protocol = htons(0xffff);         /* Unknown */
+	}
+
+	skb_dst_set(skb, &tun_dst->dst);
+	return 0;
+err:
+	return -1;
+}
+
+
 /* 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)
 {
@@ -262,6 +311,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 	unsigned int hdrlen = sizeof(struct udphdr) +
 			      sizeof(struct gtp1_header);
 	struct gtp1_header *gtp1;
+	struct pdp_ctx md_pctx;
 	struct pdp_ctx *pctx;
 
 	if (!pskb_may_pull(skb, hdrlen))
@@ -272,6 +322,24 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
 	if ((gtp1->flags >> 5) != GTP_V1)
 		return 1;
 
+	if (ip_tunnel_collect_metadata() || gtp->collect_md) {
+		int err;
+
+		pctx = &md_pctx;
+
+		pctx->gtp_version = GTP_V1;
+		pctx->sk = gtp->sk1u;
+		pctx->dev = gtp->dev;
+
+		err = gtp_set_tun_dst(pctx, skb, hdrlen);
+		if (err) {
+			gtp->dev->stats.rx_dropped++;
+			return -1;
+		}
+
+		return gtp_rx(pctx, skb, hdrlen);
+	}
+
 	if (gtp1->type != GTP_TPDU)
 		return 1;
 
@@ -353,7 +421,8 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
 	if (!gtp)
 		return 1;
 
-	netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
+	netdev_dbg(gtp->dev, "encap_recv sk=%p type %d\n",
+		   sk, udp_sk(sk)->encap_type);
 
 	switch (udp_sk(sk)->encap_type) {
 	case UDP_ENCAP_GTP0:
@@ -539,7 +608,7 @@ static struct rtable *gtp_get_v4_rt(struct sk_buff *skb,
 	memset(&fl4, 0, sizeof(fl4));
 	fl4.flowi4_oif		= sk->sk_bound_dev_if;
 	fl4.daddr		= pctx->peer_addr_ip4.s_addr;
-	fl4.saddr		= inet_sk(sk)->inet_saddr;
+	fl4.saddr		= *saddr;
 	fl4.flowi4_tos		= RT_CONN_FLAGS(sk);
 	fl4.flowi4_proto	= sk->sk_protocol;
 
@@ -617,29 +686,84 @@ static void gtp_push_header(struct sk_buff *skb, struct pdp_ctx *pctx,
 static int gtp_xmit_ip4(struct sk_buff *skb, struct net_device *dev)
 {
 	struct gtp_dev *gtp = netdev_priv(dev);
+	struct gtpu_metadata *opts = NULL;
+	struct pdp_ctx md_pctx;
 	struct pdp_ctx *pctx;
+	__be16 port;
 	struct rtable *rt;
-	__be32 saddr;
 	struct iphdr *iph;
+	__be32 saddr;
 	int headroom;
-	__be16 port;
+	__u8 tos;
 	int r;
 
-	/* Read the IP destination address and resolve the PDP context.
-	 * Prepend PDP header with TEI/TID from PDP ctx.
-	 */
-	iph = ip_hdr(skb);
-	if (gtp->role == GTP_ROLE_SGSN)
-		pctx = ipv4_pdp_find(gtp, iph->saddr);
-	else
-		pctx = ipv4_pdp_find(gtp, iph->daddr);
+	if (gtp->collect_md) {
+		/* LWT GTP1U encap */
+		struct ip_tunnel_info *info = NULL;
 
-	if (!pctx) {
-		netdev_dbg(dev, "no PDP ctx found for %pI4, skip\n",
-			   &iph->daddr);
-		return -ENOENT;
+		info = skb_tunnel_info(skb);
+		if (!info) {
+			netdev_dbg(dev, "missing tunnel info");
+			return -ENOENT;
+		}
+		if (info->key.tp_dst && ntohs(info->key.tp_dst) != GTP1U_PORT) {
+			netdev_dbg(dev, "unexpected GTP dst port: %d", ntohs(info->key.tp_dst));
+			return -EOPNOTSUPP;
+		}
+
+		if (!gtp->sk1u) {
+			netdev_dbg(dev, "missing tunnel sock");
+			return -EOPNOTSUPP;
+		}
+
+		pctx = &md_pctx;
+		memset(pctx, 0, sizeof(*pctx));
+		pctx->sk = gtp->sk1u;
+		pctx->gtp_version = GTP_V1;
+		pctx->u.v1.o_tei = ntohl(tunnel_id_to_key32(info->key.tun_id));
+		pctx->peer_addr_ip4.s_addr = info->key.u.ipv4.dst;
+
+		saddr = info->key.u.ipv4.src;
+		tos = info->key.tos;
+
+		if (info->options_len != 0) {
+			if (info->key.tun_flags & TUNNEL_GTPU_OPT) {
+				opts = ip_tunnel_info_opts(info);
+			} else {
+				netdev_dbg(dev, "missing tunnel metadata for control pkt");
+				return -EOPNOTSUPP;
+			}
+		}
+		netdev_dbg(dev, "flow-based GTP1U encap: tunnel id %d\n",
+			   pctx->u.v1.o_tei);
+	} else {
+		struct iphdr *iph;
+
+		if (ntohs(skb->protocol) != ETH_P_IP)
+			return -EOPNOTSUPP;
+
+		iph = ip_hdr(skb);
+
+		/* Read the IP destination address and resolve the PDP context.
+		 * Prepend PDP header with TEI/TID from PDP ctx.
+		 */
+		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);
+			return -ENOENT;
+		}
+		netdev_dbg(dev, "found PDP context %p\n", pctx);
+
+		saddr = inet_sk(pctx->sk)->inet_saddr;
+		tos = iph->tos;
+		netdev_dbg(dev, "gtp -> IP src: %pI4 dst: %pI4\n",
+			   &iph->saddr, &iph->daddr);
 	}
-	netdev_dbg(dev, "found PDP context %p\n", pctx);
 
 	rt = gtp_get_v4_rt(skb, dev, pctx, &saddr);
 	if (IS_ERR(rt)) {
@@ -691,7 +815,7 @@ static int gtp_xmit_ip4(struct sk_buff *skb, struct net_device *dev)
 
 	udp_tunnel_xmit_skb(rt, pctx->sk, skb,
 			    saddr, pctx->peer_addr_ip4.s_addr,
-			    iph->tos,
+			    tos,
 			    ip4_dst_hoplimit(&rt->dst),
 			    0,
 			    port, port,
diff --git a/include/uapi/linux/gtp.h b/include/uapi/linux/gtp.h
index 79f9191bbb24..62aff78b7c56 100644
--- a/include/uapi/linux/gtp.h
+++ b/include/uapi/linux/gtp.h
@@ -2,6 +2,8 @@
 #ifndef _UAPI_LINUX_GTP_H_
 #define _UAPI_LINUX_GTP_H_
 
+#include <linux/types.h>
+
 #define GTP_GENL_MCGRP_NAME	"gtp"
 
 enum gtp_genl_cmds {
@@ -34,4 +36,14 @@ enum gtp_attrs {
 };
 #define GTPA_MAX (__GTPA_MAX + 1)
 
+enum {
+	GTP_METADATA_V1
+};
+
+struct gtpu_metadata {
+	__u8    ver;
+	__u8    flags;
+	__u8    type;
+};
+
 #endif /* _UAPI_LINUX_GTP_H_ */
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index 7d9105533c7b..802da679fab1 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -176,6 +176,7 @@ enum {
 #define TUNNEL_VXLAN_OPT	__cpu_to_be16(0x1000)
 #define TUNNEL_NOCACHE		__cpu_to_be16(0x2000)
 #define TUNNEL_ERSPAN_OPT	__cpu_to_be16(0x4000)
+#define TUNNEL_GTPU_OPT		__cpu_to_be16(0x8000)
 
 #define TUNNEL_OPTIONS_PRESENT \
 		(TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT | TUNNEL_ERSPAN_OPT)
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
index d208b2af697f..28d649bda686 100644
--- a/tools/include/uapi/linux/if_link.h
+++ b/tools/include/uapi/linux/if_link.h
@@ -617,6 +617,7 @@ enum {
 	IFLA_GTP_FD1,
 	IFLA_GTP_PDP_HASHSIZE,
 	IFLA_GTP_ROLE,
+	IFLA_GTP_COLLECT_METADATA,
 	__IFLA_GTP_MAX,
 };
 #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
-- 
2.27.0


  parent reply	other threads:[~2021-01-23 20:04 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-23 19:59 [RFC PATCH 00/16] GTP: flow based Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 01/16] Revert "GTP: add support for flow based tunneling API" Jonas Bonn
2021-01-24 16:34   ` Harald Welte
2021-01-23 19:59 ` [RFC PATCH 02/16] gtp: set initial MTU Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 03/16] gtp: include role in link info Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 04/16] gtp: really check namespaces before xmit Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 05/16] gtp: drop unnecessary call to skb_dst_drop Jonas Bonn
2021-01-24 16:48   ` Harald Welte
2021-01-23 19:59 ` [RFC PATCH 06/16] gtp: set device type Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 07/16] gtp: rework IPv4 functionality Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 08/16] gtp: set dev features to enable GSO Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 09/16] gtp: support GRO Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 10/16] gtp: refactor check_ms back into version specific handlers Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 11/16] gtp: drop duplicated assignment Jonas Bonn
2021-01-23 19:59 ` [RFC PATCH 12/16] gtp: update rx_length_errors for abnormally short packets Jonas Bonn
2021-01-24 16:50   ` Harald Welte
2021-01-23 19:59 ` [RFC PATCH 13/16] gtp: set skb protocol after pulling headers Jonas Bonn
2021-01-23 19:59 ` Jonas Bonn [this message]
2021-01-24 14:27   ` [RFC PATCH 14/16] gtp: add support for flow based tunneling Jonas Bonn
2021-01-24 15:11   ` Jonas Bonn
2021-01-25  8:12   ` Jonas Bonn
2021-01-25  8:47   ` Jonas Bonn
2021-02-06 18:04   ` Jonas Bonn
2021-02-07 17:56     ` Pravin Shelar
2021-01-23 19:59 ` [RFC PATCH 15/16] gtp: add ability to send GTP controls headers Jonas Bonn
2021-01-24 14:21   ` Jonas Bonn
2021-01-25 17:41     ` Harald Welte
2021-01-28 21:29       ` Pravin Shelar
2021-01-28 21:29     ` Pravin Shelar
     [not found]       ` <9b9476d2-186f-e749-f17d-d191c30347e4@norrbonn.se>
2021-01-30  6:59         ` Pravin Shelar
2021-01-30 18:44           ` Jakub Kicinski
2021-01-30 20:05             ` Pravin Shelar
2021-02-01 20:44               ` Jakub Kicinski
2021-02-02  5:24                 ` Jonas Bonn
2021-02-02  6:56                   ` Pravin Shelar
2021-02-02  8:03                     ` Jonas Bonn
2021-02-02 22:54                       ` Pravin Shelar
2021-01-23 19:59 ` [RFC PATCH 16/16] gtp: add netlink support for setting up flow based tunnels Jonas Bonn
2021-01-24 17:42 ` [RFC PATCH 00/16] GTP: flow based Pravin Shelar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210123195916.2765481-15-jonas@norrbonn.se \
    --to=jonas@norrbonn.se \
    --cc=kuba@kernel.org \
    --cc=laforge@gnumonks.org \
    --cc=netdev@vger.kernel.org \
    --cc=pablo@netfilter.org \
    --cc=pbshelar@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.