aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Duyck <aduyck@mirantis.com>2016-04-05 12:13:39 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-07 16:56:33 -0400
commita0ca153f98db8cf25298565a09e11fe9d82846ad (patch)
tree5f7773cd6e2dbf30f3af97194a8b7d04b99fd1a0
parent0a1a37b6d62e6864a77a82e925217c720f91f963 (diff)
GRE: Disable segmentation offloads w/ CSUM and we are encapsulated via FOU
This patch fixes an issue I found in which we were dropping frames if we had enabled checksums on GRE headers that were encapsulated by either FOU or GUE. Without this patch I was barely able to get 1 Gb/s of throughput. With this patch applied I am now at least getting around 6 Gb/s. The issue is due to the fact that with FOU or GUE applied we do not provide a transport offset pointing to the GRE header, nor do we offload it in software as the GRE header is completely skipped by GSO and treated like a VXLAN or GENEVE type header. As such we need to prevent the stack from generating it and also prevent GRE from generating it via any interface we create. Fixes: c3483384ee511 ("gro: Allow tunnel stacking in the case of FOU/GUE") Signed-off-by: Alexander Duyck <aduyck@mirantis.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h5
-rw-r--r--net/core/dev.c1
-rw-r--r--net/ipv4/fou.c6
-rw-r--r--net/ipv4/gre_offload.c8
-rw-r--r--net/ipv4/ip_gre.c13
5 files changed, 29 insertions, 4 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index cb0d5d09c2e4..8395308a2445 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2120,7 +2120,10 @@ struct napi_gro_cb {
2120 /* Used in foo-over-udp, set in udp[46]_gro_receive */ 2120 /* Used in foo-over-udp, set in udp[46]_gro_receive */
2121 u8 is_ipv6:1; 2121 u8 is_ipv6:1;
2122 2122
2123 /* 7 bit hole */ 2123 /* Used in GRE, set in fou/gue_gro_receive */
2124 u8 is_fou:1;
2125
2126 /* 6 bit hole */
2124 2127
2125 /* used to support CHECKSUM_COMPLETE for tunneling protocols */ 2128 /* used to support CHECKSUM_COMPLETE for tunneling protocols */
2126 __wsum csum; 2129 __wsum csum;
diff --git a/net/core/dev.c b/net/core/dev.c
index b9bcbe77d913..77a71cd68535 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4439,6 +4439,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
4439 NAPI_GRO_CB(skb)->flush = 0; 4439 NAPI_GRO_CB(skb)->flush = 0;
4440 NAPI_GRO_CB(skb)->free = 0; 4440 NAPI_GRO_CB(skb)->free = 0;
4441 NAPI_GRO_CB(skb)->encap_mark = 0; 4441 NAPI_GRO_CB(skb)->encap_mark = 0;
4442 NAPI_GRO_CB(skb)->is_fou = 0;
4442 NAPI_GRO_CB(skb)->gro_remcsum_start = 0; 4443 NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
4443 4444
4444 /* Setup for GRO checksum validation */ 4445 /* Setup for GRO checksum validation */
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 5a94aea280d3..a39068b4a4d9 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -203,6 +203,9 @@ static struct sk_buff **fou_gro_receive(struct sk_buff **head,
203 */ 203 */
204 NAPI_GRO_CB(skb)->encap_mark = 0; 204 NAPI_GRO_CB(skb)->encap_mark = 0;
205 205
206 /* Flag this frame as already having an outer encap header */
207 NAPI_GRO_CB(skb)->is_fou = 1;
208
206 rcu_read_lock(); 209 rcu_read_lock();
207 offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; 210 offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
208 ops = rcu_dereference(offloads[proto]); 211 ops = rcu_dereference(offloads[proto]);
@@ -368,6 +371,9 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
368 */ 371 */
369 NAPI_GRO_CB(skb)->encap_mark = 0; 372 NAPI_GRO_CB(skb)->encap_mark = 0;
370 373
374 /* Flag this frame as already having an outer encap header */
375 NAPI_GRO_CB(skb)->is_fou = 1;
376
371 rcu_read_lock(); 377 rcu_read_lock();
372 offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; 378 offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
373 ops = rcu_dereference(offloads[guehdr->proto_ctype]); 379 ops = rcu_dereference(offloads[guehdr->proto_ctype]);
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
index c47539d04b88..6a5bd4317866 100644
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -150,6 +150,14 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
150 if ((greh->flags & ~(GRE_KEY|GRE_CSUM)) != 0) 150 if ((greh->flags & ~(GRE_KEY|GRE_CSUM)) != 0)
151 goto out; 151 goto out;
152 152
153 /* We can only support GRE_CSUM if we can track the location of
154 * the GRE header. In the case of FOU/GUE we cannot because the
155 * outer UDP header displaces the GRE header leaving us in a state
156 * of limbo.
157 */
158 if ((greh->flags & GRE_CSUM) && NAPI_GRO_CB(skb)->is_fou)
159 goto out;
160
153 type = greh->protocol; 161 type = greh->protocol;
154 162
155 rcu_read_lock(); 163 rcu_read_lock();
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 31936d387cfd..af5d1f38217f 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -862,9 +862,16 @@ static void __gre_tunnel_init(struct net_device *dev)
862 dev->hw_features |= GRE_FEATURES; 862 dev->hw_features |= GRE_FEATURES;
863 863
864 if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) { 864 if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
865 /* TCP offload with GRE SEQ is not supported. */ 865 /* TCP offload with GRE SEQ is not supported, nor
866 dev->features |= NETIF_F_GSO_SOFTWARE; 866 * can we support 2 levels of outer headers requiring
867 dev->hw_features |= NETIF_F_GSO_SOFTWARE; 867 * an update.
868 */
869 if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
870 (tunnel->encap.type == TUNNEL_ENCAP_NONE)) {
871 dev->features |= NETIF_F_GSO_SOFTWARE;
872 dev->hw_features |= NETIF_F_GSO_SOFTWARE;
873 }
874
868 /* Can use a lockless transmit, unless we generate 875 /* Can use a lockless transmit, unless we generate
869 * output sequences 876 * output sequences
870 */ 877 */