Commit d45355da authored by Alexander Duyck's avatar Alexander Duyck Committed by Kleber Sacilotto de Souza

GRE: Disable segmentation offloads w/ CSUM and we are encapsulated via FOU

BugLink: https://bugs.launchpad.net/bugs/1878232

commit a0ca153f upstream.

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: c3483384 ("gro: Allow tunnel stacking in the case of FOU/GUE")
Signed-off-by: default avatarAlexander Duyck <aduyck@mirantis.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarIan May <ian.may@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 30e37af3
...@@ -2062,7 +2062,10 @@ struct napi_gro_cb { ...@@ -2062,7 +2062,10 @@ struct napi_gro_cb {
/* Number of gro_receive callbacks this packet already went through */ /* Number of gro_receive callbacks this packet already went through */
u8 recursion_counter:4; u8 recursion_counter:4;
/* 3 bit hole */ /* Used in GRE, set in fou/gue_gro_receive */
u8 is_fou:1;
/* 2 bit hole */
/* used to support CHECKSUM_COMPLETE for tunneling protocols */ /* used to support CHECKSUM_COMPLETE for tunneling protocols */
__wsum csum; __wsum csum;
......
...@@ -4320,6 +4320,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff ...@@ -4320,6 +4320,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
NAPI_GRO_CB(skb)->free = 0; NAPI_GRO_CB(skb)->free = 0;
NAPI_GRO_CB(skb)->encap_mark = 0; NAPI_GRO_CB(skb)->encap_mark = 0;
NAPI_GRO_CB(skb)->recursion_counter = 0; NAPI_GRO_CB(skb)->recursion_counter = 0;
NAPI_GRO_CB(skb)->is_fou = 0;
NAPI_GRO_CB(skb)->gro_remcsum_start = 0; NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
/* Setup for GRO checksum validation */ /* Setup for GRO checksum validation */
......
...@@ -205,6 +205,9 @@ static struct sk_buff **fou_gro_receive(struct sk_buff **head, ...@@ -205,6 +205,9 @@ static struct sk_buff **fou_gro_receive(struct sk_buff **head,
*/ */
NAPI_GRO_CB(skb)->encap_mark = 0; NAPI_GRO_CB(skb)->encap_mark = 0;
/* Flag this frame as already having an outer encap header */
NAPI_GRO_CB(skb)->is_fou = 1;
rcu_read_lock(); rcu_read_lock();
offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
ops = rcu_dereference(offloads[proto]); ops = rcu_dereference(offloads[proto]);
...@@ -372,6 +375,9 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, ...@@ -372,6 +375,9 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
*/ */
NAPI_GRO_CB(skb)->encap_mark = 0; NAPI_GRO_CB(skb)->encap_mark = 0;
/* Flag this frame as already having an outer encap header */
NAPI_GRO_CB(skb)->is_fou = 1;
rcu_read_lock(); rcu_read_lock();
offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
ops = rcu_dereference(offloads[guehdr->proto_ctype]); ops = rcu_dereference(offloads[guehdr->proto_ctype]);
......
...@@ -151,6 +151,14 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, ...@@ -151,6 +151,14 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
if ((greh->flags & ~(GRE_KEY|GRE_CSUM)) != 0) if ((greh->flags & ~(GRE_KEY|GRE_CSUM)) != 0)
goto out; goto out;
/* We can only support GRE_CSUM if we can track the location of
* the GRE header. In the case of FOU/GUE we cannot because the
* outer UDP header displaces the GRE header leaving us in a state
* of limbo.
*/
if ((greh->flags & GRE_CSUM) && NAPI_GRO_CB(skb)->is_fou)
goto out;
type = greh->protocol; type = greh->protocol;
rcu_read_lock(); rcu_read_lock();
......
...@@ -851,9 +851,16 @@ static void __gre_tunnel_init(struct net_device *dev) ...@@ -851,9 +851,16 @@ static void __gre_tunnel_init(struct net_device *dev)
dev->hw_features |= GRE_FEATURES; dev->hw_features |= GRE_FEATURES;
if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) { if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
/* TCP offload with GRE SEQ is not supported. */ /* TCP offload with GRE SEQ is not supported, nor
dev->features |= NETIF_F_GSO_SOFTWARE; * can we support 2 levels of outer headers requiring
dev->hw_features |= NETIF_F_GSO_SOFTWARE; * an update.
*/
if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
(tunnel->encap.type == TUNNEL_ENCAP_NONE)) {
dev->features |= NETIF_F_GSO_SOFTWARE;
dev->hw_features |= NETIF_F_GSO_SOFTWARE;
}
/* Can use a lockless transmit, unless we generate /* Can use a lockless transmit, unless we generate
* output sequences * output sequences
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment