Skip to content

Commit b7fe10e

Browse files
tomratbertdavem330
authored andcommitted
gro: Fix remcsum offload to deal with frags in GRO
The remote checksum offload GRO did not consider the case that frag0 might be in use. This patch fixes that by accessing headers using the skb_gro functions and not saving offsets relative to skb->head. Signed-off-by: Tom Herbert <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9a873c7 commit b7fe10e

File tree

3 files changed

+53
-42
lines changed

3 files changed

+53
-42
lines changed

drivers/net/vxlan.c

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -519,10 +519,10 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
519519
u32 data, struct gro_remcsum *grc,
520520
bool nopartial)
521521
{
522-
size_t start, offset, plen;
522+
size_t start, offset;
523523

524524
if (skb->remcsum_offload)
525-
return NULL;
525+
return vh;
526526

527527
if (!NAPI_GRO_CB(skb)->csum_valid)
528528
return NULL;
@@ -532,17 +532,8 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
532532
offsetof(struct udphdr, check) :
533533
offsetof(struct tcphdr, check));
534534

535-
plen = hdrlen + offset + sizeof(u16);
536-
537-
/* Pull checksum that will be written */
538-
if (skb_gro_header_hard(skb, off + plen)) {
539-
vh = skb_gro_header_slow(skb, off + plen, off);
540-
if (!vh)
541-
return NULL;
542-
}
543-
544-
skb_gro_remcsum_process(skb, (void *)vh + hdrlen,
545-
start, offset, grc, nopartial);
535+
vh = skb_gro_remcsum_process(skb, (void *)vh, off, hdrlen,
536+
start, offset, grc, nopartial);
546537

547538
skb->remcsum_offload = 1;
548539

@@ -573,7 +564,6 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
573564
goto out;
574565
}
575566

576-
skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
577567
skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
578568

579569
flags = ntohl(vh->vx_flags);
@@ -588,6 +578,8 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
588578
goto out;
589579
}
590580

581+
skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
582+
591583
flush = 0;
592584

593585
for (p = *head; p; p = p->next) {
@@ -1110,6 +1102,9 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh,
11101102
{
11111103
size_t start, offset, plen;
11121104

1105+
if (skb->remcsum_offload)
1106+
return vh;
1107+
11131108
start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
11141109
offset = start + ((data & VXLAN_RCO_UDP) ?
11151110
offsetof(struct udphdr, check) :

include/linux/netdevice.h

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,8 +2311,7 @@ __sum16 __skb_gro_checksum_complete(struct sk_buff *skb);
23112311

23122312
static inline bool skb_at_gro_remcsum_start(struct sk_buff *skb)
23132313
{
2314-
return (NAPI_GRO_CB(skb)->gro_remcsum_start - skb_headroom(skb) ==
2315-
skb_gro_offset(skb));
2314+
return (NAPI_GRO_CB(skb)->gro_remcsum_start == skb_gro_offset(skb));
23162315
}
23172316

23182317
static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb,
@@ -2408,37 +2407,58 @@ static inline void skb_gro_remcsum_init(struct gro_remcsum *grc)
24082407
grc->delta = 0;
24092408
}
24102409

2411-
static inline void skb_gro_remcsum_process(struct sk_buff *skb, void *ptr,
2412-
int start, int offset,
2413-
struct gro_remcsum *grc,
2414-
bool nopartial)
2410+
static inline void *skb_gro_remcsum_process(struct sk_buff *skb, void *ptr,
2411+
unsigned int off, size_t hdrlen,
2412+
int start, int offset,
2413+
struct gro_remcsum *grc,
2414+
bool nopartial)
24152415
{
24162416
__wsum delta;
2417+
size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start);
24172418

24182419
BUG_ON(!NAPI_GRO_CB(skb)->csum_valid);
24192420

24202421
if (!nopartial) {
2421-
NAPI_GRO_CB(skb)->gro_remcsum_start =
2422-
((unsigned char *)ptr + start) - skb->head;
2423-
return;
2422+
NAPI_GRO_CB(skb)->gro_remcsum_start = off + hdrlen + start;
2423+
return ptr;
2424+
}
2425+
2426+
ptr = skb_gro_header_fast(skb, off);
2427+
if (skb_gro_header_hard(skb, off + plen)) {
2428+
ptr = skb_gro_header_slow(skb, off + plen, off);
2429+
if (!ptr)
2430+
return NULL;
24242431
}
24252432

2426-
delta = remcsum_adjust(ptr, NAPI_GRO_CB(skb)->csum, start, offset);
2433+
delta = remcsum_adjust(ptr + hdrlen, NAPI_GRO_CB(skb)->csum,
2434+
start, offset);
24272435

24282436
/* Adjust skb->csum since we changed the packet */
24292437
NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta);
24302438

2431-
grc->offset = (ptr + offset) - (void *)skb->head;
2439+
grc->offset = off + hdrlen + offset;
24322440
grc->delta = delta;
2441+
2442+
return ptr;
24332443
}
24342444

24352445
static inline void skb_gro_remcsum_cleanup(struct sk_buff *skb,
24362446
struct gro_remcsum *grc)
24372447
{
2448+
void *ptr;
2449+
size_t plen = grc->offset + sizeof(u16);
2450+
24382451
if (!grc->delta)
24392452
return;
24402453

2441-
remcsum_unadjust((__sum16 *)(skb->head + grc->offset), grc->delta);
2454+
ptr = skb_gro_header_fast(skb, grc->offset);
2455+
if (skb_gro_header_hard(skb, grc->offset + sizeof(u16))) {
2456+
ptr = skb_gro_header_slow(skb, plen, grc->offset);
2457+
if (!ptr)
2458+
return;
2459+
}
2460+
2461+
remcsum_unadjust((__sum16 *)ptr, grc->delta);
24422462
}
24432463

24442464
static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,

net/ipv4/fou.c

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr,
7979
__be16 *pd = data;
8080
size_t start = ntohs(pd[0]);
8181
size_t offset = ntohs(pd[1]);
82-
size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start);
82+
size_t plen = sizeof(struct udphdr) + hdrlen +
83+
max_t(size_t, offset + sizeof(u16), start);
84+
85+
if (skb->remcsum_offload)
86+
return guehdr;
8387

8488
if (!pskb_may_pull(skb, plen))
8589
return NULL;
@@ -221,29 +225,21 @@ static int fou_gro_complete(struct sk_buff *skb, int nhoff,
221225

222226
static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off,
223227
struct guehdr *guehdr, void *data,
224-
size_t hdrlen, u8 ipproto,
225-
struct gro_remcsum *grc, bool nopartial)
228+
size_t hdrlen, struct gro_remcsum *grc,
229+
bool nopartial)
226230
{
227231
__be16 *pd = data;
228232
size_t start = ntohs(pd[0]);
229233
size_t offset = ntohs(pd[1]);
230-
size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start);
231234

232235
if (skb->remcsum_offload)
233-
return NULL;
236+
return guehdr;
234237

235238
if (!NAPI_GRO_CB(skb)->csum_valid)
236239
return NULL;
237240

238-
/* Pull checksum that will be written */
239-
if (skb_gro_header_hard(skb, off + plen)) {
240-
guehdr = skb_gro_header_slow(skb, off + plen, off);
241-
if (!guehdr)
242-
return NULL;
243-
}
244-
245-
skb_gro_remcsum_process(skb, (void *)guehdr + hdrlen,
246-
start, offset, grc, nopartial);
241+
guehdr = skb_gro_remcsum_process(skb, (void *)guehdr, off, hdrlen,
242+
start, offset, grc, nopartial);
247243

248244
skb->remcsum_offload = 1;
249245

@@ -307,10 +303,10 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
307303

308304
if (flags & GUE_PFLAG_REMCSUM) {
309305
guehdr = gue_gro_remcsum(skb, off, guehdr,
310-
data + doffset, hdrlen,
311-
guehdr->proto_ctype, &grc,
306+
data + doffset, hdrlen, &grc,
312307
!!(fou->flags &
313308
FOU_F_REMCSUM_NOPARTIAL));
309+
314310
if (!guehdr)
315311
goto out;
316312

0 commit comments

Comments
 (0)