diff options
-rw-r--r-- | include/linux/netdevice.h | 4 | ||||
-rw-r--r-- | include/linux/skbuff.h | 21 | ||||
-rw-r--r-- | net/core/dev.c | 2 |
3 files changed, 24 insertions, 3 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 202c25a9aadf..a0ab6d9d400a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -2216,7 +2216,9 @@ static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb) | |||
2216 | if (__skb_gro_checksum_validate_needed(skb, zero_okay, check)) \ | 2216 | if (__skb_gro_checksum_validate_needed(skb, zero_okay, check)) \ |
2217 | __ret = __skb_gro_checksum_validate_complete(skb, \ | 2217 | __ret = __skb_gro_checksum_validate_complete(skb, \ |
2218 | compute_pseudo(skb, proto)); \ | 2218 | compute_pseudo(skb, proto)); \ |
2219 | if (!__ret) \ | 2219 | if (__ret) \ |
2220 | __skb_mark_checksum_bad(skb); \ | ||
2221 | else \ | ||
2220 | skb_gro_incr_csum_unnecessary(skb); \ | 2222 | skb_gro_incr_csum_unnecessary(skb); \ |
2221 | __ret; \ | 2223 | __ret; \ |
2222 | }) | 2224 | }) |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c93b5859a772..23710a243439 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -617,7 +617,8 @@ struct sk_buff { | |||
617 | 617 | ||
618 | kmemcheck_bitfield_begin(flags3); | 618 | kmemcheck_bitfield_begin(flags3); |
619 | __u8 csum_level:2; | 619 | __u8 csum_level:2; |
620 | /* 14 bit hole */ | 620 | __u8 csum_bad:1; |
621 | /* 13 bit hole */ | ||
621 | kmemcheck_bitfield_end(flags3); | 622 | kmemcheck_bitfield_end(flags3); |
622 | 623 | ||
623 | __be16 inner_protocol; | 624 | __be16 inner_protocol; |
@@ -2825,6 +2826,21 @@ static inline void __skb_incr_checksum_unnecessary(struct sk_buff *skb) | |||
2825 | } | 2826 | } |
2826 | } | 2827 | } |
2827 | 2828 | ||
2829 | static inline void __skb_mark_checksum_bad(struct sk_buff *skb) | ||
2830 | { | ||
2831 | /* Mark current checksum as bad (typically called from GRO | ||
2832 | * path). In the case that ip_summed is CHECKSUM_NONE | ||
2833 | * this must be the first checksum encountered in the packet. | ||
2834 | * When ip_summed is CHECKSUM_UNNECESSARY, this is the first | ||
2835 | * checksum after the last one validated. For UDP, a zero | ||
2836 | * checksum can not be marked as bad. | ||
2837 | */ | ||
2838 | |||
2839 | if (skb->ip_summed == CHECKSUM_NONE || | ||
2840 | skb->ip_summed == CHECKSUM_UNNECESSARY) | ||
2841 | skb->csum_bad = 1; | ||
2842 | } | ||
2843 | |||
2828 | /* Check if we need to perform checksum complete validation. | 2844 | /* Check if we need to perform checksum complete validation. |
2829 | * | 2845 | * |
2830 | * Returns true if checksum complete is needed, false otherwise | 2846 | * Returns true if checksum complete is needed, false otherwise |
@@ -2866,6 +2882,9 @@ static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb, | |||
2866 | skb->csum_valid = 1; | 2882 | skb->csum_valid = 1; |
2867 | return 0; | 2883 | return 0; |
2868 | } | 2884 | } |
2885 | } else if (skb->csum_bad) { | ||
2886 | /* ip_summed == CHECKSUM_NONE in this case */ | ||
2887 | return 1; | ||
2869 | } | 2888 | } |
2870 | 2889 | ||
2871 | skb->csum = psum; | 2890 | skb->csum = psum; |
diff --git a/net/core/dev.c b/net/core/dev.c index 6857d57aa294..3774afc3bebf 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3918,7 +3918,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
3918 | if (!(skb->dev->features & NETIF_F_GRO)) | 3918 | if (!(skb->dev->features & NETIF_F_GRO)) |
3919 | goto normal; | 3919 | goto normal; |
3920 | 3920 | ||
3921 | if (skb_is_gso(skb) || skb_has_frag_list(skb)) | 3921 | if (skb_is_gso(skb) || skb_has_frag_list(skb) || skb->csum_bad) |
3922 | goto normal; | 3922 | goto normal; |
3923 | 3923 | ||
3924 | gro_list_prepare(napi, skb); | 3924 | gro_list_prepare(napi, skb); |