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
@@ -567,7 +567,8 @@ struct sk_buff {
|
||||
* headers if needed
|
||||
*/
|
||||
__u8 encapsulation:1;
|
||||
/* 6/8 bit hole (depending on ndisc_nodetype presence) */
|
||||
__u8 encap_hdr_csum:1;
|
||||
/* 5/7 bit hole (depending on ndisc_nodetype presence) */
|
||||
kmemcheck_bitfield_end(flags2);
|
||||
|
||||
#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
|
||||
@@ -2988,6 +2989,7 @@ static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
|
||||
struct skb_gso_cb {
|
||||
int mac_offset;
|
||||
int encap_level;
|
||||
__u16 csum_start;
|
||||
};
|
||||
#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb)
|
||||
|
||||
@@ -3012,6 +3014,28 @@ static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute the checksum for a gso segment. First compute the checksum value
|
||||
* from the start of transport header to SKB_GSO_CB(skb)->csum_start, and
|
||||
* then add in skb->csum (checksum from csum_start to end of packet).
|
||||
* skb->csum and csum_start are then updated to reflect the checksum of the
|
||||
* resultant packet starting from the transport header-- the resultant checksum
|
||||
* is in the res argument (i.e. normally zero or ~ of checksum of a pseudo
|
||||
* header.
|
||||
*/
|
||||
static inline __sum16 gso_make_checksum(struct sk_buff *skb, __wsum res)
|
||||
{
|
||||
int plen = SKB_GSO_CB(skb)->csum_start - skb_headroom(skb) -
|
||||
skb_transport_offset(skb);
|
||||
__u16 csum;
|
||||
|
||||
csum = csum_fold(csum_partial(skb_transport_header(skb),
|
||||
plen, skb->csum));
|
||||
skb->csum = res;
|
||||
SKB_GSO_CB(skb)->csum_start -= plen;
|
||||
|
||||
return csum;
|
||||
}
|
||||
|
||||
static inline bool skb_is_gso(const struct sk_buff *skb)
|
||||
{
|
||||
return skb_shinfo(skb)->gso_size;
|
||||
|
Reference in New Issue
Block a user