netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH next-next 0/7]  net: Cleanup IPv6 ip tunnels
@ 2016-04-30  0:12 Tom Herbert
  2016-04-30  0:12 ` [PATCH next-next 1/7] ipv6: Cleanup IPv6 tunnel receive path Tom Herbert
                   ` (9 more replies)
  0 siblings, 10 replies; 17+ messages in thread
From: Tom Herbert @ 2016-04-30  0:12 UTC (permalink / raw)
  To: davem, netdev; +Cc: kernel-team

The IPv6 tunnel code is very different from IPv4 code. There is a lot
of redundancy with the IPv4 code, particularly in the GRE tunneling.

This patch set cleans up the tunnel code to make the IPv6 code look
more like the IPv4 code and use common functions between the two
stacks where possible.

This work should make it easier to maintain and extend the IPv6 ip
tunnels.

Items in this patch set:
  - Cleanup IPv6 tunnel receive path (ip6_tnl_rcv). Includes using
    gro_cells and exporting ip6_tnl_rcv so the ip6_gre can call it
  - Move GRE functions to common header file (tx functions) or
    gre_demux.c (rx functions like gre_parse_header)
  - Call common GRE functions from IPv6 GRE
  - Create ip6_tnl_xmit (to be like ip_tunnel_xmit)

Tested:
  Ran super_netperf tests for TCP_RR and TCP_STREAM for:
    - IPv4 over gre, gretap, gre6, gre6tap
    - IPv6 over gre, gretap, gre6, gre6tap
    - ipip
    - ip6ip6
    - ipip/gue
    - IPv6 over gre/gue
    - IPv4 over gre/gue

Tom Herbert (7):
  ipv6: Cleanup IPv6 tunnel receive path
  gre: Move utility functions to common headers
  gre6: Cleanup GREv6 receive path, call common GRE functions
  ipv6: Create ip6_tnl_xmit
  gre: Create common functions for transmit
  ipv6: Generic tunnel cleanup
  gre6: Cleanup GREv6 transmit path, call common GRE functions

 include/net/gre.h        | 104 +++++++++++++
 include/net/ip6_tunnel.h |  11 +-
 net/ipv4/gre_demux.c     |  64 ++++++++
 net/ipv4/ip_gre.c        | 199 +++---------------------
 net/ipv6/ip6_gre.c       | 392 +++++++++--------------------------------------
 net/ipv6/ip6_tunnel.c    | 266 +++++++++++++++++++++-----------
 6 files changed, 452 insertions(+), 584 deletions(-)

-- 
2.8.0.rc2

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

* [PATCH next-next 1/7] ipv6: Cleanup IPv6 tunnel receive path
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
@ 2016-04-30  0:12 ` Tom Herbert
  2016-04-30  0:12 ` [PATCH next-next 2/7] gre: Move utility functions to common headers Tom Herbert
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Tom Herbert @ 2016-04-30  0:12 UTC (permalink / raw)
  To: davem, netdev; +Cc: kernel-team

Some basic changes to make IPv6 tunnel receive path look more like
IPv4 path:
  - Make ip6_tnl_rcv non-static so that GREv6 and others can call it
  - Make ip6_tnl_rcv look like ip_tunnel_rcv
  - Switch to gro_cells_receive
  - Make ip6_tnl_rcv non-static and export it

Signed-off-by: Tom Herbert <tom@herbertland.com>
---
 include/net/ip6_tunnel.h |   4 +
 net/ipv6/ip6_tunnel.c    | 212 +++++++++++++++++++++++++++++++----------------
 2 files changed, 146 insertions(+), 70 deletions(-)

diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index 499a707..eab3a9b 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -42,6 +42,7 @@ struct ip6_tnl {
 	struct __ip6_tnl_parm parms;	/* tunnel configuration parameters */
 	struct flowi fl;	/* flowi template for xmit */
 	struct dst_cache dst_cache;	/* cached dst */
+	struct gro_cells gro_cells;
 
 	int err_count;
 	unsigned long err_time;
@@ -63,6 +64,9 @@ struct ipv6_tlv_tnl_enc_lim {
 
 int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
 		const struct in6_addr *raddr);
+int ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
+		const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
+		bool log_ecn_error);
 int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
 		     const struct in6_addr *raddr);
 __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 1f20345..94ed065 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -238,6 +238,7 @@ static void ip6_dev_free(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
 
+	gro_cells_destroy(&t->gro_cells);
 	dst_cache_destroy(&t->dst_cache);
 	free_percpu(dev->tstats);
 	free_netdev(dev);
@@ -753,97 +754,157 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
 }
 EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
 
-/**
- * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
- *   @skb: received socket buffer
- *   @protocol: ethernet protocol ID
- *   @dscp_ecn_decapsulate: the function to decapsulate DSCP code and ECN
- *
- * Return: 0
- **/
-
-static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
-		       __u8 ipproto,
-		       int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
-						   const struct ipv6hdr *ipv6h,
-						   struct sk_buff *skb))
+static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
+			 const struct tnl_ptk_info *tpi,
+			 struct metadata_dst *tun_dst,
+			 int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
+						const struct ipv6hdr *ipv6h,
+						struct sk_buff *skb),
+			 bool log_ecn_err)
 {
-	struct ip6_tnl *t;
+	struct pcpu_sw_netstats *tstats;
 	const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
-	u8 tproto;
 	int err;
 
-	rcu_read_lock();
-	t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
-	if (t) {
-		struct pcpu_sw_netstats *tstats;
+	if ((!(tpi->flags & TUNNEL_CSUM) &&
+	     (tunnel->parms.i_flags & TUNNEL_CSUM)) ||
+	    ((tpi->flags & TUNNEL_CSUM) &&
+	     !(tunnel->parms.i_flags & TUNNEL_CSUM))) {
+		tunnel->dev->stats.rx_crc_errors++;
+		tunnel->dev->stats.rx_errors++;
+		goto drop;
+	}
 
-		tproto = ACCESS_ONCE(t->parms.proto);
-		if (tproto != ipproto && tproto != 0) {
-			rcu_read_unlock();
-			goto discard;
+	if (tunnel->parms.i_flags & TUNNEL_SEQ) {
+		if (!(tpi->flags & TUNNEL_SEQ) ||
+		    (tunnel->i_seqno &&
+		     (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) {
+			tunnel->dev->stats.rx_fifo_errors++;
+			tunnel->dev->stats.rx_errors++;
+			goto drop;
 		}
+		tunnel->i_seqno = ntohl(tpi->seq) + 1;
+	}
 
-		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-			rcu_read_unlock();
-			goto discard;
-		}
+	skb->protocol = tpi->proto;
 
-		if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
-			t->dev->stats.rx_dropped++;
-			rcu_read_unlock();
-			goto discard;
+	/* Warning: All skb pointers will be invalidated! */
+	if (tunnel->dev->type == ARPHRD_ETHER) {
+		if (!pskb_may_pull(skb, ETH_HLEN)) {
+			tunnel->dev->stats.rx_length_errors++;
+			tunnel->dev->stats.rx_errors++;
+			goto drop;
 		}
-		skb->mac_header = skb->network_header;
-		skb_reset_network_header(skb);
-		skb->protocol = htons(protocol);
-		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
-
-		__skb_tunnel_rx(skb, t->dev, t->net);
-
-		err = dscp_ecn_decapsulate(t, ipv6h, skb);
-		if (unlikely(err)) {
-			if (log_ecn_error)
-				net_info_ratelimited("non-ECT from %pI6 with dsfield=%#x\n",
-						     &ipv6h->saddr,
-						     ipv6_get_dsfield(ipv6h));
-			if (err > 1) {
-				++t->dev->stats.rx_frame_errors;
-				++t->dev->stats.rx_errors;
-				rcu_read_unlock();
-				goto discard;
-			}
+
+		ipv6h = ipv6_hdr(skb);
+		skb->protocol = eth_type_trans(skb, tunnel->dev);
+		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+	} else {
+		skb->dev = tunnel->dev;
+	}
+
+	skb_reset_network_header(skb);
+	memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+
+	__skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
+
+	err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
+	if (unlikely(err)) {
+		if (log_ecn_err)
+			net_info_ratelimited("non-ECT from %pI6 with DS=%#x\n",
+					     &ipv6h->saddr,
+					     ipv6_get_dsfield(ipv6h));
+		if (err > 1) {
+			++tunnel->dev->stats.rx_frame_errors;
+			++tunnel->dev->stats.rx_errors;
+			goto drop;
 		}
+	}
 
-		tstats = this_cpu_ptr(t->dev->tstats);
-		u64_stats_update_begin(&tstats->syncp);
-		tstats->rx_packets++;
-		tstats->rx_bytes += skb->len;
-		u64_stats_update_end(&tstats->syncp);
+	tstats = this_cpu_ptr(tunnel->dev->tstats);
+	u64_stats_update_begin(&tstats->syncp);
+	tstats->rx_packets++;
+	tstats->rx_bytes += skb->len;
+	u64_stats_update_end(&tstats->syncp);
 
-		netif_rx(skb);
+	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev)));
 
-		rcu_read_unlock();
-		return 0;
+	gro_cells_receive(&tunnel->gro_cells, skb);
+	return 0;
+
+drop:
+	kfree_skb(skb);
+	return 0;
+}
+
+int ip6_tnl_rcv(struct ip6_tnl *t, struct sk_buff *skb,
+		const struct tnl_ptk_info *tpi,
+		struct metadata_dst *tun_dst,
+		bool log_ecn_err)
+{
+	return __ip6_tnl_rcv(t, skb, tpi, NULL, ip6ip6_dscp_ecn_decapsulate,
+			     log_ecn_err);
+}
+EXPORT_SYMBOL(ip6_tnl_rcv);
+
+static const struct tnl_ptk_info tpi_v6 = {
+	/* no tunnel info required for ipxip6. */
+	.proto = htons(ETH_P_IPV6),
+};
+
+static const struct tnl_ptk_info tpi_v4 = {
+	/* no tunnel info required for ipxip6. */
+	.proto = htons(ETH_P_IP),
+};
+
+static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto,
+		      const struct tnl_ptk_info *tpi,
+		      int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
+						  const struct ipv6hdr *ipv6h,
+						  struct sk_buff *skb))
+{
+	struct ip6_tnl *t;
+	const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+	int ret = -1;
+
+	rcu_read_lock();
+	t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
+
+	if (t) {
+		u8 tproto = ACCESS_ONCE(t->parms.proto);
+
+		if (tproto != ipproto && tproto != 0)
+			goto drop;
+		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
+			goto drop;
+		if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr))
+			goto drop;
+		if (iptunnel_pull_header(skb, 0, tpi->proto, false))
+			goto drop;
+		ret = __ip6_tnl_rcv(t, skb, tpi, NULL, dscp_ecn_decapsulate,
+				    log_ecn_error);
 	}
+
 	rcu_read_unlock();
-	return 1;
 
-discard:
+	return ret;
+
+drop:
+	rcu_read_unlock();
 	kfree_skb(skb);
 	return 0;
 }
 
 static int ip4ip6_rcv(struct sk_buff *skb)
 {
-	return ip6_tnl_rcv(skb, ETH_P_IP, IPPROTO_IPIP,
-			   ip4ip6_dscp_ecn_decapsulate);
+	return ipxip6_rcv(skb, IPPROTO_IP, &tpi_v4,
+			  ip4ip6_dscp_ecn_decapsulate);
 }
 
 static int ip6ip6_rcv(struct sk_buff *skb)
 {
-	return ip6_tnl_rcv(skb, ETH_P_IPV6, IPPROTO_IPV6,
-			   ip6ip6_dscp_ecn_decapsulate);
+	return ipxip6_rcv(skb, IPPROTO_IPV6, &tpi_v6,
+			  ip6ip6_dscp_ecn_decapsulate);
 }
 
 struct ipv6_tel_txoption {
@@ -1370,6 +1431,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	struct net *net = t->net;
 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
 
+	memset(&p1, 0, sizeof(p1));
+
 	switch (cmd) {
 	case SIOCGETTUNNEL:
 		if (dev == ip6n->fb_tnl_dev) {
@@ -1549,13 +1612,22 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
 		return -ENOMEM;
 
 	ret = dst_cache_init(&t->dst_cache, GFP_KERNEL);
-	if (ret) {
-		free_percpu(dev->tstats);
-		dev->tstats = NULL;
-		return ret;
-	}
+	if (ret)
+		goto free_stats;
+
+	ret = gro_cells_init(&t->gro_cells, dev);
+	if (ret)
+		goto destroy_dst;
 
 	return 0;
+
+destroy_dst:
+	dst_cache_destroy(&t->dst_cache);
+free_stats:
+	free_percpu(dev->tstats);
+	dev->tstats = NULL;
+
+	return ret;
 }
 
 /**
-- 
2.8.0.rc2

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

* [PATCH next-next 2/7] gre: Move utility functions to common headers
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
  2016-04-30  0:12 ` [PATCH next-next 1/7] ipv6: Cleanup IPv6 tunnel receive path Tom Herbert
@ 2016-04-30  0:12 ` Tom Herbert
  2016-05-03 11:29   ` Jiri Benc
  2016-04-30  0:12 ` [PATCH next-next 3/7] gre6: Cleanup GREv6 receive path, call common GRE functions Tom Herbert
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Tom Herbert @ 2016-04-30  0:12 UTC (permalink / raw)
  To: davem, netdev; +Cc: kernel-team

Several of the GRE functions defined in net/ipv4/ip_gre.c are usable
for IPv6 GRE implementation (that is they are protocol agnostic).

These include:
  - GRE flag handling functions are move to gre.h
  - GRE build_header is moved to gre.h and renamed gre_build_header
  - parse_gre_header is moved to gre_demux.c and renamed gre_parse_header
  - iptunnel_pull_header is taken out of gre_parse_header. This is now
    done by caller. The header length is returned from gre_parse_header
    in an int* argument.

Signed-off-by: Tom Herbert <tom@herbertland.com>
---
 include/net/gre.h    |  60 +++++++++++++++++++++
 net/ipv4/gre_demux.c |  64 ++++++++++++++++++++++
 net/ipv4/ip_gre.c    | 149 +++++++--------------------------------------------
 3 files changed, 144 insertions(+), 129 deletions(-)

diff --git a/include/net/gre.h b/include/net/gre.h
index 97eafdc..3959158 100644
--- a/include/net/gre.h
+++ b/include/net/gre.h
@@ -25,4 +25,64 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version);
 
 struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
 				       u8 name_assign_type);
+int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
+		     bool *csum_err, int *hdr_len);
+
+static inline int gre_calc_hlen(__be16 o_flags)
+{
+	int addend = 4;
+
+	if (o_flags & TUNNEL_CSUM)
+		addend += 4;
+	if (o_flags & TUNNEL_KEY)
+		addend += 4;
+	if (o_flags & TUNNEL_SEQ)
+		addend += 4;
+	return addend;
+}
+
+static inline __be16 gre_flags_to_tnl_flags(__be16 flags)
+{
+	__be16 tflags = 0;
+
+	if (flags & GRE_CSUM)
+		tflags |= TUNNEL_CSUM;
+	if (flags & GRE_ROUTING)
+		tflags |= TUNNEL_ROUTING;
+	if (flags & GRE_KEY)
+		tflags |= TUNNEL_KEY;
+	if (flags & GRE_SEQ)
+		tflags |= TUNNEL_SEQ;
+	if (flags & GRE_STRICT)
+		tflags |= TUNNEL_STRICT;
+	if (flags & GRE_REC)
+		tflags |= TUNNEL_REC;
+	if (flags & GRE_VERSION)
+		tflags |= TUNNEL_VERSION;
+
+	return tflags;
+}
+
+static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags)
+{
+	__be16 flags = 0;
+
+	if (tflags & TUNNEL_CSUM)
+		flags |= GRE_CSUM;
+	if (tflags & TUNNEL_ROUTING)
+		flags |= GRE_ROUTING;
+	if (tflags & TUNNEL_KEY)
+		flags |= GRE_KEY;
+	if (tflags & TUNNEL_SEQ)
+		flags |= GRE_SEQ;
+	if (tflags & TUNNEL_STRICT)
+		flags |= GRE_STRICT;
+	if (tflags & TUNNEL_REC)
+		flags |= GRE_REC;
+	if (tflags & TUNNEL_VERSION)
+		flags |= GRE_VERSION;
+
+	return flags;
+}
+
 #endif
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c
index d9c552a..37167480 100644
--- a/net/ipv4/gre_demux.c
+++ b/net/ipv4/gre_demux.c
@@ -60,6 +60,70 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version)
 }
 EXPORT_SYMBOL_GPL(gre_del_protocol);
 
+int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
+		     bool *csum_err, int *ret_hdr_len)
+{
+	const struct gre_base_hdr *greh;
+	__be32 *options;
+	int hdr_len;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
+		return -EINVAL;
+
+	greh = (struct gre_base_hdr *)skb_transport_header(skb);
+	if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
+		return -EINVAL;
+
+	tpi->flags = gre_flags_to_tnl_flags(greh->flags);
+	hdr_len = gre_calc_hlen(tpi->flags);
+
+	if (!pskb_may_pull(skb, hdr_len))
+		return -EINVAL;
+
+	greh = (struct gre_base_hdr *)skb_transport_header(skb);
+	tpi->proto = greh->protocol;
+
+	options = (__be32 *)(greh + 1);
+	if (greh->flags & GRE_CSUM) {
+		if (skb_checksum_simple_validate(skb)) {
+			*csum_err = true;
+			return -EINVAL;
+		}
+
+		skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
+					 null_compute_pseudo);
+		options++;
+	}
+
+	if (greh->flags & GRE_KEY) {
+		tpi->key = *options;
+		options++;
+	} else {
+		tpi->key = 0;
+	}
+	if (unlikely(greh->flags & GRE_SEQ)) {
+		tpi->seq = *options;
+		options++;
+	} else {
+		tpi->seq = 0;
+	}
+	/* WCCP version 1 and 2 protocol decoding.
+	 * - Change protocol to IP
+	 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
+	 */
+	if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
+		tpi->proto = htons(ETH_P_IP);
+		if ((*(u8 *)options & 0xF0) != 0x40) {
+			hdr_len += 4;
+			if (!pskb_may_pull(skb, hdr_len))
+				return -EINVAL;
+		}
+	}
+	*ret_hdr_len = hdr_len;
+	return 0;
+}
+EXPORT_SYMBOL(gre_parse_header);
+
 static int gre_rcv(struct sk_buff *skb)
 {
 	const struct gre_protocol *proto;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index eedd829..f6db3d6 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -122,125 +122,6 @@ static int ipgre_tunnel_init(struct net_device *dev);
 static int ipgre_net_id __read_mostly;
 static int gre_tap_net_id __read_mostly;
 
-static int ip_gre_calc_hlen(__be16 o_flags)
-{
-	int addend = 4;
-
-	if (o_flags & TUNNEL_CSUM)
-		addend += 4;
-	if (o_flags & TUNNEL_KEY)
-		addend += 4;
-	if (o_flags & TUNNEL_SEQ)
-		addend += 4;
-	return addend;
-}
-
-static __be16 gre_flags_to_tnl_flags(__be16 flags)
-{
-	__be16 tflags = 0;
-
-	if (flags & GRE_CSUM)
-		tflags |= TUNNEL_CSUM;
-	if (flags & GRE_ROUTING)
-		tflags |= TUNNEL_ROUTING;
-	if (flags & GRE_KEY)
-		tflags |= TUNNEL_KEY;
-	if (flags & GRE_SEQ)
-		tflags |= TUNNEL_SEQ;
-	if (flags & GRE_STRICT)
-		tflags |= TUNNEL_STRICT;
-	if (flags & GRE_REC)
-		tflags |= TUNNEL_REC;
-	if (flags & GRE_VERSION)
-		tflags |= TUNNEL_VERSION;
-
-	return tflags;
-}
-
-static __be16 tnl_flags_to_gre_flags(__be16 tflags)
-{
-	__be16 flags = 0;
-
-	if (tflags & TUNNEL_CSUM)
-		flags |= GRE_CSUM;
-	if (tflags & TUNNEL_ROUTING)
-		flags |= GRE_ROUTING;
-	if (tflags & TUNNEL_KEY)
-		flags |= GRE_KEY;
-	if (tflags & TUNNEL_SEQ)
-		flags |= GRE_SEQ;
-	if (tflags & TUNNEL_STRICT)
-		flags |= GRE_STRICT;
-	if (tflags & TUNNEL_REC)
-		flags |= GRE_REC;
-	if (tflags & TUNNEL_VERSION)
-		flags |= GRE_VERSION;
-
-	return flags;
-}
-
-static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
-			    bool *csum_err)
-{
-	const struct gre_base_hdr *greh;
-	__be32 *options;
-	int hdr_len;
-
-	if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
-		return -EINVAL;
-
-	greh = (struct gre_base_hdr *)skb_transport_header(skb);
-	if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
-		return -EINVAL;
-
-	tpi->flags = gre_flags_to_tnl_flags(greh->flags);
-	hdr_len = ip_gre_calc_hlen(tpi->flags);
-
-	if (!pskb_may_pull(skb, hdr_len))
-		return -EINVAL;
-
-	greh = (struct gre_base_hdr *)skb_transport_header(skb);
-	tpi->proto = greh->protocol;
-
-	options = (__be32 *)(greh + 1);
-	if (greh->flags & GRE_CSUM) {
-		if (skb_checksum_simple_validate(skb)) {
-			*csum_err = true;
-			return -EINVAL;
-		}
-
-		skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
-					 null_compute_pseudo);
-		options++;
-	}
-
-	if (greh->flags & GRE_KEY) {
-		tpi->key = *options;
-		options++;
-	} else {
-		tpi->key = 0;
-	}
-	if (unlikely(greh->flags & GRE_SEQ)) {
-		tpi->seq = *options;
-		options++;
-	} else {
-		tpi->seq = 0;
-	}
-	/* WCCP version 1 and 2 protocol decoding.
-	 * - Change protocol to IP
-	 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
-	 */
-	if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
-		tpi->proto = htons(ETH_P_IP);
-		if ((*(u8 *)options & 0xF0) != 0x40) {
-			hdr_len += 4;
-			if (!pskb_may_pull(skb, hdr_len))
-				return -EINVAL;
-		}
-	}
-	return iptunnel_pull_header(skb, hdr_len, tpi->proto, false);
-}
-
 static void ipgre_err(struct sk_buff *skb, u32 info,
 		      const struct tnl_ptk_info *tpi)
 {
@@ -340,12 +221,16 @@ static void gre_err(struct sk_buff *skb, u32 info)
 	const int code = icmp_hdr(skb)->code;
 	struct tnl_ptk_info tpi;
 	bool csum_err = false;
+	int hdr_len;
 
-	if (parse_gre_header(skb, &tpi, &csum_err)) {
+	if (gre_parse_header(skb, &tpi, &csum_err, &hdr_len)) {
 		if (!csum_err)		/* ignore csum errors. */
 			return;
 	}
 
+	if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
+		return;
+
 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
 		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
 				 skb->dev->ifindex, 0, IPPROTO_GRE, 0);
@@ -419,6 +304,7 @@ static int gre_rcv(struct sk_buff *skb)
 {
 	struct tnl_ptk_info tpi;
 	bool csum_err = false;
+	int hdr_len;
 
 #ifdef CONFIG_NET_IPGRE_BROADCAST
 	if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
@@ -428,7 +314,10 @@ static int gre_rcv(struct sk_buff *skb)
 	}
 #endif
 
-	if (parse_gre_header(skb, &tpi, &csum_err) < 0)
+	if (gre_parse_header(skb, &tpi, &csum_err, &hdr_len) < 0)
+		goto drop;
+
+	if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
 		goto drop;
 
 	if (ipgre_rcv(skb, &tpi) == PACKET_RCVD)
@@ -460,7 +349,7 @@ static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags,
 
 	skb_reset_transport_header(skb);
 	greh = (struct gre_base_hdr *)skb->data;
-	greh->flags = tnl_flags_to_gre_flags(flags);
+	greh->flags = gre_tnl_flags_to_gre_flags(flags);
 	greh->protocol = proto;
 
 	if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
@@ -552,7 +441,7 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
 					  fl.saddr);
 	}
 
-	tunnel_hlen = ip_gre_calc_hlen(key->tun_flags);
+	tunnel_hlen = gre_calc_hlen(key->tun_flags);
 
 	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
 			+ tunnel_hlen + sizeof(struct iphdr);
@@ -694,8 +583,8 @@ static int ipgre_tunnel_ioctl(struct net_device *dev,
 	if (err)
 		return err;
 
-	p.i_flags = tnl_flags_to_gre_flags(p.i_flags);
-	p.o_flags = tnl_flags_to_gre_flags(p.o_flags);
+	p.i_flags = gre_tnl_flags_to_gre_flags(p.i_flags);
+	p.o_flags = gre_tnl_flags_to_gre_flags(p.o_flags);
 
 	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
 		return -EFAULT;
@@ -739,7 +628,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
 
 	iph = (struct iphdr *)skb_push(skb, t->hlen + sizeof(*iph));
 	greh = (struct gre_base_hdr *)(iph+1);
-	greh->flags = tnl_flags_to_gre_flags(t->parms.o_flags);
+	greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags);
 	greh->protocol = htons(type);
 
 	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
@@ -840,7 +729,7 @@ static void __gre_tunnel_init(struct net_device *dev)
 	int t_hlen;
 
 	tunnel = netdev_priv(dev);
-	tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
+	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
 	tunnel->parms.iph.protocol = IPPROTO_GRE;
 
 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
@@ -1155,8 +1044,10 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
 	struct ip_tunnel_parm *p = &t->parms;
 
 	if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
-	    nla_put_be16(skb, IFLA_GRE_IFLAGS, tnl_flags_to_gre_flags(p->i_flags)) ||
-	    nla_put_be16(skb, IFLA_GRE_OFLAGS, tnl_flags_to_gre_flags(p->o_flags)) ||
+	    nla_put_be16(skb, IFLA_GRE_IFLAGS,
+			 gre_tnl_flags_to_gre_flags(p->i_flags)) ||
+	    nla_put_be16(skb, IFLA_GRE_OFLAGS,
+			 gre_tnl_flags_to_gre_flags(p->o_flags)) ||
 	    nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
 	    nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
 	    nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
-- 
2.8.0.rc2

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

* [PATCH next-next 3/7] gre6: Cleanup GREv6 receive path, call common GRE functions
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
  2016-04-30  0:12 ` [PATCH next-next 1/7] ipv6: Cleanup IPv6 tunnel receive path Tom Herbert
  2016-04-30  0:12 ` [PATCH next-next 2/7] gre: Move utility functions to common headers Tom Herbert
@ 2016-04-30  0:12 ` Tom Herbert
  2016-04-30  0:12 ` [PATCH next-next 4/7] ipv6: Create ip6_tnl_xmit Tom Herbert
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Tom Herbert @ 2016-04-30  0:12 UTC (permalink / raw)
  To: davem, netdev; +Cc: kernel-team

  - Create gre_rcv function. This calls gre_parse_header and ip6gre_rcv.
  - Call ip6_tnl_rcv. Doing this and using gre_parse_header eliminates
    most of the code in ip6gre_rcv.

Signed-off-by: Tom Herbert <tom@herbertland.com>
---
 net/ipv6/ip6_gre.c | 140 +++++++++--------------------------------------------
 1 file changed, 23 insertions(+), 117 deletions(-)

diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index ca5a2c5..9b33745 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -54,6 +54,7 @@
 #include <net/ip6_fib.h>
 #include <net/ip6_route.h>
 #include <net/ip6_tunnel.h>
+#include <net/gre.h>
 
 
 static bool log_ecn_error = true;
@@ -443,137 +444,40 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	t->err_time = jiffies;
 }
 
-static int ip6gre_rcv(struct sk_buff *skb)
+static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
 {
 	const struct ipv6hdr *ipv6h;
-	u8     *h;
-	__be16    flags;
-	__sum16   csum = 0;
-	__be32 key = 0;
-	u32    seqno = 0;
 	struct ip6_tnl *tunnel;
-	int    offset = 4;
-	__be16 gre_proto;
-	int err;
-
-	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
-		goto drop;
 
 	ipv6h = ipv6_hdr(skb);
-	h = skb->data;
-	flags = *(__be16 *)h;
-
-	if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
-		/* - Version must be 0.
-		   - We do not support routing headers.
-		 */
-		if (flags&(GRE_VERSION|GRE_ROUTING))
-			goto drop;
-
-		if (flags&GRE_CSUM) {
-			csum = skb_checksum_simple_validate(skb);
-			offset += 4;
-		}
-		if (flags&GRE_KEY) {
-			key = *(__be32 *)(h + offset);
-			offset += 4;
-		}
-		if (flags&GRE_SEQ) {
-			seqno = ntohl(*(__be32 *)(h + offset));
-			offset += 4;
-		}
-	}
-
-	gre_proto = *(__be16 *)(h + 2);
-
 	tunnel = ip6gre_tunnel_lookup(skb->dev,
-					  &ipv6h->saddr, &ipv6h->daddr, key,
-					  gre_proto);
+				      &ipv6h->saddr, &ipv6h->daddr, tpi->key,
+				      tpi->proto);
 	if (tunnel) {
-		struct pcpu_sw_netstats *tstats;
-
-		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
-			goto drop;
-
-		if (!ip6_tnl_rcv_ctl(tunnel, &ipv6h->daddr, &ipv6h->saddr)) {
-			tunnel->dev->stats.rx_dropped++;
-			goto drop;
-		}
-
-		skb->protocol = gre_proto;
-		/* WCCP version 1 and 2 protocol decoding.
-		 * - Change protocol to IPv6
-		 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
-		 */
-		if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
-			skb->protocol = htons(ETH_P_IPV6);
-			if ((*(h + offset) & 0xF0) != 0x40)
-				offset += 4;
-		}
+		ip6_tnl_rcv(tunnel, skb, tpi, NULL, false);
 
-		skb->mac_header = skb->network_header;
-		__pskb_pull(skb, offset);
-		skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
-
-		if (((flags&GRE_CSUM) && csum) ||
-		    (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
-			tunnel->dev->stats.rx_crc_errors++;
-			tunnel->dev->stats.rx_errors++;
-			goto drop;
-		}
-		if (tunnel->parms.i_flags&GRE_SEQ) {
-			if (!(flags&GRE_SEQ) ||
-			    (tunnel->i_seqno &&
-					(s32)(seqno - tunnel->i_seqno) < 0)) {
-				tunnel->dev->stats.rx_fifo_errors++;
-				tunnel->dev->stats.rx_errors++;
-				goto drop;
-			}
-			tunnel->i_seqno = seqno + 1;
-		}
-
-		/* Warning: All skb pointers will be invalidated! */
-		if (tunnel->dev->type == ARPHRD_ETHER) {
-			if (!pskb_may_pull(skb, ETH_HLEN)) {
-				tunnel->dev->stats.rx_length_errors++;
-				tunnel->dev->stats.rx_errors++;
-				goto drop;
-			}
-
-			ipv6h = ipv6_hdr(skb);
-			skb->protocol = eth_type_trans(skb, tunnel->dev);
-			skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
-		}
-
-		__skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
+		return PACKET_RCVD;
+	}
 
-		skb_reset_network_header(skb);
+	return PACKET_REJECT;
+}
 
-		err = IP6_ECN_decapsulate(ipv6h, skb);
-		if (unlikely(err)) {
-			if (log_ecn_error)
-				net_info_ratelimited("non-ECT from %pI6 with dsfield=%#x\n",
-						     &ipv6h->saddr,
-						     ipv6_get_dsfield(ipv6h));
-			if (err > 1) {
-				++tunnel->dev->stats.rx_frame_errors;
-				++tunnel->dev->stats.rx_errors;
-				goto drop;
-			}
-		}
+static int gre_rcv(struct sk_buff *skb)
+{
+	struct tnl_ptk_info tpi;
+	bool csum_err = false;
+	int hdr_len;
 
-		tstats = this_cpu_ptr(tunnel->dev->tstats);
-		u64_stats_update_begin(&tstats->syncp);
-		tstats->rx_packets++;
-		tstats->rx_bytes += skb->len;
-		u64_stats_update_end(&tstats->syncp);
+	if (gre_parse_header(skb, &tpi, &csum_err, &hdr_len) < 0)
+		goto drop;
 
-		netif_rx(skb);
+	if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
+		goto drop;
 
+	if (ip6gre_rcv(skb, &tpi) == PACKET_RCVD)
 		return 0;
-	}
-	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
 
+	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
 drop:
 	kfree_skb(skb);
 	return 0;
@@ -1075,6 +979,8 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev,
 	struct net *net = t->net;
 	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
 
+	memset(&p1, 0, sizeof(p1));
+
 	switch (cmd) {
 	case SIOCGETTUNNEL:
 		if (dev == ign->fb_tunnel_dev) {
@@ -1318,7 +1224,7 @@ static void ip6gre_fb_tunnel_init(struct net_device *dev)
 
 
 static struct inet6_protocol ip6gre_protocol __read_mostly = {
-	.handler     = ip6gre_rcv,
+	.handler     = gre_rcv,
 	.err_handler = ip6gre_err,
 	.flags       = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
-- 
2.8.0.rc2

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

* [PATCH next-next 4/7] ipv6: Create ip6_tnl_xmit
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
                   ` (2 preceding siblings ...)
  2016-04-30  0:12 ` [PATCH next-next 3/7] gre6: Cleanup GREv6 receive path, call common GRE functions Tom Herbert
@ 2016-04-30  0:12 ` Tom Herbert
  2016-04-30  0:12 ` [PATCH next-next 5/7] gre: Create common functions for transmit Tom Herbert
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Tom Herbert @ 2016-04-30  0:12 UTC (permalink / raw)
  To: davem, netdev; +Cc: kernel-team

This patch renames ip6_tnl_xmit2 to ip6_tnl_xmit and exports it. Other
users like GRE will be able to call this. The original ip6_tnl_xmit
function is renamed to ip6_tnl_start_xmit (this is an ndo_start_xmit
function).

Signed-off-by: Tom Herbert <tom@herbertland.com>
---
 include/net/ip6_tunnel.h |  2 ++
 net/ipv6/ip6_tunnel.c    | 47 ++++++++++++++++++++++++++++++-----------------
 2 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index eab3a9b..835491b 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -69,6 +69,8 @@ int ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
 		bool log_ecn_error);
 int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
 		     const struct in6_addr *raddr);
+int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
+		 struct flowi6 *fl6, int encap_limit, __u32 *pmtu, __u8 proto);
 __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
 __u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
 			     const struct in6_addr *raddr);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 94ed065..b1f31d2 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -979,13 +979,14 @@ int ip6_tnl_xmit_ctl(struct ip6_tnl *t,
 EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
 
 /**
- * ip6_tnl_xmit2 - encapsulate packet and send
+ * ip6_tnl_xmit - encapsulate packet and send
  *   @skb: the outgoing socket buffer
  *   @dev: the outgoing tunnel device
  *   @dsfield: dscp code for outer header
- *   @fl: flow of tunneled packet
+ *   @fl6: flow of tunneled packet
  *   @encap_limit: encapsulation limit
  *   @pmtu: Path MTU is stored if packet is too big
+ *   @proto: next header value
  *
  * Description:
  *   Build new header and do some sanity checks on the packet before sending
@@ -997,12 +998,9 @@ EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
  *   %-EMSGSIZE message too big. return mtu in this case.
  **/
 
-static int ip6_tnl_xmit2(struct sk_buff *skb,
-			 struct net_device *dev,
-			 __u8 dsfield,
-			 struct flowi6 *fl6,
-			 int encap_limit,
-			 __u32 *pmtu)
+int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
+		 struct flowi6 *fl6, int encap_limit, __u32 *pmtu,
+		 __u8 proto)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
 	struct net *net = t->net;
@@ -1013,7 +1011,6 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 	struct net_device *tdev;
 	int mtu;
 	unsigned int max_headroom = sizeof(struct ipv6hdr);
-	u8 proto;
 	int err = -1;
 
 	/* NBMA tunnel */
@@ -1075,12 +1072,23 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 		mtu = IPV6_MIN_MTU;
 	if (skb_dst(skb))
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
-	if (skb->len > mtu) {
+	if (skb->len > mtu && !skb_is_gso(skb)) {
 		*pmtu = mtu;
 		err = -EMSGSIZE;
 		goto tx_err_dst_release;
 	}
 
+	if (t->err_count > 0) {
+		if (time_before(jiffies,
+				t->err_time + IP6TUNNEL_ERR_TIMEO)) {
+			t->err_count--;
+
+			dst_link_failure(skb);
+		} else {
+			t->err_count = 0;
+		}
+	}
+
 	skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
 
 	/*
@@ -1108,7 +1116,6 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 
 	skb->transport_header = skb->network_header;
 
-	proto = fl6->flowi6_proto;
 	if (encap_limit >= 0) {
 		init_tel_txopt(&opt, encap_limit);
 		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
@@ -1119,6 +1126,11 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 		skb->encapsulation = 1;
 	}
 
+	max_headroom = LL_RESERVED_SPACE(dst->dev) + sizeof(struct ipv6hdr)
+			+ dst->header_len;
+	if (max_headroom > dev->needed_headroom)
+		dev->needed_headroom = max_headroom;
+
 	skb_push(skb, sizeof(struct ipv6hdr));
 	skb_reset_network_header(skb);
 	ipv6h = ipv6_hdr(skb);
@@ -1137,6 +1149,7 @@ tx_err_dst_release:
 	dst_release(dst);
 	return err;
 }
+EXPORT_SYMBOL(ip6_tnl_xmit);
 
 static inline int
 ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -1160,7 +1173,6 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 		encap_limit = t->parms.encap_limit;
 
 	memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
-	fl6.flowi6_proto = IPPROTO_IPIP;
 
 	dsfield = ipv4_get_dsfield(iph);
 
@@ -1170,7 +1182,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
 		fl6.flowi6_mark = skb->mark;
 
-	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+	err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
+			   IPPROTO_IPIP);
 	if (err != 0) {
 		/* XXX: send ICMP error even if DF is not set. */
 		if (err == -EMSGSIZE)
@@ -1214,7 +1227,6 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 		encap_limit = t->parms.encap_limit;
 
 	memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
-	fl6.flowi6_proto = IPPROTO_IPV6;
 
 	dsfield = ipv6_get_dsfield(ipv6h);
 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
@@ -1224,7 +1236,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
 		fl6.flowi6_mark = skb->mark;
 
-	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+	err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
+			   IPPROTO_IPV6);
 	if (err != 0) {
 		if (err == -EMSGSIZE)
 			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -1235,7 +1248,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 }
 
 static netdev_tx_t
-ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
 	struct net_device_stats *stats = &t->dev->stats;
@@ -1556,7 +1569,7 @@ EXPORT_SYMBOL(ip6_tnl_get_iflink);
 static const struct net_device_ops ip6_tnl_netdev_ops = {
 	.ndo_init	= ip6_tnl_dev_init,
 	.ndo_uninit	= ip6_tnl_dev_uninit,
-	.ndo_start_xmit = ip6_tnl_xmit,
+	.ndo_start_xmit = ip6_tnl_start_xmit,
 	.ndo_do_ioctl	= ip6_tnl_ioctl,
 	.ndo_change_mtu = ip6_tnl_change_mtu,
 	.ndo_get_stats	= ip6_get_stats,
-- 
2.8.0.rc2

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

* [PATCH next-next 5/7] gre: Create common functions for transmit
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
                   ` (3 preceding siblings ...)
  2016-04-30  0:12 ` [PATCH next-next 4/7] ipv6: Create ip6_tnl_xmit Tom Herbert
@ 2016-04-30  0:12 ` Tom Herbert
  2016-04-30  0:12 ` [PATCH net-next 6/7] ipv6: Generic tunnel cleanup Tom Herbert
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Tom Herbert @ 2016-04-30  0:12 UTC (permalink / raw)
  To: davem, netdev; +Cc: kernel-team

Create common functions for both IPv4 and IPv6 GRE in transmit. These
are put into gre.h.

Common functions are for:
  - GRE checksum calculation. Move gre_checksum to gre.h.
  - Building a GRE header. Move GRE build_header and rename
    gre_build_header.

Signed-off-by: Tom Herbert <tom@herbertland.com>
---
 include/net/gre.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/ip_gre.c | 52 +++++-----------------------------------------------
 2 files changed, 49 insertions(+), 47 deletions(-)

diff --git a/include/net/gre.h b/include/net/gre.h
index 3959158..29e3732 100644
--- a/include/net/gre.h
+++ b/include/net/gre.h
@@ -85,4 +85,48 @@ static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags)
 	return flags;
 }
 
+static inline __sum16 gre_checksum(struct sk_buff *skb)
+{
+	__wsum csum;
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL)
+		csum = lco_csum(skb);
+	else
+		csum = skb_checksum(skb, 0, skb->len, 0);
+	return csum_fold(csum);
+}
+
+static inline void gre_build_header(struct sk_buff *skb, int hdr_len,
+				    __be16 flags, __be16 proto,
+				    __be32 key, __be32 seq)
+{
+	struct gre_base_hdr *greh;
+
+	skb_push(skb, hdr_len);
+
+	skb_reset_transport_header(skb);
+	greh = (struct gre_base_hdr *)skb->data;
+	greh->flags = gre_tnl_flags_to_gre_flags(flags);
+	greh->protocol = proto;
+
+	if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
+		__be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
+
+		if (flags & TUNNEL_SEQ) {
+			*ptr = seq;
+			ptr--;
+		}
+		if (flags & TUNNEL_KEY) {
+			*ptr = key;
+			ptr--;
+		}
+		if (flags & TUNNEL_CSUM &&
+		    !(skb_shinfo(skb)->gso_type &
+		      (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
+			*ptr = 0;
+			*(__sum16 *)ptr = gre_checksum(skb);
+		}
+	}
+}
+
 #endif
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index f6db3d6..2480d79 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -329,49 +329,6 @@ drop:
 	return 0;
 }
 
-static __sum16 gre_checksum(struct sk_buff *skb)
-{
-	__wsum csum;
-
-	if (skb->ip_summed == CHECKSUM_PARTIAL)
-		csum = lco_csum(skb);
-	else
-		csum = skb_checksum(skb, 0, skb->len, 0);
-	return csum_fold(csum);
-}
-
-static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags,
-			 __be16 proto, __be32 key, __be32 seq)
-{
-	struct gre_base_hdr *greh;
-
-	skb_push(skb, hdr_len);
-
-	skb_reset_transport_header(skb);
-	greh = (struct gre_base_hdr *)skb->data;
-	greh->flags = gre_tnl_flags_to_gre_flags(flags);
-	greh->protocol = proto;
-
-	if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
-		__be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
-
-		if (flags & TUNNEL_SEQ) {
-			*ptr = seq;
-			ptr--;
-		}
-		if (flags & TUNNEL_KEY) {
-			*ptr = key;
-			ptr--;
-		}
-		if (flags & TUNNEL_CSUM &&
-		    !(skb_shinfo(skb)->gso_type &
-		      (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
-			*ptr = 0;
-			*(__sum16 *)ptr = gre_checksum(skb);
-		}
-	}
-}
-
 static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
 		       const struct iphdr *tnl_params,
 		       __be16 proto)
@@ -382,8 +339,9 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
 		tunnel->o_seqno++;
 
 	/* Push GRE header. */
-	build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
-		     proto, tunnel->parms.o_key, htonl(tunnel->o_seqno));
+	gre_build_header(skb, tunnel->tun_hlen,
+			 tunnel->parms.o_flags, proto, tunnel->parms.o_key,
+			 htonl(tunnel->o_seqno));
 
 	skb_set_inner_protocol(skb, proto);
 	ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
@@ -460,8 +418,8 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
 		goto err_free_rt;
 
 	flags = tun_info->key.tun_flags & (TUNNEL_CSUM | TUNNEL_KEY);
-	build_header(skb, tunnel_hlen, flags, htons(ETH_P_TEB),
-		     tunnel_id_to_key(tun_info->key.tun_id), 0);
+	gre_build_header(skb, tunnel_hlen, flags, htons(ETH_P_TEB),
+			 tunnel_id_to_key(tun_info->key.tun_id), 0);
 
 	df = key->tun_flags & TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
 
-- 
2.8.0.rc2

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

* [PATCH net-next 6/7] ipv6: Generic tunnel cleanup
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
                   ` (4 preceding siblings ...)
  2016-04-30  0:12 ` [PATCH next-next 5/7] gre: Create common functions for transmit Tom Herbert
@ 2016-04-30  0:12 ` Tom Herbert
  2016-04-30  0:12 ` [PATCH next-next 7/7] gre6: Cleanup GREv6 transmit path, call common GRE functions Tom Herbert
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Tom Herbert @ 2016-04-30  0:12 UTC (permalink / raw)
  To: davem, netdev; +Cc: kernel-team

A few generic changes to generalize tunnels in IPv6:
  - Export ip6_tnl_change_mtu so that it can be called by ip6_gre
  - Add tun_hlen to ip6_tnl structure.

Signed-off-by: Tom Herbert <tom@herbertland.com>
---
 include/net/ip6_tunnel.h | 5 ++++-
 net/ipv6/ip6_tunnel.c    | 7 +++++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index 835491b..fb9e015 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -50,8 +50,10 @@ struct ip6_tnl {
 	/* These fields used only by GRE */
 	__u32 i_seqno;	/* The last seen seqno	*/
 	__u32 o_seqno;	/* The last output seqno */
-	int hlen;       /* Precalculated GRE header length */
+	int hlen;       /* tun_hlen + encap_hlen */
+	int tun_hlen;	/* Precalculated header length */
 	int mlink;
+
 };
 
 /* Tunnel encapsulation limit destination sub-option */
@@ -76,6 +78,7 @@ __u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
 			     const struct in6_addr *raddr);
 struct net *ip6_tnl_get_link_net(const struct net_device *dev);
 int ip6_tnl_get_iflink(const struct net_device *dev);
+int ip6_tnl_change_mtu(struct net_device *dev, int new_mtu);
 
 #ifdef CONFIG_INET
 static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index b1f31d2..ade55af 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1540,8 +1540,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  *   %-EINVAL if mtu too small
  **/
 
-static int
-ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
+int ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct ip6_tnl *tnl = netdev_priv(dev);
 
@@ -1557,6 +1556,7 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
 	dev->mtu = new_mtu;
 	return 0;
 }
+EXPORT_SYMBOL(ip6_tnl_change_mtu);
 
 int ip6_tnl_get_iflink(const struct net_device *dev)
 {
@@ -1632,6 +1632,9 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
 	if (ret)
 		goto destroy_dst;
 
+	t->hlen = 0;
+	t->tun_hlen = 0;
+
 	return 0;
 
 destroy_dst:
-- 
2.8.0.rc2

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

* [PATCH next-next 7/7] gre6: Cleanup GREv6 transmit path, call common GRE functions
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
                   ` (5 preceding siblings ...)
  2016-04-30  0:12 ` [PATCH net-next 6/7] ipv6: Generic tunnel cleanup Tom Herbert
@ 2016-04-30  0:12 ` Tom Herbert
  2016-04-30  1:00 ` [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Alexander Duyck
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Tom Herbert @ 2016-04-30  0:12 UTC (permalink / raw)
  To: davem, netdev; +Cc: kernel-team

Changes in GREv6 transmit path:
  - Call gre_checksum, remove gre6_checksum
  - Rename ip6gre_xmit2 to __gre6_xmit
  - Call gre_build_header utility function
  - Call ip6_tnl_xmit common function
  - Call ip6_tnl_change_mtu, eliminate ip6gre_tunnel_change_mtu

Signed-off-by: Tom Herbert <tom@herbertland.com>
---
 net/ipv6/ip6_gre.c | 252 +++++++++++------------------------------------------
 1 file changed, 50 insertions(+), 202 deletions(-)

diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 9b33745..1012774 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -488,199 +488,40 @@ struct ipv6_tel_txoption {
 	__u8 dst_opt[8];
 };
 
-static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit)
+static int gre_handle_offloads(struct sk_buff *skb, bool csum)
 {
-	memset(opt, 0, sizeof(struct ipv6_tel_txoption));
-
-	opt->dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT;
-	opt->dst_opt[3] = 1;
-	opt->dst_opt[4] = encap_limit;
-	opt->dst_opt[5] = IPV6_TLV_PADN;
-	opt->dst_opt[6] = 1;
-
-	opt->ops.dst0opt = (struct ipv6_opt_hdr *) opt->dst_opt;
-	opt->ops.opt_nflen = 8;
+	return iptunnel_handle_offloads(skb,
+					csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
 }
 
-static __sum16 gre6_checksum(struct sk_buff *skb)
-{
-	__wsum csum;
-
-	if (skb->ip_summed == CHECKSUM_PARTIAL)
-		csum = lco_csum(skb);
-	else
-		csum = skb_checksum(skb, sizeof(struct ipv6hdr),
-				    skb->len - sizeof(struct ipv6hdr), 0);
-	return csum_fold(csum);
-}
-
-static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
-			 struct net_device *dev,
-			 __u8 dsfield,
-			 struct flowi6 *fl6,
-			 int encap_limit,
-			 __u32 *pmtu)
+static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
+			       struct net_device *dev, __u8 dsfield,
+			       struct flowi6 *fl6, int encap_limit,
+			       __u32 *pmtu, __be16 proto)
 {
 	struct ip6_tnl *tunnel = netdev_priv(dev);
-	struct net *net = tunnel->net;
-	struct net_device *tdev;    /* Device to other host */
-	struct ipv6hdr  *ipv6h;     /* Our new IP header */
-	unsigned int min_headroom = 0; /* The extra header space needed */
-	int    gre_hlen;
-	struct ipv6_tel_txoption opt;
-	int    mtu;
-	struct dst_entry *dst = NULL, *ndst = NULL;
-	struct net_device_stats *stats = &tunnel->dev->stats;
-	int err = -1;
-	u8 proto;
-	__be16 protocol;
+	__be16 protocol = (dev->type == ARPHRD_ETHER) ?
+			  htons(ETH_P_TEB) : proto;
 
 	if (dev->type == ARPHRD_ETHER)
 		IPCB(skb)->flags = 0;
 
-	if (dev->header_ops && dev->type == ARPHRD_IP6GRE) {
-		gre_hlen = 0;
-		ipv6h = (struct ipv6hdr *)skb->data;
-		fl6->daddr = ipv6h->daddr;
-	} else {
-		gre_hlen = tunnel->hlen;
+	if (dev->header_ops && dev->type == ARPHRD_IP6GRE)
+		fl6->daddr = ((struct ipv6hdr *)skb->data)->daddr;
+	else
 		fl6->daddr = tunnel->parms.raddr;
-	}
-
-	if (!fl6->flowi6_mark)
-		dst = dst_cache_get(&tunnel->dst_cache);
-
-	if (!dst) {
-		dst = ip6_route_output(net, NULL, fl6);
-
-		if (dst->error)
-			goto tx_err_link_failure;
-		dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
-		if (IS_ERR(dst)) {
-			err = PTR_ERR(dst);
-			dst = NULL;
-			goto tx_err_link_failure;
-		}
-		ndst = dst;
-	}
-
-	tdev = dst->dev;
-
-	if (tdev == dev) {
-		stats->collisions++;
-		net_warn_ratelimited("%s: Local routing loop detected!\n",
-				     tunnel->parms.name);
-		goto tx_err_dst_release;
-	}
 
-	mtu = dst_mtu(dst) - sizeof(*ipv6h);
-	if (encap_limit >= 0) {
-		min_headroom += 8;
-		mtu -= 8;
-	}
-	if (mtu < IPV6_MIN_MTU)
-		mtu = IPV6_MIN_MTU;
-	if (skb_dst(skb))
-		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
-	if (skb->len > mtu && !skb_is_gso(skb)) {
-		*pmtu = mtu;
-		err = -EMSGSIZE;
-		goto tx_err_dst_release;
-	}
+	if (tunnel->parms.o_flags & TUNNEL_SEQ)
+		tunnel->o_seqno++;
 
-	if (tunnel->err_count > 0) {
-		if (time_before(jiffies,
-				tunnel->err_time + IP6TUNNEL_ERR_TIMEO)) {
-			tunnel->err_count--;
+	/* Push GRE header. */
+	gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
+			 protocol, tunnel->parms.o_key, htonl(tunnel->o_seqno));
 
-			dst_link_failure(skb);
-		} else
-			tunnel->err_count = 0;
-	}
+	skb_set_inner_protocol(skb, proto);
 
-	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
-
-	min_headroom += LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
-
-	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
-		int head_delta = SKB_DATA_ALIGN(min_headroom -
-						skb_headroom(skb) +
-						16);
-
-		err = pskb_expand_head(skb, max_t(int, head_delta, 0),
-				       0, GFP_ATOMIC);
-		if (min_headroom > dev->needed_headroom)
-			dev->needed_headroom = min_headroom;
-		if (unlikely(err))
-			goto tx_err_dst_release;
-	}
-
-	if (!fl6->flowi6_mark && ndst)
-		dst_cache_set_ip6(&tunnel->dst_cache, ndst, &fl6->saddr);
-	skb_dst_set(skb, dst);
-
-	proto = NEXTHDR_GRE;
-	if (encap_limit >= 0) {
-		init_tel_txopt(&opt, encap_limit);
-		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
-	}
-
-	err = iptunnel_handle_offloads(skb,
-				       (tunnel->parms.o_flags & GRE_CSUM) ?
-				       SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
-	if (err)
-		goto tx_err_dst_release;
-
-	skb_push(skb, gre_hlen);
-	skb_reset_network_header(skb);
-	skb_set_transport_header(skb, sizeof(*ipv6h));
-
-	/*
-	 *	Push down and install the IP header.
-	 */
-	ipv6h = ipv6_hdr(skb);
-	ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
-		     ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
-	ipv6h->hop_limit = tunnel->parms.hop_limit;
-	ipv6h->nexthdr = proto;
-	ipv6h->saddr = fl6->saddr;
-	ipv6h->daddr = fl6->daddr;
-
-	((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags;
-	protocol = (dev->type == ARPHRD_ETHER) ?
-		    htons(ETH_P_TEB) : skb->protocol;
-	((__be16 *)(ipv6h + 1))[1] = protocol;
-
-	if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
-		__be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4);
-
-		if (tunnel->parms.o_flags&GRE_SEQ) {
-			++tunnel->o_seqno;
-			*ptr = htonl(tunnel->o_seqno);
-			ptr--;
-		}
-		if (tunnel->parms.o_flags&GRE_KEY) {
-			*ptr = tunnel->parms.o_key;
-			ptr--;
-		}
-		if ((tunnel->parms.o_flags & GRE_CSUM) &&
-		    !(skb_shinfo(skb)->gso_type &
-		      (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
-			*ptr = 0;
-			*(__sum16 *)ptr = gre6_checksum(skb);
-		}
-	}
-
-	skb_set_inner_protocol(skb, protocol);
-
-	ip6tunnel_xmit(NULL, skb, dev);
-	return 0;
-tx_err_link_failure:
-	stats->tx_carrier_errors++;
-	dst_link_failure(skb);
-tx_err_dst_release:
-	dst_release(dst);
-	return err;
+	return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu,
+			    NEXTHDR_GRE);
 }
 
 static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
@@ -699,7 +540,6 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
 		encap_limit = t->parms.encap_limit;
 
 	memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
-	fl6.flowi6_proto = IPPROTO_GRE;
 
 	dsfield = ipv4_get_dsfield(iph);
 
@@ -709,7 +549,12 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
 		fl6.flowi6_mark = skb->mark;
 
-	err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+	err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
+	if (err)
+		return -1;
+
+	err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
+			  skb->protocol);
 	if (err != 0) {
 		/* XXX: send ICMP error even if DF is not set. */
 		if (err == -EMSGSIZE)
@@ -749,7 +594,6 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
 		encap_limit = t->parms.encap_limit;
 
 	memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
-	fl6.flowi6_proto = IPPROTO_GRE;
 
 	dsfield = ipv6_get_dsfield(ipv6h);
 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
@@ -759,7 +603,11 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
 		fl6.flowi6_mark = skb->mark;
 
-	err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+	if (gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM)))
+		return -1;
+
+	err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit,
+			  &mtu, skb->protocol);
 	if (err != 0) {
 		if (err == -EMSGSIZE)
 			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -803,7 +651,11 @@ static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev)
 	memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
 	fl6.flowi6_proto = skb->protocol;
 
-	err = ip6gre_xmit2(skb, dev, 0, &fl6, encap_limit, &mtu);
+	err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
+	if (err)
+		return err;
+
+	err = __gre6_xmit(skb, dev, 0, &fl6, encap_limit, &mtu, skb->protocol);
 
 	return err;
 }
@@ -1080,15 +932,6 @@ done:
 	return err;
 }
 
-static int ip6gre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if (new_mtu < 68 ||
-	    new_mtu > 0xFFF8 - dev->hard_header_len)
-		return -EINVAL;
-	dev->mtu = new_mtu;
-	return 0;
-}
-
 static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
 			unsigned short type,
 			const void *daddr, const void *saddr, unsigned int len)
@@ -1132,7 +975,7 @@ static const struct net_device_ops ip6gre_netdev_ops = {
 	.ndo_uninit		= ip6gre_tunnel_uninit,
 	.ndo_start_xmit		= ip6gre_tunnel_xmit,
 	.ndo_do_ioctl		= ip6gre_tunnel_ioctl,
-	.ndo_change_mtu		= ip6gre_tunnel_change_mtu,
+	.ndo_change_mtu		= ip6_tnl_change_mtu,
 	.ndo_get_stats64	= ip_tunnel_get_stats64,
 	.ndo_get_iflink		= ip6_tnl_get_iflink,
 };
@@ -1148,17 +991,11 @@ static void ip6gre_dev_free(struct net_device *dev)
 
 static void ip6gre_tunnel_setup(struct net_device *dev)
 {
-	struct ip6_tnl *t;
-
 	dev->netdev_ops = &ip6gre_netdev_ops;
 	dev->destructor = ip6gre_dev_free;
 
 	dev->type = ARPHRD_IP6GRE;
-	dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr) + 4;
-	dev->mtu = ETH_DATA_LEN - sizeof(struct ipv6hdr) - 4;
-	t = netdev_priv(dev);
-	if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
-		dev->mtu -= 8;
+
 	dev->flags |= IFF_NOARP;
 	dev->addr_len = sizeof(struct in6_addr);
 	netif_keep_dst(dev);
@@ -1168,6 +1005,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
 {
 	struct ip6_tnl *tunnel;
 	int ret;
+	int t_hlen;
 
 	tunnel = netdev_priv(dev);
 
@@ -1186,6 +1024,16 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
 		return ret;
 	}
 
+	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
+
+	t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
+
+	dev->needed_headroom	= LL_MAX_HEADER + t_hlen + 4;
+	dev->mtu		= ETH_DATA_LEN - t_hlen - 4;
+
+	if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+		dev->mtu -= 8;
+
 	return 0;
 }
 
@@ -1420,7 +1268,7 @@ static const struct net_device_ops ip6gre_tap_netdev_ops = {
 	.ndo_start_xmit = ip6gre_tunnel_xmit,
 	.ndo_set_mac_address = eth_mac_addr,
 	.ndo_validate_addr = eth_validate_addr,
-	.ndo_change_mtu = ip6gre_tunnel_change_mtu,
+	.ndo_change_mtu = ip6_tnl_change_mtu,
 	.ndo_get_stats64 = ip_tunnel_get_stats64,
 	.ndo_get_iflink = ip6_tnl_get_iflink,
 };
-- 
2.8.0.rc2

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

* Re: [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
                   ` (6 preceding siblings ...)
  2016-04-30  0:12 ` [PATCH next-next 7/7] gre6: Cleanup GREv6 transmit path, call common GRE functions Tom Herbert
@ 2016-04-30  1:00 ` Alexander Duyck
  2016-05-02 19:32   ` Tom Herbert
  2016-05-02 23:23 ` David Miller
  2016-05-03  2:03 ` Alexander Duyck
  9 siblings, 1 reply; 17+ messages in thread
From: Alexander Duyck @ 2016-04-30  1:00 UTC (permalink / raw)
  To: Tom Herbert; +Cc: David Miller, Netdev, Kernel Team

On Fri, Apr 29, 2016 at 5:12 PM, Tom Herbert <tom@herbertland.com> wrote:
> The IPv6 tunnel code is very different from IPv4 code. There is a lot
> of redundancy with the IPv4 code, particularly in the GRE tunneling.
>
> This patch set cleans up the tunnel code to make the IPv6 code look
> more like the IPv4 code and use common functions between the two
> stacks where possible.
>
> This work should make it easier to maintain and extend the IPv6 ip
> tunnels.
>
> Items in this patch set:
>   - Cleanup IPv6 tunnel receive path (ip6_tnl_rcv). Includes using
>     gro_cells and exporting ip6_tnl_rcv so the ip6_gre can call it
>   - Move GRE functions to common header file (tx functions) or
>     gre_demux.c (rx functions like gre_parse_header)
>   - Call common GRE functions from IPv6 GRE
>   - Create ip6_tnl_xmit (to be like ip_tunnel_xmit)
>
> Tested:
>   Ran super_netperf tests for TCP_RR and TCP_STREAM for:
>     - IPv4 over gre, gretap, gre6, gre6tap
>     - IPv6 over gre, gretap, gre6, gre6tap
>     - ipip
>     - ip6ip6
>     - ipip/gue
>     - IPv6 over gre/gue
>     - IPv4 over gre/gue

You should probably add 2 additional test cases.  One for IPv4 GRE/GUE
w/ checksum on the GRE header, and same for IPv6.  It was broken
previously in terms of offloads so we need to make sure we don't
introduce a regression and break it again.

> Tom Herbert (7):
>   ipv6: Cleanup IPv6 tunnel receive path
>   gre: Move utility functions to common headers
>   gre6: Cleanup GREv6 receive path, call common GRE functions
>   ipv6: Create ip6_tnl_xmit
>   gre: Create common functions for transmit
>   ipv6: Generic tunnel cleanup
>   gre6: Cleanup GREv6 transmit path, call common GRE functions
>
>  include/net/gre.h        | 104 +++++++++++++
>  include/net/ip6_tunnel.h |  11 +-
>  net/ipv4/gre_demux.c     |  64 ++++++++
>  net/ipv4/ip_gre.c        | 199 +++---------------------
>  net/ipv6/ip6_gre.c       | 392 +++++++++--------------------------------------
>  net/ipv6/ip6_tunnel.c    | 266 +++++++++++++++++++++-----------
>  6 files changed, 452 insertions(+), 584 deletions(-)
>
> --
> 2.8.0.rc2
>

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

* Re: [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels
  2016-04-30  1:00 ` [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Alexander Duyck
@ 2016-05-02 19:32   ` Tom Herbert
  2016-05-02 19:42     ` Alexander Duyck
  0 siblings, 1 reply; 17+ messages in thread
From: Tom Herbert @ 2016-05-02 19:32 UTC (permalink / raw)
  To: Alexander Duyck; +Cc: David Miller, Netdev, Kernel Team

On Fri, Apr 29, 2016 at 6:00 PM, Alexander Duyck
<alexander.duyck@gmail.com> wrote:
> On Fri, Apr 29, 2016 at 5:12 PM, Tom Herbert <tom@herbertland.com> wrote:
>> The IPv6 tunnel code is very different from IPv4 code. There is a lot
>> of redundancy with the IPv4 code, particularly in the GRE tunneling.
>>
>> This patch set cleans up the tunnel code to make the IPv6 code look
>> more like the IPv4 code and use common functions between the two
>> stacks where possible.
>>
>> This work should make it easier to maintain and extend the IPv6 ip
>> tunnels.
>>
>> Items in this patch set:
>>   - Cleanup IPv6 tunnel receive path (ip6_tnl_rcv). Includes using
>>     gro_cells and exporting ip6_tnl_rcv so the ip6_gre can call it
>>   - Move GRE functions to common header file (tx functions) or
>>     gre_demux.c (rx functions like gre_parse_header)
>>   - Call common GRE functions from IPv6 GRE
>>   - Create ip6_tnl_xmit (to be like ip_tunnel_xmit)
>>
>> Tested:
>>   Ran super_netperf tests for TCP_RR and TCP_STREAM for:
>>     - IPv4 over gre, gretap, gre6, gre6tap
>>     - IPv6 over gre, gretap, gre6, gre6tap
>>     - ipip
>>     - ip6ip6
>>     - ipip/gue
>>     - IPv6 over gre/gue
>>     - IPv4 over gre/gue
>
> You should probably add 2 additional test cases.  One for IPv4 GRE/GUE
> w/ checksum on the GRE header, and same for IPv6.  It was broken
> previously in terms of offloads so we need to make sure we don't
> introduce a regression and break it again.
>
Hi Alexander,

I did test GRE/GUE with checksum and remcsum for IPv4, that works okay.

Support for GUE with IPv6 is in the next patch set I am working on.

Thanks,
Tom

>> Tom Herbert (7):
>>   ipv6: Cleanup IPv6 tunnel receive path
>>   gre: Move utility functions to common headers
>>   gre6: Cleanup GREv6 receive path, call common GRE functions
>>   ipv6: Create ip6_tnl_xmit
>>   gre: Create common functions for transmit
>>   ipv6: Generic tunnel cleanup
>>   gre6: Cleanup GREv6 transmit path, call common GRE functions
>>
>>  include/net/gre.h        | 104 +++++++++++++
>>  include/net/ip6_tunnel.h |  11 +-
>>  net/ipv4/gre_demux.c     |  64 ++++++++
>>  net/ipv4/ip_gre.c        | 199 +++---------------------
>>  net/ipv6/ip6_gre.c       | 392 +++++++++--------------------------------------
>>  net/ipv6/ip6_tunnel.c    | 266 +++++++++++++++++++++-----------
>>  6 files changed, 452 insertions(+), 584 deletions(-)
>>
>> --
>> 2.8.0.rc2
>>

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

* Re: [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels
  2016-05-02 19:32   ` Tom Herbert
@ 2016-05-02 19:42     ` Alexander Duyck
  0 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2016-05-02 19:42 UTC (permalink / raw)
  To: Tom Herbert; +Cc: David Miller, Netdev, Kernel Team

On Mon, May 2, 2016 at 12:32 PM, Tom Herbert <tom@herbertland.com> wrote:
> On Fri, Apr 29, 2016 at 6:00 PM, Alexander Duyck
> <alexander.duyck@gmail.com> wrote:
>> On Fri, Apr 29, 2016 at 5:12 PM, Tom Herbert <tom@herbertland.com> wrote:
>>> The IPv6 tunnel code is very different from IPv4 code. There is a lot
>>> of redundancy with the IPv4 code, particularly in the GRE tunneling.
>>>
>>> This patch set cleans up the tunnel code to make the IPv6 code look
>>> more like the IPv4 code and use common functions between the two
>>> stacks where possible.
>>>
>>> This work should make it easier to maintain and extend the IPv6 ip
>>> tunnels.
>>>
>>> Items in this patch set:
>>>   - Cleanup IPv6 tunnel receive path (ip6_tnl_rcv). Includes using
>>>     gro_cells and exporting ip6_tnl_rcv so the ip6_gre can call it
>>>   - Move GRE functions to common header file (tx functions) or
>>>     gre_demux.c (rx functions like gre_parse_header)
>>>   - Call common GRE functions from IPv6 GRE
>>>   - Create ip6_tnl_xmit (to be like ip_tunnel_xmit)
>>>
>>> Tested:
>>>   Ran super_netperf tests for TCP_RR and TCP_STREAM for:
>>>     - IPv4 over gre, gretap, gre6, gre6tap
>>>     - IPv6 over gre, gretap, gre6, gre6tap
>>>     - ipip
>>>     - ip6ip6
>>>     - ipip/gue
>>>     - IPv6 over gre/gue
>>>     - IPv4 over gre/gue
>>
>> You should probably add 2 additional test cases.  One for IPv4 GRE/GUE
>> w/ checksum on the GRE header, and same for IPv6.  It was broken
>> previously in terms of offloads so we need to make sure we don't
>> introduce a regression and break it again.
>>
> Hi Alexander,
>
> I did test GRE/GUE with checksum and remcsum for IPv4, that works okay.
>
> Support for GUE with IPv6 is in the next patch set I am working on.
>
> Thanks,
> Tom

Just so it is clear I am talking about having a checksum in the GRE
header, not the GUE header.  If there is a GRE checksum present we
have to force software segmentation since we don't have any means of
pointing to the header in a way that is meaningful for hardware.  As
long as we don't see any regressions I am good with these changes.

Thanks.

- Alex

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

* Re: [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
                   ` (7 preceding siblings ...)
  2016-04-30  1:00 ` [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Alexander Duyck
@ 2016-05-02 23:23 ` David Miller
  2016-05-03  2:03 ` Alexander Duyck
  9 siblings, 0 replies; 17+ messages in thread
From: David Miller @ 2016-05-02 23:23 UTC (permalink / raw)
  To: tom; +Cc: netdev, kernel-team

From: Tom Herbert <tom@herbertland.com>
Date: Fri, 29 Apr 2016 17:12:14 -0700

> The IPv6 tunnel code is very different from IPv4 code. There is a lot
> of redundancy with the IPv4 code, particularly in the GRE tunneling.
> 
> This patch set cleans up the tunnel code to make the IPv6 code look
> more like the IPv4 code and use common functions between the two
> stacks where possible.

Series applied, nice work Tom.

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

* Re: [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels
  2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
                   ` (8 preceding siblings ...)
  2016-05-02 23:23 ` David Miller
@ 2016-05-03  2:03 ` Alexander Duyck
  9 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2016-05-03  2:03 UTC (permalink / raw)
  To: Tom Herbert; +Cc: David Miller, Netdev, Kernel Team

On Fri, Apr 29, 2016 at 5:12 PM, Tom Herbert <tom@herbertland.com> wrote:
> The IPv6 tunnel code is very different from IPv4 code. There is a lot
> of redundancy with the IPv4 code, particularly in the GRE tunneling.
>
> This patch set cleans up the tunnel code to make the IPv6 code look
> more like the IPv4 code and use common functions between the two
> stacks where possible.
>
> This work should make it easier to maintain and extend the IPv6 ip
> tunnels.
>
> Items in this patch set:
>   - Cleanup IPv6 tunnel receive path (ip6_tnl_rcv). Includes using
>     gro_cells and exporting ip6_tnl_rcv so the ip6_gre can call it
>   - Move GRE functions to common header file (tx functions) or
>     gre_demux.c (rx functions like gre_parse_header)
>   - Call common GRE functions from IPv6 GRE
>   - Create ip6_tnl_xmit (to be like ip_tunnel_xmit)
>
> Tested:
>   Ran super_netperf tests for TCP_RR and TCP_STREAM for:
>     - IPv4 over gre, gretap, gre6, gre6tap
>     - IPv6 over gre, gretap, gre6, gre6tap
>     - ipip
>     - ip6ip6
>     - ipip/gue
>     - IPv6 over gre/gue
>     - IPv4 over gre/gue
>
> Tom Herbert (7):
>   ipv6: Cleanup IPv6 tunnel receive path
>   gre: Move utility functions to common headers
>   gre6: Cleanup GREv6 receive path, call common GRE functions
>   ipv6: Create ip6_tnl_xmit
>   gre: Create common functions for transmit
>   ipv6: Generic tunnel cleanup
>   gre6: Cleanup GREv6 transmit path, call common GRE functions
>
>  include/net/gre.h        | 104 +++++++++++++
>  include/net/ip6_tunnel.h |  11 +-
>  net/ipv4/gre_demux.c     |  64 ++++++++
>  net/ipv4/ip_gre.c        | 199 +++---------------------
>  net/ipv6/ip6_gre.c       | 392 +++++++++--------------------------------------
>  net/ipv6/ip6_tunnel.c    | 266 +++++++++++++++++++++-----------
>  6 files changed, 452 insertions(+), 584 deletions(-)
>
> --
> 2.8.0.rc2
>

I was wondering if you have more work going on in this area or not?  I
ask because I was just going through and auditing the calls to
skb_reset_inner_headers and I think the only spot left that is calling
it without verifying that either GSO or CHECKSUM_PARTIAL is set is in
ip6_tnl_xmit.  If we can get that moved over to using
iptunnel_handle_offloads like the other functions then we should be
guaranteed that skb->encapsulation is only ever set if an offload is
requested, and that in turn guarantees that csum_start and
inner_transport_offset will always be the same value.

Thanks.

- Alex

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

* Re: [PATCH next-next 2/7] gre: Move utility functions to common headers
  2016-04-30  0:12 ` [PATCH next-next 2/7] gre: Move utility functions to common headers Tom Herbert
@ 2016-05-03 11:29   ` Jiri Benc
  2016-05-04  4:53     ` David Miller
  0 siblings, 1 reply; 17+ messages in thread
From: Jiri Benc @ 2016-05-03 11:29 UTC (permalink / raw)
  To: Tom Herbert; +Cc: davem, netdev, kernel-team

On Fri, 29 Apr 2016 17:12:16 -0700, Tom Herbert wrote:
>   - iptunnel_pull_header is taken out of gre_parse_header. This is now
>     done by caller. The header length is returned from gre_parse_header
>     in an int* argument.

Seems we conflicted here, I've done the same for net.git to fix ICMP
path. I made parse_gre_header return the length instead of adding the
parameter, as it's easier consumed that way (no need for an extra local
variable in gre_err).

How do we resolve the conflict between net and net-next? I'd prefer
gre_parse_header to return the header length. I can submit a patch for
net-next that does this; that would substantially ease the merge.

 Jiri

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

* Re: [PATCH next-next 2/7] gre: Move utility functions to common headers
  2016-05-03 11:29   ` Jiri Benc
@ 2016-05-04  4:53     ` David Miller
  2016-05-04  8:35       ` Jiri Benc
  0 siblings, 1 reply; 17+ messages in thread
From: David Miller @ 2016-05-04  4:53 UTC (permalink / raw)
  To: jbenc; +Cc: tom, netdev, kernel-team

From: Jiri Benc <jbenc@redhat.com>
Date: Tue, 3 May 2016 13:29:44 +0200

> How do we resolve the conflict between net and net-next? I'd prefer
> gre_parse_header to return the header length. I can submit a patch for
> net-next that does this; that would substantially ease the merge.

Jiri, I just did the net --> net-next merge.  Please send me something on
top of that which does what you like.

Thanks.

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

* Re: [PATCH next-next 2/7] gre: Move utility functions to common headers
  2016-05-04  4:53     ` David Miller
@ 2016-05-04  8:35       ` Jiri Benc
  2016-05-04 16:45         ` David Miller
  0 siblings, 1 reply; 17+ messages in thread
From: Jiri Benc @ 2016-05-04  8:35 UTC (permalink / raw)
  To: David Miller; +Cc: tom, netdev, kernel-team

On Wed, 04 May 2016 00:53:16 -0400 (EDT), David Miller wrote:
> From: Jiri Benc <jbenc@redhat.com>
> Date: Tue, 3 May 2016 13:29:44 +0200
> 
> > How do we resolve the conflict between net and net-next? I'd prefer
> > gre_parse_header to return the header length. I can submit a patch for
> > net-next that does this; that would substantially ease the merge.
> 
> Jiri, I just did the net --> net-next merge.  Please send me something on
> top of that which does what you like.

The patch http://patchwork.ozlabs.org/patch/617940/ still applies and
does the right thing even post merge.

Note that the merge reintroduced the bug fixed by b7f8fe251e46 (the
mentioned patch fixes this, too).

Thanks,

 Jiri

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

* Re: [PATCH next-next 2/7] gre: Move utility functions to common headers
  2016-05-04  8:35       ` Jiri Benc
@ 2016-05-04 16:45         ` David Miller
  0 siblings, 0 replies; 17+ messages in thread
From: David Miller @ 2016-05-04 16:45 UTC (permalink / raw)
  To: jbenc; +Cc: tom, netdev, kernel-team

From: Jiri Benc <jbenc@redhat.com>
Date: Wed, 4 May 2016 10:35:49 +0200

> On Wed, 04 May 2016 00:53:16 -0400 (EDT), David Miller wrote:
>> From: Jiri Benc <jbenc@redhat.com>
>> Date: Tue, 3 May 2016 13:29:44 +0200
>> 
>> > How do we resolve the conflict between net and net-next? I'd prefer
>> > gre_parse_header to return the header length. I can submit a patch for
>> > net-next that does this; that would substantially ease the merge.
>> 
>> Jiri, I just did the net --> net-next merge.  Please send me something on
>> top of that which does what you like.
> 
> The patch http://patchwork.ozlabs.org/patch/617940/ still applies and
> does the right thing even post merge.
> 
> Note that the merge reintroduced the bug fixed by b7f8fe251e46 (the
> mentioned patch fixes this, too).

Awesome, I'll use that, thanks Jiri.

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

end of thread, other threads:[~2016-05-04 16:45 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-30  0:12 [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Tom Herbert
2016-04-30  0:12 ` [PATCH next-next 1/7] ipv6: Cleanup IPv6 tunnel receive path Tom Herbert
2016-04-30  0:12 ` [PATCH next-next 2/7] gre: Move utility functions to common headers Tom Herbert
2016-05-03 11:29   ` Jiri Benc
2016-05-04  4:53     ` David Miller
2016-05-04  8:35       ` Jiri Benc
2016-05-04 16:45         ` David Miller
2016-04-30  0:12 ` [PATCH next-next 3/7] gre6: Cleanup GREv6 receive path, call common GRE functions Tom Herbert
2016-04-30  0:12 ` [PATCH next-next 4/7] ipv6: Create ip6_tnl_xmit Tom Herbert
2016-04-30  0:12 ` [PATCH next-next 5/7] gre: Create common functions for transmit Tom Herbert
2016-04-30  0:12 ` [PATCH net-next 6/7] ipv6: Generic tunnel cleanup Tom Herbert
2016-04-30  0:12 ` [PATCH next-next 7/7] gre6: Cleanup GREv6 transmit path, call common GRE functions Tom Herbert
2016-04-30  1:00 ` [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels Alexander Duyck
2016-05-02 19:32   ` Tom Herbert
2016-05-02 19:42     ` Alexander Duyck
2016-05-02 23:23 ` David Miller
2016-05-03  2:03 ` Alexander Duyck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).