| From foo@baz Mon Sep 17 13:33:56 CEST 2018 |
| From: Stephen Hemminger <stephen@networkplumber.org> |
| Date: Thu, 13 Sep 2018 07:58:56 -0700 |
| Subject: net: pskb_trim_rcsum() and CHECKSUM_COMPLETE are friends |
| To: davem@davemloft.net, gregkh@linuxfoundation.org |
| Cc: netdev@vger.kernel.org, stable@vger.kernel.org, edumazet@google.com |
| Message-ID: <20180913145902.17531-25-sthemmin@microsoft.com> |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| After working on IP defragmentation lately, I found that some large |
| packets defeat CHECKSUM_COMPLETE optimization because of NIC adding |
| zero paddings on the last (small) fragment. |
| |
| While removing the padding with pskb_trim_rcsum(), we set skb->ip_summed |
| to CHECKSUM_NONE, forcing a full csum validation, even if all prior |
| fragments had CHECKSUM_COMPLETE set. |
| |
| We can instead compute the checksum of the part we are trimming, |
| usually smaller than the part we keep. |
| |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| (cherry picked from commit 88078d98d1bb085d72af8437707279e203524fa5) |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/linux/skbuff.h | 5 ++--- |
| net/core/skbuff.c | 14 ++++++++++++++ |
| 2 files changed, 16 insertions(+), 3 deletions(-) |
| |
| --- a/include/linux/skbuff.h |
| +++ b/include/linux/skbuff.h |
| @@ -3135,6 +3135,7 @@ static inline void *skb_push_rcsum(struc |
| return skb->data; |
| } |
| |
| +int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len); |
| /** |
| * pskb_trim_rcsum - trim received skb and update checksum |
| * @skb: buffer to trim |
| @@ -3148,9 +3149,7 @@ static inline int pskb_trim_rcsum(struct |
| { |
| if (likely(len >= skb->len)) |
| return 0; |
| - if (skb->ip_summed == CHECKSUM_COMPLETE) |
| - skb->ip_summed = CHECKSUM_NONE; |
| - return __pskb_trim(skb, len); |
| + return pskb_trim_rcsum_slow(skb, len); |
| } |
| |
| static inline int __skb_trim_rcsum(struct sk_buff *skb, unsigned int len) |
| --- a/net/core/skbuff.c |
| +++ b/net/core/skbuff.c |
| @@ -1839,6 +1839,20 @@ done: |
| } |
| EXPORT_SYMBOL(___pskb_trim); |
| |
| +/* Note : use pskb_trim_rcsum() instead of calling this directly |
| + */ |
| +int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len) |
| +{ |
| + if (skb->ip_summed == CHECKSUM_COMPLETE) { |
| + int delta = skb->len - len; |
| + |
| + skb->csum = csum_sub(skb->csum, |
| + skb_checksum(skb, len, delta, 0)); |
| + } |
| + return __pskb_trim(skb, len); |
| +} |
| +EXPORT_SYMBOL(pskb_trim_rcsum_slow); |
| + |
| /** |
| * __pskb_pull_tail - advance tail of skb header |
| * @skb: buffer to reallocate |