From c194cf93c164ed1c71142485ee0f70f9f2d1fe35 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 9 Mar 2016 09:24:23 -0800 Subject: [PATCH 1/2] gro: Defer clearing of flush bit in tunnel paths This patch updates the GRO handlers for GRE, VXLAN, GENEVE, and FOU so that we do not clear the flush bit until after we have called the next level GRO handler. Previously this was being cleared before parsing through the list of frames, however this resulted in several paths where either the bit needed to be reset but wasn't as in the case of FOU, or cases where it was being set as in GENEVE. By just deferring the clearing of the bit until after the next level protocol has been parsed we can avoid any unnecessary bit twiddling and avoid bugs. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- drivers/net/geneve.c | 7 ++----- drivers/net/vxlan.c | 3 +-- net/ipv4/fou.c | 3 +-- net/ipv4/gre_offload.c | 3 +-- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 33185b9a435e..192631a345df 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -463,8 +463,6 @@ static struct sk_buff **geneve_gro_receive(struct sk_buff **head, goto out; } - flush = 0; - for (p = *head; p; p = p->next) { if (!NAPI_GRO_CB(p)->same_flow) continue; @@ -481,14 +479,13 @@ static struct sk_buff **geneve_gro_receive(struct sk_buff **head, rcu_read_lock(); ptype = gro_find_receive_by_type(type); - if (!ptype) { - flush = 1; + if (!ptype) goto out_unlock; - } skb_gro_pull(skb, gh_len); skb_gro_postpull_rcsum(skb, gh, gh_len); pp = ptype->callbacks.gro_receive(head, skb); + flush = 0; out_unlock: rcu_read_unlock(); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 8eda76f9e474..800106a7246c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -591,8 +591,6 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */ - flush = 0; - for (p = *head; p; p = p->next) { if (!NAPI_GRO_CB(p)->same_flow) continue; @@ -606,6 +604,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, } pp = eth_gro_receive(head, skb); + flush = 0; out: skb_gro_remcsum_cleanup(skb, &grc); diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 88dab0c1670c..780484243e14 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -319,8 +319,6 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, skb_gro_pull(skb, hdrlen); - flush = 0; - for (p = *head; p; p = p->next) { const struct guehdr *guehdr2; @@ -352,6 +350,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, goto out_unlock; pp = ops->callbacks.gro_receive(head, skb); + flush = 0; out_unlock: rcu_read_unlock(); diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 47f4c544c916..540866dbd27d 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -175,8 +175,6 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, null_compute_pseudo); } - flush = 0; - for (p = *head; p; p = p->next) { const struct gre_base_hdr *greh2; @@ -213,6 +211,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, skb_gro_postpull_rcsum(skb, greh, grehlen); pp = ptype->callbacks.gro_receive(head, skb); + flush = 0; out_unlock: rcu_read_unlock(); From 338039635d01524090e7bd706a3e555e20d5b337 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 9 Mar 2016 09:25:26 -0800 Subject: [PATCH 2/2] csum: Update csum_block_add to use rotate instead of byteswap The code for csum_block_add was doing a funky byteswap to swap the even and odd bytes of the checksum if the offset was odd. Instead of doing this we can save ourselves some trouble and just shift by 8 as this should have the same effect in terms of the final checksum value and only requires one instruction. In addition we can update csum_block_sub to just use csum_block_add with a inverse value for csum2. This way we follow the same code path as csum_block_add without having to duplicate it. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/net/checksum.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/net/checksum.h b/include/net/checksum.h index abffc64e7300..5c30891e84e5 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -88,8 +88,11 @@ static inline __wsum csum_block_add(__wsum csum, __wsum csum2, int offset) { u32 sum = (__force u32)csum2; - if (offset&1) - sum = ((sum&0xFF00FF)<<8)+((sum>>8)&0xFF00FF); + + /* rotate sum to align it with a 16b boundary */ + if (offset & 1) + sum = ror32(sum, 8); + return csum_add(csum, (__force __wsum)sum); } @@ -102,10 +105,7 @@ csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len) static inline __wsum csum_block_sub(__wsum csum, __wsum csum2, int offset) { - u32 sum = (__force u32)csum2; - if (offset&1) - sum = ((sum&0xFF00FF)<<8)+((sum>>8)&0xFF00FF); - return csum_sub(csum, (__force __wsum)sum); + return csum_block_add(csum, ~csum2, offset); } static inline __wsum csum_unfold(__sum16 n)