Skip to content

Commit 8a29111

Browse files
edumazetdavem330
authored andcommitted
net: gro: allow to build full sized skb
skb_gro_receive() is currently limited to 16 or 17 MSS per GRO skb, typically 24616 bytes, because it fills up to MAX_SKB_FRAGS frags. It's relatively easy to extend the skb using frag_list to allow more frags to be appended into the last sk_buff. This still builds very efficient skbs, and allows reaching 45 MSS per skb. (45 MSS GRO packet uses one skb plus a frag_list containing 2 additional sk_buff) High speed TCP flows benefit from this extension by lowering TCP stack cpu usage (less packets stored in receive queue, less ACK packets processed) Forwarding setups could be hurt, as such skbs will need to be linearized, although its not a new problem, as GRO could already provide skbs with a frag_list. We could make the 65536 bytes threshold a tunable to mitigate this. (First time we need to linearize skb in skb_needs_linearize(), we could lower the tunable to ~16*1460 so that following skb_gro_receive() calls build smaller skbs) Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 4c60f1d commit 8a29111

File tree

1 file changed

+26
-17
lines changed

1 file changed

+26
-17
lines changed

net/core/skbuff.c

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2936,32 +2936,30 @@ EXPORT_SYMBOL_GPL(skb_segment);
29362936

29372937
int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
29382938
{
2939-
struct sk_buff *p = *head;
2940-
struct sk_buff *nskb;
2941-
struct skb_shared_info *skbinfo = skb_shinfo(skb);
2942-
struct skb_shared_info *pinfo = skb_shinfo(p);
2943-
unsigned int headroom;
2944-
unsigned int len = skb_gro_len(skb);
2939+
struct skb_shared_info *pinfo, *skbinfo = skb_shinfo(skb);
29452940
unsigned int offset = skb_gro_offset(skb);
29462941
unsigned int headlen = skb_headlen(skb);
2942+
struct sk_buff *nskb, *lp, *p = *head;
2943+
unsigned int len = skb_gro_len(skb);
29472944
unsigned int delta_truesize;
2945+
unsigned int headroom;
29482946

2949-
if (p->len + len >= 65536)
2947+
if (unlikely(p->len + len >= 65536))
29502948
return -E2BIG;
29512949

2952-
if (pinfo->frag_list)
2953-
goto merge;
2954-
else if (headlen <= offset) {
2950+
lp = NAPI_GRO_CB(p)->last ?: p;
2951+
pinfo = skb_shinfo(lp);
2952+
2953+
if (headlen <= offset) {
29552954
skb_frag_t *frag;
29562955
skb_frag_t *frag2;
29572956
int i = skbinfo->nr_frags;
29582957
int nr_frags = pinfo->nr_frags + i;
29592958

2960-
offset -= headlen;
2961-
29622959
if (nr_frags > MAX_SKB_FRAGS)
2963-
return -E2BIG;
2960+
goto merge;
29642961

2962+
offset -= headlen;
29652963
pinfo->nr_frags = nr_frags;
29662964
skbinfo->nr_frags = 0;
29672965

@@ -2992,7 +2990,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
29922990
unsigned int first_offset;
29932991

29942992
if (nr_frags + 1 + skbinfo->nr_frags > MAX_SKB_FRAGS)
2995-
return -E2BIG;
2993+
goto merge;
29962994

29972995
first_offset = skb->data -
29982996
(unsigned char *)page_address(page) +
@@ -3010,7 +3008,10 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
30103008
delta_truesize = skb->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));
30113009
NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD;
30123010
goto done;
3013-
} else if (skb_gro_len(p) != pinfo->gso_size)
3011+
}
3012+
if (pinfo->frag_list)
3013+
goto merge;
3014+
if (skb_gro_len(p) != pinfo->gso_size)
30143015
return -E2BIG;
30153016

30163017
headroom = skb_headroom(p);
@@ -3062,16 +3063,24 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
30623063

30633064
__skb_pull(skb, offset);
30643065

3065-
NAPI_GRO_CB(p)->last->next = skb;
3066+
if (!NAPI_GRO_CB(p)->last)
3067+
skb_shinfo(p)->frag_list = skb;
3068+
else
3069+
NAPI_GRO_CB(p)->last->next = skb;
30663070
NAPI_GRO_CB(p)->last = skb;
30673071
skb_header_release(skb);
3072+
lp = p;
30683073

30693074
done:
30703075
NAPI_GRO_CB(p)->count++;
30713076
p->data_len += len;
30723077
p->truesize += delta_truesize;
30733078
p->len += len;
3074-
3079+
if (lp != p) {
3080+
lp->data_len += len;
3081+
lp->truesize += delta_truesize;
3082+
lp->len += len;
3083+
}
30753084
NAPI_GRO_CB(skb)->same_flow = 1;
30763085
return 0;
30773086
}

0 commit comments

Comments
 (0)