diff mbox series

[net-next,13/14] gtp: Support for GRO

Message ID 20170919003904.5124-14-tom@quantonium.net
State Changes Requested, archived
Delegated to: David Miller
Headers show
Series gtp: Additional feature support | expand

Commit Message

Tom Herbert Sept. 19, 2017, 12:39 a.m. UTC
Populate GRO receive and GRO complete functions for GTP-Uv0 and v1.

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 drivers/net/gtp.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 204 insertions(+)

Comments

kernel test robot Sept. 19, 2017, 11:57 a.m. UTC | #1
Hi Tom,

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Tom-Herbert/gtp-Additional-feature-support/20170919-143920
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)


vim +3958 include/linux/netdevice.h

5b33bc6e Tom Herbert 2017-09-18  3944  
5b33bc6e Tom Herbert 2017-09-18  3945  /* rcu_read_lock() must be held */
5b33bc6e Tom Herbert 2017-09-18  3946  static inline struct skb_gso_app *skb_gso_app_lookup(struct sk_buff *skb,
5b33bc6e Tom Herbert 2017-09-18  3947  						     netdev_features_t features,
5b33bc6e Tom Herbert 2017-09-18  3948  						     unsigned int check_flags)
5b33bc6e Tom Herbert 2017-09-18  3949  {
5b33bc6e Tom Herbert 2017-09-18  3950  	struct skb_gso_app *app;
5b33bc6e Tom Herbert 2017-09-18  3951  	int type;
5b33bc6e Tom Herbert 2017-09-18  3952  
5b33bc6e Tom Herbert 2017-09-18  3953  	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_APP_MASK))
5b33bc6e Tom Herbert 2017-09-18  3954  		return false;
5b33bc6e Tom Herbert 2017-09-18  3955  
5b33bc6e Tom Herbert 2017-09-18  3956  	type = skb_gso_app_to_index(skb_shinfo(skb)->gso_type);
5b33bc6e Tom Herbert 2017-09-18  3957  
5b33bc6e Tom Herbert 2017-09-18 @3958  	app = rcu_dereference(skb_gso_apps[type]);
5b33bc6e Tom Herbert 2017-09-18  3959  	if (app && app->gso_segment &&
5b33bc6e Tom Herbert 2017-09-18  3960  	    (check_flags & app->check_flags))
5b33bc6e Tom Herbert 2017-09-18  3961  		return app;
5b33bc6e Tom Herbert 2017-09-18  3962  
5b33bc6e Tom Herbert 2017-09-18  3963  	return NULL;
5b33bc6e Tom Herbert 2017-09-18  3964  }
5b33bc6e Tom Herbert 2017-09-18  3965  

:::::: The code at line 3958 was first introduced by commit
:::::: 5b33bc6e4fcae1113167c651a3d3a218c7e277c6 net: Add a facility to support application defined GSO

:::::: TO: Tom Herbert <tom@quantonium.net>
:::::: CC: 0day robot <fengguang.wu@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Harald Welte Sept. 19, 2017, 12:03 p.m. UTC | #2
On Mon, Sep 18, 2017 at 05:39:03PM -0700, Tom Herbert wrote:
> Populate GRO receive and GRO complete functions for GTP-Uv0 and v1.

looks fine to me, though I'm not the GRO expert here.  Let's say what
the netdev gurus have to say in their review.

If you say it is tested with GRO-capable and non-GRO capable device
drivers, I'm fine with the patch.
diff mbox series

Patch

diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index b53946f8b10b..2f9d810cf19f 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -22,6 +22,7 @@ 
 #include <linux/jhash.h>
 #include <linux/if_tunnel.h>
 #include <linux/net.h>
+#include <linux/netdevice.h>
 #include <linux/file.h>
 #include <linux/gtp.h>
 
@@ -429,6 +430,205 @@  static int gtp1u_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 	return 1;
 }
 
+static struct sk_buff **gtp_gro_receive_finish(struct sock *sk,
+					       struct sk_buff **head,
+					       struct sk_buff *skb,
+					       void *hdr, size_t hdrlen)
+{
+	const struct packet_offload *ptype;
+	struct sk_buff **pp;
+	__be16 type;
+
+	type = ipver_to_eth((struct iphdr *)((void *)hdr + hdrlen));
+	if (!type)
+		goto out_err;
+
+	rcu_read_lock();
+
+	ptype = gro_find_receive_by_type(type);
+	if (!ptype)
+		goto out_unlock_err;
+
+	skb_gro_pull(skb, hdrlen);
+	skb_gro_postpull_rcsum(skb, hdr, hdrlen);
+	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+
+	rcu_read_unlock();
+
+	return pp;
+
+out_unlock_err:
+	rcu_read_unlock();
+out_err:
+	NAPI_GRO_CB(skb)->flush |= 1;
+	return NULL;
+}
+
+static struct sk_buff **gtp0_gro_receive(struct sock *sk,
+					 struct sk_buff **head,
+					 struct sk_buff *skb)
+{
+	struct gtp0_header *gtp0;
+	size_t len, hdrlen, off;
+	struct sk_buff *p;
+
+	off = skb_gro_offset(skb);
+	len = off + sizeof(*gtp0);
+	hdrlen = sizeof(*gtp0);
+
+	gtp0 = skb_gro_header_fast(skb, off);
+	if (skb_gro_header_hard(skb, len)) {
+		gtp0 = skb_gro_header_slow(skb, len, off);
+		if (unlikely(!gtp0))
+			goto out;
+	}
+
+	if ((gtp0->flags >> 5) != GTP_V0 || gtp0->type != GTP_TPDU)
+		goto out;
+
+	hdrlen += sizeof(*gtp0);
+
+	/* To get IP version */
+	len += sizeof(struct iphdr);
+
+	/* Now get header with GTP header an IPv4 header (for version) */
+	if (skb_gro_header_hard(skb, len)) {
+		gtp0 = skb_gro_header_slow(skb, len, off);
+		if (unlikely(!gtp0))
+			goto out;
+	}
+
+	for (p = *head; p; p = p->next) {
+		const struct gtp0_header *gtp0_t;
+
+		if (!NAPI_GRO_CB(p)->same_flow)
+			continue;
+
+		gtp0_t = (struct gtp0_header *)(p->data + off);
+
+		if (gtp0->flags != gtp0_t->flags ||
+		    gtp0->type != gtp0_t->type ||
+		    gtp0->flow != gtp0_t->flow ||
+		    gtp0->tid != gtp0_t->tid) {
+			NAPI_GRO_CB(p)->same_flow = 0;
+			continue;
+		}
+	}
+
+	return gtp_gro_receive_finish(sk, head, skb, gtp0, hdrlen);
+
+out:
+	NAPI_GRO_CB(skb)->flush |= 1;
+
+	return NULL;
+}
+
+static struct sk_buff **gtp1u_gro_receive(struct sock *sk,
+					  struct sk_buff **head,
+					  struct sk_buff *skb)
+{
+	struct gtp1_header *gtp1;
+	size_t len, hdrlen, off;
+	struct sk_buff *p;
+
+	off = skb_gro_offset(skb);
+	len = off + sizeof(*gtp1);
+	hdrlen = sizeof(*gtp1);
+
+	gtp1 = skb_gro_header_fast(skb, off);
+	if (skb_gro_header_hard(skb, len)) {
+		gtp1 = skb_gro_header_slow(skb, len, off);
+		if (unlikely(!gtp1))
+			goto out;
+	}
+
+	if ((gtp1->flags >> 5) != GTP_V1 || gtp1->type != GTP_TPDU)
+		goto out;
+
+	if (gtp1->flags & GTP1_F_MASK) {
+		hdrlen += 4;
+		len += 4;
+	}
+
+	len += sizeof(struct iphdr);
+
+	/* Now get header with GTP header an IPv4 header (for version) */
+	if (skb_gro_header_hard(skb, len)) {
+		gtp1 = skb_gro_header_slow(skb, len, off);
+		if (unlikely(!gtp1))
+			goto out;
+	}
+
+	for (p = *head; p; p = p->next) {
+		const struct gtp1_header *gtp1_t;
+
+		if (!NAPI_GRO_CB(p)->same_flow)
+			continue;
+
+		gtp1_t = (struct gtp1_header *)(p->data + off);
+
+		if (gtp1->flags != gtp1_t->flags ||
+		    gtp1->type != gtp1_t->type ||
+		    gtp1->tid != gtp1_t->tid) {
+			NAPI_GRO_CB(p)->same_flow = 0;
+			continue;
+		}
+	}
+
+	return gtp_gro_receive_finish(sk, head, skb, gtp1, hdrlen);
+
+out:
+	NAPI_GRO_CB(skb)->flush = 1;
+
+	return NULL;
+}
+
+static int gtp_gro_complete_finish(struct sock *sk, struct sk_buff *skb,
+				   int nhoff, size_t hdrlen)
+{
+	struct packet_offload *ptype;
+	int err = -EINVAL;
+	__be16 type;
+
+	type = ipver_to_eth((struct iphdr *)(skb->data + nhoff + hdrlen));
+	if (!type)
+		return err;
+
+	rcu_read_lock();
+	ptype = gro_find_complete_by_type(type);
+	if (ptype)
+		err = ptype->callbacks.gro_complete(skb, nhoff + hdrlen);
+
+	rcu_read_unlock();
+
+	skb_set_inner_mac_header(skb, nhoff + hdrlen);
+
+	return err;
+}
+
+static int gtp0_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
+{
+	struct gtp0_header *gtp0 = (struct gtp0_header *)(skb->data + nhoff);
+	size_t hdrlen = sizeof(struct gtp0_header);
+
+	gtp0->length = htons(skb->len - nhoff - hdrlen);
+
+	return gtp_gro_complete_finish(sk, skb, nhoff, hdrlen);
+}
+
+static int gtp1u_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
+{
+	struct gtp1_header *gtp1 = (struct gtp1_header *)(skb->data + nhoff);
+	size_t hdrlen = sizeof(struct gtp1_header);
+
+	if (gtp1->flags & GTP1_F_MASK)
+		hdrlen += 4;
+
+	gtp1->length = htons(skb->len - nhoff - hdrlen);
+
+	return gtp_gro_complete_finish(sk, skb, nhoff, hdrlen);
+}
+
 static void gtp_encap_destroy(struct sock *sk)
 {
 	struct gtp_dev *gtp;
@@ -946,9 +1146,13 @@  static int gtp_encap_enable_sock(struct socket *sock, int type,
 	switch (type) {
 	case UDP_ENCAP_GTP0:
 		tuncfg.encap_rcv = gtp0_udp_encap_recv;
+		tuncfg.gro_receive = gtp0_gro_receive;
+		tuncfg.gro_complete = gtp0_gro_complete;
 		break;
 	case UDP_ENCAP_GTP1U:
 		tuncfg.encap_rcv = gtp1u_udp_encap_recv;
+		tuncfg.gro_receive = gtp1u_gro_receive;
+		tuncfg.gro_complete = gtp1u_gro_complete;
 		break;
 	default:
 		pr_debug("Unknown encap type %u\n", type);