aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2015-02-10 19:30:27 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-11 18:12:09 -0500
commit26c4f7da3e413da697a7beb22ad496390eda7da0 (patch)
tree55182c7a68fc4129369ffce2ac30a897cc3d55a1 /include/linux
parent13101602c4a9f653d59af9469040797bc5b361ca (diff)
net: Fix remcsum in GRO path to not change packet
Remote checksum offload processing is currently the same for both the GRO and non-GRO path. When the remote checksum offload option is encountered, the checksum field referred to is modified in the packet. So in the GRO case, the packet is modified in the GRO path and then the operation is skipped when the packet goes through the normal path based on skb->remcsum_offload. There is a problem in that the packet may be modified in the GRO path, but then forwarded off host still containing the remote checksum option. A remote host will again perform RCO but now the checksum verification will fail since GRO RCO already modified the checksum. To fix this, we ensure that GRO restores a packet to it's original state before returning. In this model, when GRO processes a remote checksum option it still changes the checksum per the algorithm but on return from lower layer processing the checksum is restored to its original value. In this patch we add define gro_remcsum structure which is passed to skb_gro_remcsum_process to save offset and delta for the checksum being changed. After lower layer processing, skb_gro_remcsum_cleanup is called to restore the checksum before returning from GRO. Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/netdevice.h25
1 files changed, 23 insertions, 2 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d115256ed5a2..3aa02457fe4f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2321,8 +2321,19 @@ do { \
2321 compute_pseudo(skb, proto)); \ 2321 compute_pseudo(skb, proto)); \
2322} while (0) 2322} while (0)
2323 2323
2324struct gro_remcsum {
2325 int offset;
2326 __wsum delta;
2327};
2328
2329static inline void skb_gro_remcsum_init(struct gro_remcsum *grc)
2330{
2331 grc->delta = 0;
2332}
2333
2324static inline void skb_gro_remcsum_process(struct sk_buff *skb, void *ptr, 2334static inline void skb_gro_remcsum_process(struct sk_buff *skb, void *ptr,
2325 int start, int offset) 2335 int start, int offset,
2336 struct gro_remcsum *grc)
2326{ 2337{
2327 __wsum delta; 2338 __wsum delta;
2328 2339
@@ -2331,10 +2342,20 @@ static inline void skb_gro_remcsum_process(struct sk_buff *skb, void *ptr,
2331 delta = remcsum_adjust(ptr, NAPI_GRO_CB(skb)->csum, start, offset); 2342 delta = remcsum_adjust(ptr, NAPI_GRO_CB(skb)->csum, start, offset);
2332 2343
2333 /* Adjust skb->csum since we changed the packet */ 2344 /* Adjust skb->csum since we changed the packet */
2334 skb->csum = csum_add(skb->csum, delta);
2335 NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta); 2345 NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta);
2346
2347 grc->offset = (ptr + offset) - (void *)skb->head;
2348 grc->delta = delta;
2336} 2349}
2337 2350
2351static inline void skb_gro_remcsum_cleanup(struct sk_buff *skb,
2352 struct gro_remcsum *grc)
2353{
2354 if (!grc->delta)
2355 return;
2356
2357 remcsum_unadjust((__sum16 *)(skb->head + grc->offset), grc->delta);
2358}
2338 2359
2339static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, 2360static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
2340 unsigned short type, 2361 unsigned short type,