Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gro: decrease size of CB

The GRO control block (NAPI_GRO_CB) is currently at its maximum size.
This commit reduces its size by putting two groups of fields that are
used only at different times into a union.

Specifically, the fields frag0 and frag0_len are the fields that make up
the frag0 optimisation mechanism, which is used during the initial
parsing of the SKB.

The fields last and age are used after the initial parsing, while the
SKB is stored in the GRO list, waiting for other packets to arrive.

There was one location in dev_gro_receive that modified the frag0 fields
after setting last and age. I changed this accordingly without altering
the code behaviour.

Signed-off-by: Richard Gobert <richardbgobert@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20230601161407.GA9253@debian
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Richard Gobert and committed by
Paolo Abeni
7b355b76 ddb8701d

+28 -17
+16 -10
include/net/gro.h
··· 11 11 #include <net/udp.h> 12 12 13 13 struct napi_gro_cb { 14 - /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */ 15 - void *frag0; 14 + union { 15 + struct { 16 + /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */ 17 + void *frag0; 16 18 17 - /* Length of frag0. */ 18 - unsigned int frag0_len; 19 + /* Length of frag0. */ 20 + unsigned int frag0_len; 21 + }; 22 + 23 + struct { 24 + /* used in skb_gro_receive() slow path */ 25 + struct sk_buff *last; 26 + 27 + /* jiffies when first packet was created/queued */ 28 + unsigned long age; 29 + }; 30 + }; 19 31 20 32 /* This indicates where we are processing relative to skb->data. */ 21 33 int data_offset; ··· 43 31 44 32 /* Used in ipv6_gro_receive() and foo-over-udp */ 45 33 u16 proto; 46 - 47 - /* jiffies when first packet was created/queued */ 48 - unsigned long age; 49 34 50 35 /* Used in napi_gro_cb::free */ 51 36 #define NAPI_GRO_FREE 1 ··· 86 77 87 78 /* used to support CHECKSUM_COMPLETE for tunneling protocols */ 88 79 __wsum csum; 89 - 90 - /* used in skb_gro_receive() slow path */ 91 - struct sk_buff *last; 92 80 }; 93 81 94 82 #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
+12 -7
net/core/gro.c
··· 458 458 } 459 459 } 460 460 461 + static void gro_try_pull_from_frag0(struct sk_buff *skb) 462 + { 463 + int grow = skb_gro_offset(skb) - skb_headlen(skb); 464 + 465 + if (grow > 0) 466 + gro_pull_from_frag0(skb, grow); 467 + } 468 + 461 469 static void gro_flush_oldest(struct napi_struct *napi, struct list_head *head) 462 470 { 463 471 struct sk_buff *oldest; ··· 495 487 struct sk_buff *pp = NULL; 496 488 enum gro_result ret; 497 489 int same_flow; 498 - int grow; 499 490 500 491 if (netif_elide_gro(skb->dev)) 501 492 goto normal; ··· 569 562 else 570 563 gro_list->count++; 571 564 565 + /* Must be called before setting NAPI_GRO_CB(skb)->{age|last} */ 566 + gro_try_pull_from_frag0(skb); 572 567 NAPI_GRO_CB(skb)->age = jiffies; 573 568 NAPI_GRO_CB(skb)->last = skb; 574 569 if (!skb_is_gso(skb)) 575 570 skb_shinfo(skb)->gso_size = skb_gro_len(skb); 576 571 list_add(&skb->list, &gro_list->list); 577 572 ret = GRO_HELD; 578 - 579 - pull: 580 - grow = skb_gro_offset(skb) - skb_headlen(skb); 581 - if (grow > 0) 582 - gro_pull_from_frag0(skb, grow); 583 573 ok: 584 574 if (gro_list->count) { 585 575 if (!test_bit(bucket, &napi->gro_bitmask)) ··· 589 585 590 586 normal: 591 587 ret = GRO_NORMAL; 592 - goto pull; 588 + gro_try_pull_from_frag0(skb); 589 + goto ok; 593 590 } 594 591 595 592 struct packet_offload *gro_find_receive_by_type(__be16 type)