Skip to content

Commit 3d3be43

Browse files
Eric Dumazetdavem330
authored andcommitted
gro: fix different skb headrooms
Packets entering GRO might have different headrooms, even for a given flow (because of implementation details in drivers, like copybreak). We cant force drivers to deliver packets with a fixed headroom. 1) fix skb_segment() skb_segment() makes the false assumption headrooms of fragments are same than the head. When CHECKSUM_PARTIAL is used, this can give csum_start errors, and crash later in skb_copy_and_csum_dev() 2) allocate a minimal skb for head of frag_list skb_gro_receive() uses netdev_alloc_skb(headroom + skb_gro_offset(p)) to allocate a fresh skb. This adds NET_SKB_PAD to a padding already provided by netdevice, depending on various things, like copybreak. Use alloc_skb() to allocate an exact padding, to reduce cache line needs: NET_SKB_PAD + NET_IP_ALIGN bugzilla : https://bugzilla.kernel.org/show_bug.cgi?id=16626 Many thanks to Plamen Petrov, testing many debugging patches ! With help of Jarek Poplawski. Reported-by: Plamen Petrov <pvp-lsts@fs.uni-ruse.bg> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Jarek Poplawski <jarkao2@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 87f94b4 commit 3d3be43

File tree

1 file changed

+6
-2
lines changed

1 file changed

+6
-2
lines changed

net/core/skbuff.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2573,6 +2573,10 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
25732573
__copy_skb_header(nskb, skb);
25742574
nskb->mac_len = skb->mac_len;
25752575

2576+
/* nskb and skb might have different headroom */
2577+
if (nskb->ip_summed == CHECKSUM_PARTIAL)
2578+
nskb->csum_start += skb_headroom(nskb) - headroom;
2579+
25762580
skb_reset_mac_header(nskb);
25772581
skb_set_network_header(nskb, skb->mac_len);
25782582
nskb->transport_header = (nskb->network_header +
@@ -2702,8 +2706,8 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
27022706
} else if (skb_gro_len(p) != pinfo->gso_size)
27032707
return -E2BIG;
27042708

2705-
headroom = skb_headroom(p);
2706-
nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p));
2709+
headroom = NET_SKB_PAD + NET_IP_ALIGN;
2710+
nskb = alloc_skb(headroom + skb_gro_offset(p), GFP_ATOMIC);
27072711
if (unlikely(!nskb))
27082712
return -ENOMEM;
27092713

0 commit comments

Comments
 (0)