mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 21:33:00 +00:00
net: Store checksum result for offloaded GSO checksums
This patch makes it so that we can offload the checksums for a packet up to a certain point and then begin computing the checksums via software. Setting this up is fairly straight forward as all we need to do is reset the values stored in csum and csum_start for the GSO context block. One complication for this is remote checksum offload. In order to allow the inner checksums to be offloaded while computing the outer checksum manually we needed to have some way of indicating that the offload wasn't real. In order to do that I replaced CHECKSUM_PARTIAL with CHECKSUM_UNNECESSARY in the case of us computing checksums for the outer header while skipping computing checksums for the inner headers. We clean up the ip_summed flag and set it to either CHECKSUM_PARTIAL or CHECKSUM_NONE once we hand the packet off to the next lower level. Signed-off-by: Alexander Duyck <aduyck@mirantis.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7fbeffed77
commit
08b64fcca9
@ -2161,6 +2161,11 @@ static inline int skb_checksum_start_offset(const struct sk_buff *skb)
|
|||||||
return skb->csum_start - skb_headroom(skb);
|
return skb->csum_start - skb_headroom(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned char *skb_checksum_start(const struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return skb->head + skb->csum_start;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int skb_transport_offset(const struct sk_buff *skb)
|
static inline int skb_transport_offset(const struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
return skb_transport_header(skb) - skb->data;
|
return skb_transport_header(skb) - skb->data;
|
||||||
@ -3576,6 +3581,16 @@ static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void gso_reset_checksum(struct sk_buff *skb, __wsum res)
|
||||||
|
{
|
||||||
|
/* Do not update partial checksums if remote checksum is enabled. */
|
||||||
|
if (skb->remcsum_offload)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SKB_GSO_CB(skb)->csum = res;
|
||||||
|
SKB_GSO_CB(skb)->csum_start = skb_checksum_start(skb) - skb->head;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compute the checksum for a gso segment. First compute the checksum value
|
/* 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
|
* 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).
|
* then add in skb->csum (checksum from csum_start to end of packet).
|
||||||
|
@ -135,7 +135,9 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
|
|||||||
th->fin = th->psh = 0;
|
th->fin = th->psh = 0;
|
||||||
th->check = newcheck;
|
th->check = newcheck;
|
||||||
|
|
||||||
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||||
|
gso_reset_checksum(skb, ~th->check);
|
||||||
|
else
|
||||||
th->check = gso_make_checksum(skb, ~th->check);
|
th->check = gso_make_checksum(skb, ~th->check);
|
||||||
|
|
||||||
seq += mss;
|
seq += mss;
|
||||||
@ -169,7 +171,9 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
|
|||||||
skb->data_len);
|
skb->data_len);
|
||||||
th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
|
th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
|
||||||
(__force u32)delta));
|
(__force u32)delta));
|
||||||
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||||
|
gso_reset_checksum(skb, ~th->check);
|
||||||
|
else
|
||||||
th->check = gso_make_checksum(skb, ~th->check);
|
th->check = gso_make_checksum(skb, ~th->check);
|
||||||
out:
|
out:
|
||||||
return segs;
|
return segs;
|
||||||
|
Loading…
Reference in New Issue
Block a user