net: Support for multiple checksums with gso
When creating a GSO packet segment we may need to set more than one checksum in the packet (for instance a TCP checksum and UDP checksum for VXLAN encapsulation). To be efficient, we want to do checksum calculation for any part of the packet at most once. This patch adds csum_start offset to skb_gso_cb. This tracks the starting offset for skb->csum which is initially set in skb_segment. When a protocol needs to compute a transport checksum it calls gso_make_checksum which computes the checksum value from the start of transport header to csum_start and then adds in skb->csum to get the full checksum. skb->csum and csum_start are then updated to reflect the checksum of the resultant packet starting from the transport header. This patch also adds a flag to skbuff, encap_hdr_csum, which is set in *gso_segment fucntions to indicate that a tunnel protocol needs checksum calculation Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
77157e1973
commit
7e2b10c1e5
@ -2885,7 +2885,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
|
||||
if (unlikely(!proto))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
csum = !!can_checksum_protocol(features, proto);
|
||||
csum = !head_skb->encap_hdr_csum &&
|
||||
!!can_checksum_protocol(features, proto);
|
||||
|
||||
__skb_push(head_skb, doffset);
|
||||
headroom = skb_headroom(head_skb);
|
||||
pos = skb_headlen(head_skb);
|
||||
@ -2983,6 +2985,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
|
||||
nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
|
||||
skb_put(nskb, len),
|
||||
len, 0);
|
||||
SKB_GSO_CB(nskb)->csum_start =
|
||||
skb_headroom(nskb) + offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3052,6 +3056,8 @@ perform_csum_check:
|
||||
nskb->csum = skb_checksum(nskb, doffset,
|
||||
nskb->len - doffset, 0);
|
||||
nskb->ip_summed = CHECKSUM_NONE;
|
||||
SKB_GSO_CB(nskb)->csum_start =
|
||||
skb_headroom(nskb) + doffset;
|
||||
}
|
||||
} while ((offset += len) < head_skb->len);
|
||||
|
||||
|
Reference in New Issue
Block a user