diff options
-rw-r--r-- | include/linux/netdevice.h | 76 | ||||
-rw-r--r-- | net/core/dev.c | 34 |
2 files changed, 107 insertions, 3 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7e2b0b8b5cd7..eb73444e1bd0 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1883,7 +1883,13 @@ struct napi_gro_cb { | |||
1883 | u16 proto; | 1883 | u16 proto; |
1884 | 1884 | ||
1885 | /* Used in udp_gro_receive */ | 1885 | /* Used in udp_gro_receive */ |
1886 | u16 udp_mark; | 1886 | u8 udp_mark:1; |
1887 | |||
1888 | /* GRO checksum is valid */ | ||
1889 | u8 csum_valid:1; | ||
1890 | |||
1891 | /* Number encapsulation layers crossed */ | ||
1892 | u8 encapsulation; | ||
1887 | 1893 | ||
1888 | /* used to support CHECKSUM_COMPLETE for tunneling protocols */ | 1894 | /* used to support CHECKSUM_COMPLETE for tunneling protocols */ |
1889 | __wsum csum; | 1895 | __wsum csum; |
@@ -2154,11 +2160,77 @@ static inline void *skb_gro_network_header(struct sk_buff *skb) | |||
2154 | static inline void skb_gro_postpull_rcsum(struct sk_buff *skb, | 2160 | static inline void skb_gro_postpull_rcsum(struct sk_buff *skb, |
2155 | const void *start, unsigned int len) | 2161 | const void *start, unsigned int len) |
2156 | { | 2162 | { |
2157 | if (skb->ip_summed == CHECKSUM_COMPLETE) | 2163 | if (NAPI_GRO_CB(skb)->csum_valid) |
2158 | NAPI_GRO_CB(skb)->csum = csum_sub(NAPI_GRO_CB(skb)->csum, | 2164 | NAPI_GRO_CB(skb)->csum = csum_sub(NAPI_GRO_CB(skb)->csum, |
2159 | csum_partial(start, len, 0)); | 2165 | csum_partial(start, len, 0)); |
2160 | } | 2166 | } |
2161 | 2167 | ||
2168 | /* GRO checksum functions. These are logical equivalents of the normal | ||
2169 | * checksum functions (in skbuff.h) except that they operate on the GRO | ||
2170 | * offsets and fields in sk_buff. | ||
2171 | */ | ||
2172 | |||
2173 | __sum16 __skb_gro_checksum_complete(struct sk_buff *skb); | ||
2174 | |||
2175 | static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb, | ||
2176 | bool zero_okay, | ||
2177 | __sum16 check) | ||
2178 | { | ||
2179 | return (skb->ip_summed != CHECKSUM_PARTIAL && | ||
2180 | (skb->ip_summed != CHECKSUM_UNNECESSARY || | ||
2181 | (NAPI_GRO_CB(skb)->encapsulation > skb->encapsulation)) && | ||
2182 | (!zero_okay || check)); | ||
2183 | } | ||
2184 | |||
2185 | static inline __sum16 __skb_gro_checksum_validate_complete(struct sk_buff *skb, | ||
2186 | __wsum psum) | ||
2187 | { | ||
2188 | if (NAPI_GRO_CB(skb)->csum_valid && | ||
2189 | !csum_fold(csum_add(psum, NAPI_GRO_CB(skb)->csum))) | ||
2190 | return 0; | ||
2191 | |||
2192 | NAPI_GRO_CB(skb)->csum = psum; | ||
2193 | |||
2194 | return __skb_gro_checksum_complete(skb); | ||
2195 | } | ||
2196 | |||
2197 | /* Update skb for CHECKSUM_UNNECESSARY when we verified a top level | ||
2198 | * checksum or an encapsulated one during GRO. This saves work | ||
2199 | * if we fallback to normal path with the packet. | ||
2200 | */ | ||
2201 | static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb) | ||
2202 | { | ||
2203 | if (skb->ip_summed == CHECKSUM_UNNECESSARY) { | ||
2204 | if (NAPI_GRO_CB(skb)->encapsulation) | ||
2205 | skb->encapsulation = 1; | ||
2206 | } else if (skb->ip_summed != CHECKSUM_PARTIAL) { | ||
2207 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
2208 | skb->encapsulation = 0; | ||
2209 | } | ||
2210 | } | ||
2211 | |||
2212 | #define __skb_gro_checksum_validate(skb, proto, zero_okay, check, \ | ||
2213 | compute_pseudo) \ | ||
2214 | ({ \ | ||
2215 | __sum16 __ret = 0; \ | ||
2216 | if (__skb_gro_checksum_validate_needed(skb, zero_okay, check)) \ | ||
2217 | __ret = __skb_gro_checksum_validate_complete(skb, \ | ||
2218 | compute_pseudo(skb, proto)); \ | ||
2219 | if (!__ret) \ | ||
2220 | skb_gro_incr_csum_unnecessary(skb); \ | ||
2221 | __ret; \ | ||
2222 | }) | ||
2223 | |||
2224 | #define skb_gro_checksum_validate(skb, proto, compute_pseudo) \ | ||
2225 | __skb_gro_checksum_validate(skb, proto, false, 0, compute_pseudo) | ||
2226 | |||
2227 | #define skb_gro_checksum_validate_zero_check(skb, proto, check, \ | ||
2228 | compute_pseudo) \ | ||
2229 | __skb_gro_checksum_validate(skb, proto, true, check, compute_pseudo) | ||
2230 | |||
2231 | #define skb_gro_checksum_simple_validate(skb) \ | ||
2232 | __skb_gro_checksum_validate(skb, 0, false, 0, null_compute_pseudo) | ||
2233 | |||
2162 | static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, | 2234 | static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, |
2163 | unsigned short type, | 2235 | unsigned short type, |
2164 | const void *daddr, const void *saddr, | 2236 | const void *daddr, const void *saddr, |
diff --git a/net/core/dev.c b/net/core/dev.c index 1421dad4cb29..b6a718ec11c1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3962,7 +3962,13 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
3962 | goto normal; | 3962 | goto normal; |
3963 | 3963 | ||
3964 | gro_list_prepare(napi, skb); | 3964 | gro_list_prepare(napi, skb); |
3965 | NAPI_GRO_CB(skb)->csum = skb->csum; /* Needed for CHECKSUM_COMPLETE */ | 3965 | |
3966 | if (skb->ip_summed == CHECKSUM_COMPLETE) { | ||
3967 | NAPI_GRO_CB(skb)->csum = skb->csum; | ||
3968 | NAPI_GRO_CB(skb)->csum_valid = 1; | ||
3969 | } else { | ||
3970 | NAPI_GRO_CB(skb)->csum_valid = 0; | ||
3971 | } | ||
3966 | 3972 | ||
3967 | rcu_read_lock(); | 3973 | rcu_read_lock(); |
3968 | list_for_each_entry_rcu(ptype, head, list) { | 3974 | list_for_each_entry_rcu(ptype, head, list) { |
@@ -3975,6 +3981,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
3975 | NAPI_GRO_CB(skb)->flush = 0; | 3981 | NAPI_GRO_CB(skb)->flush = 0; |
3976 | NAPI_GRO_CB(skb)->free = 0; | 3982 | NAPI_GRO_CB(skb)->free = 0; |
3977 | NAPI_GRO_CB(skb)->udp_mark = 0; | 3983 | NAPI_GRO_CB(skb)->udp_mark = 0; |
3984 | NAPI_GRO_CB(skb)->encapsulation = 0; | ||
3978 | 3985 | ||
3979 | pp = ptype->callbacks.gro_receive(&napi->gro_list, skb); | 3986 | pp = ptype->callbacks.gro_receive(&napi->gro_list, skb); |
3980 | break; | 3987 | break; |
@@ -4205,6 +4212,31 @@ gro_result_t napi_gro_frags(struct napi_struct *napi) | |||
4205 | } | 4212 | } |
4206 | EXPORT_SYMBOL(napi_gro_frags); | 4213 | EXPORT_SYMBOL(napi_gro_frags); |
4207 | 4214 | ||
4215 | /* Compute the checksum from gro_offset and return the folded value | ||
4216 | * after adding in any pseudo checksum. | ||
4217 | */ | ||
4218 | __sum16 __skb_gro_checksum_complete(struct sk_buff *skb) | ||
4219 | { | ||
4220 | __wsum wsum; | ||
4221 | __sum16 sum; | ||
4222 | |||
4223 | wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), 0); | ||
4224 | |||
4225 | /* NAPI_GRO_CB(skb)->csum holds pseudo checksum */ | ||
4226 | sum = csum_fold(csum_add(NAPI_GRO_CB(skb)->csum, wsum)); | ||
4227 | if (likely(!sum)) { | ||
4228 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && | ||
4229 | !skb->csum_complete_sw) | ||
4230 | netdev_rx_csum_fault(skb->dev); | ||
4231 | } | ||
4232 | |||
4233 | NAPI_GRO_CB(skb)->csum = wsum; | ||
4234 | NAPI_GRO_CB(skb)->csum_valid = 1; | ||
4235 | |||
4236 | return sum; | ||
4237 | } | ||
4238 | EXPORT_SYMBOL(__skb_gro_checksum_complete); | ||
4239 | |||
4208 | /* | 4240 | /* |
4209 | * net_rps_action_and_irq_enable sends any pending IPI's for rps. | 4241 | * net_rps_action_and_irq_enable sends any pending IPI's for rps. |
4210 | * Note: called with local irq disabled, but exits with local irq enabled. | 4242 | * Note: called with local irq disabled, but exits with local irq enabled. |