* [PATCH net-next 0/3] gro: inline tcp6_gro_{receive,complete}
@ 2026-01-16 15:29 Eric Dumazet
2026-01-16 15:29 ` [PATCH net-next 1/3] net: always inline __skb_incr_checksum_unnecessary() Eric Dumazet
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Eric Dumazet @ 2026-01-16 15:29 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, netdev, Willem de Bruijn, Kuniyuki Iwashima,
eric.dumazet, Eric Dumazet
On some platforms, GRO stack is too deep and causes cpu stalls.
Decreasing call depths by one shows a 1.5 % gain on Zen 2 cpus.
(32 RX queues, 100Gbit NIC, RFS enabled, tcp_rr with 128 threads and 10,000 flows)
We can go further by inlining ipv6_gro_{receive,complete}
and take care of IPv4 if there is interest.
Cumulative size increase for this series (of 3):
$ scripts/bloat-o-meter -t vmlinux.0 vmlinux.3
add/remove: 2/2 grow/shrink: 5/1 up/down: 1572/-471 (1101)
Function old new delta
ipv6_gro_receive 1069 1846 +777
ipv6_gro_complete 433 733 +300
tcp6_check_fraglist_gro - 272 +272
tcp6_gro_complete 227 306 +79
tcp4_gro_complete 325 397 +72
ipv6_offload_init 218 274 +56
__pfx_tcp6_check_fraglist_gro - 16 +16
__pfx___skb_incr_checksum_unnecessary 32 - -32
__skb_incr_checksum_unnecessary 186 - -186
tcp6_gro_receive 959 706 -253
Total: Before=22592724, After=22593825, chg +0.00%
Eric Dumazet (3):
net: always inline __skb_incr_checksum_unnecessary()
gro: inline tcp6_gro_receive()
gro: inline tcp6_gro_complete()
include/linux/skbuff.h | 2 +-
include/net/tcp.h | 2 --
net/ipv6/Makefile | 2 +-
net/ipv6/ip6_offload.c | 43 ++++++++++++++++++++--------------------
net/ipv6/tcpv6_offload.c | 12 +++++------
5 files changed, 29 insertions(+), 32 deletions(-)
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH net-next 1/3] net: always inline __skb_incr_checksum_unnecessary() 2026-01-16 15:29 [PATCH net-next 0/3] gro: inline tcp6_gro_{receive,complete} Eric Dumazet @ 2026-01-16 15:29 ` Eric Dumazet 2026-01-16 15:29 ` [PATCH net-next 2/3] gro: inline tcp6_gro_receive() Eric Dumazet 2026-01-16 15:29 ` [PATCH net-next 3/3] gro: inline tcp6_gro_complete() Eric Dumazet 2 siblings, 0 replies; 7+ messages in thread From: Eric Dumazet @ 2026-01-16 15:29 UTC (permalink / raw) To: David S . Miller, Jakub Kicinski, Paolo Abeni Cc: Simon Horman, netdev, Willem de Bruijn, Kuniyuki Iwashima, eric.dumazet, Eric Dumazet clang does not inline this helper in GRO fast path. We can save space and cpu cycles. $ scripts/bloat-o-meter -t vmlinux.0 vmlinux.1 add/remove: 0/2 grow/shrink: 2/0 up/down: 156/-218 (-62) Function old new delta tcp6_gro_complete 227 311 +84 tcp4_gro_complete 325 397 +72 __pfx___skb_incr_checksum_unnecessary 32 - -32 __skb_incr_checksum_unnecessary 186 - -186 Total: Before=22592724, After=22592662, chg -0.00% Signed-off-by: Eric Dumazet <edumazet@google.com> --- include/linux/skbuff.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 86737076101d4a8452e90fe78adcdcfdefb79169..e6bfe5d0c5252b2e7540e1fef9317aab83feced2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4763,7 +4763,7 @@ static inline void __skb_decr_checksum_unnecessary(struct sk_buff *skb) } } -static inline void __skb_incr_checksum_unnecessary(struct sk_buff *skb) +static __always_inline void __skb_incr_checksum_unnecessary(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_UNNECESSARY) { if (skb->csum_level < SKB_MAX_CSUM_LEVEL) -- 2.52.0.457.g6b5491de43-goog ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 2/3] gro: inline tcp6_gro_receive() 2026-01-16 15:29 [PATCH net-next 0/3] gro: inline tcp6_gro_{receive,complete} Eric Dumazet 2026-01-16 15:29 ` [PATCH net-next 1/3] net: always inline __skb_incr_checksum_unnecessary() Eric Dumazet @ 2026-01-16 15:29 ` Eric Dumazet 2026-01-17 1:52 ` kernel test robot ` (2 more replies) 2026-01-16 15:29 ` [PATCH net-next 3/3] gro: inline tcp6_gro_complete() Eric Dumazet 2 siblings, 3 replies; 7+ messages in thread From: Eric Dumazet @ 2026-01-16 15:29 UTC (permalink / raw) To: David S . Miller, Jakub Kicinski, Paolo Abeni Cc: Simon Horman, netdev, Willem de Bruijn, Kuniyuki Iwashima, eric.dumazet, Eric Dumazet FDO/LTO are unable to inline tcp6_gro_receive() from ipv6_gro_receive() Make sure tcp6_check_fraglist_gro() is only called only when needed, so that compiler can leave it out-of-line. $ scripts/bloat-o-meter -t vmlinux.1 vmlinux.2 add/remove: 2/0 grow/shrink: 3/1 up/down: 1123/-253 (870) Function old new delta ipv6_gro_receive 1069 1846 +777 tcp6_check_fraglist_gro - 272 +272 ipv6_offload_init 218 274 +56 __pfx_tcp6_check_fraglist_gro - 16 +16 ipv6_gro_complete 433 435 +2 tcp6_gro_receive 959 706 -253 Total: Before=22592662, After=22593532, chg +0.00% Signed-off-by: Eric Dumazet <edumazet@google.com> --- include/net/tcp.h | 1 - net/ipv6/Makefile | 2 +- net/ipv6/ip6_offload.c | 22 +++++++++++++--------- net/ipv6/tcpv6_offload.c | 10 ++++------ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index ef0fee58fde82620399df49a35c7ecae8e34068e..2a7744de226ed0a378719fd60fa2a3830bef2e7e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2328,7 +2328,6 @@ struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb, INDIRECT_CALLABLE_DECLARE(int tcp4_gro_complete(struct sk_buff *skb, int thoff)); INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)); INDIRECT_CALLABLE_DECLARE(int tcp6_gro_complete(struct sk_buff *skb, int thoff)); -INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb)); #ifdef CONFIG_INET void tcp_gro_complete(struct sk_buff *skb); #else diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index d283c59df4c1c421bc043056fe11e5437cc4aece..0492f1a0b4918ada8c56cf649fbec04c7114863a 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -45,7 +45,7 @@ obj-$(CONFIG_IPV6_FOU) += fou6.o obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o obj-$(CONFIG_INET) += output_core.o protocol.o \ - ip6_offload.o tcpv6_offload.o exthdrs_offload.o + ip6_offload.o exthdrs_offload.o obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index fce91183797a60fcbf271c73e086aeb0aa9d40c6..4d96154c0dcd019322908ab6ddaa663a2a565e44 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -19,6 +19,7 @@ #include <net/gso.h> #include "ip6_offload.h" +#include "tcpv6_offload.c" /* All GRO functions are always builtin, except UDP over ipv6, which lays in * ipv6 module, as it depends on UDPv6 lookup function, so we need special care @@ -30,13 +31,6 @@ #define INDIRECT_CALL_L4(f, f2, f1, ...) INDIRECT_CALL_1(f, f2, __VA_ARGS__) #endif -#define indirect_call_gro_receive_l4(f2, f1, cb, head, skb) \ -({ \ - unlikely(gro_recursion_inc_test(skb)) ? \ - NAPI_GRO_CB(skb)->flush |= 1, NULL : \ - INDIRECT_CALL_L4(cb, f2, f1, head, skb); \ -}) - static int ipv6_gro_pull_exthdrs(struct sk_buff *skb, int off, int proto) { const struct net_offload *ops = NULL; @@ -298,9 +292,19 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head, skb_gro_postpull_rcsum(skb, iph, nlen); - pp = indirect_call_gro_receive_l4(tcp6_gro_receive, udp6_gro_receive, - ops->callbacks.gro_receive, head, skb); + if (unlikely(gro_recursion_inc_test(skb))) { + flush = 1; + goto out; + } + if (likely(proto == IPPROTO_TCP)) + pp = tcp6_gro_receive(head, skb); +#if IS_BUILTIN(CONFIG_IPV6) + else if (likely(proto == IPPROTO_UDP)) + pp = udp6_gro_receive(head, skb); +#endif + else + pp = ops->callbacks.gro_receive(head, skb); out: skb_gro_flush_final(skb, pp, flush); diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index effeba58630b5ac2593b824bd8fc10a473954b6c..7f19ce423058870f285b7f8ae2a4d116d783f9fb 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c @@ -24,9 +24,6 @@ static void tcp6_check_fraglist_gro(struct list_head *head, struct sk_buff *skb, struct net *net; int iif, sdif; - if (likely(!(skb->dev->features & NETIF_F_GRO_FRAGLIST))) - return; - p = tcp_gro_lookup(head, th); if (p) { NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist; @@ -45,8 +42,8 @@ static void tcp6_check_fraglist_gro(struct list_head *head, struct sk_buff *skb, #endif /* IS_ENABLED(CONFIG_IPV6) */ } -INDIRECT_CALLABLE_SCOPE -struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb) +static __always_inline struct sk_buff *tcp6_gro_receive(struct list_head *head, + struct sk_buff *skb) { struct tcphdr *th; @@ -60,7 +57,8 @@ struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb) if (!th) goto flush; - tcp6_check_fraglist_gro(head, skb, th); + if (unlikely(skb->dev->features & NETIF_F_GRO_FRAGLIST)) + tcp6_check_fraglist_gro(head, skb, th); return tcp_gro_receive(head, skb, th); -- 2.52.0.457.g6b5491de43-goog ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 2/3] gro: inline tcp6_gro_receive() 2026-01-16 15:29 ` [PATCH net-next 2/3] gro: inline tcp6_gro_receive() Eric Dumazet @ 2026-01-17 1:52 ` kernel test robot 2026-01-17 2:05 ` kernel test robot 2026-01-17 2:05 ` kernel test robot 2 siblings, 0 replies; 7+ messages in thread From: kernel test robot @ 2026-01-17 1:52 UTC (permalink / raw) To: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni Cc: llvm, oe-kbuild-all, Simon Horman, netdev, Willem de Bruijn, Kuniyuki Iwashima, eric.dumazet, Eric Dumazet Hi Eric, kernel test robot noticed the following build errors: [auto build test ERROR on net-next/main] url: https://github.com/intel-lab-lkp/linux/commits/Eric-Dumazet/net-always-inline-__skb_incr_checksum_unnecessary/20260116-233745 base: net-next/main patch link: https://lore.kernel.org/r/20260116152957.1825626-3-edumazet%40google.com patch subject: [PATCH net-next 2/3] gro: inline tcp6_gro_receive() config: i386-randconfig-011-20260117 (https://download.01.org/0day-ci/archive/20260117/202601170955.0wVpALLC-lkp@intel.com/config) compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601170955.0wVpALLC-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202601170955.0wVpALLC-lkp@intel.com/ All errors (new ones prefixed by >>): >> net/ipv6/ip6_offload.c:304:8: error: call to undeclared function 'udp6_gro_receive'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 304 | pp = udp6_gro_receive(head, skb); | ^ net/ipv6/ip6_offload.c:304:8: note: did you mean 'udp_gro_receive'? include/net/gro.h:419:17: note: 'udp_gro_receive' declared here 419 | struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb, | ^ >> net/ipv6/ip6_offload.c:304:6: error: incompatible integer to pointer conversion assigning to 'struct sk_buff *' from 'int' [-Wint-conversion] 304 | pp = udp6_gro_receive(head, skb); | ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 errors generated. vim +/udp6_gro_receive +304 net/ipv6/ip6_offload.c 215 216 INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head, 217 struct sk_buff *skb) 218 { 219 const struct net_offload *ops; 220 struct sk_buff *pp = NULL; 221 struct sk_buff *p; 222 struct ipv6hdr *iph; 223 unsigned int nlen; 224 unsigned int hlen; 225 unsigned int off; 226 u16 flush = 1; 227 int proto; 228 229 off = skb_gro_offset(skb); 230 hlen = off + sizeof(*iph); 231 iph = skb_gro_header(skb, hlen, off); 232 if (unlikely(!iph)) 233 goto out; 234 235 NAPI_GRO_CB(skb)->network_offsets[NAPI_GRO_CB(skb)->encap_mark] = off; 236 237 flush += ntohs(iph->payload_len) != skb->len - hlen; 238 239 proto = iph->nexthdr; 240 ops = rcu_dereference(inet6_offloads[proto]); 241 if (!ops || !ops->callbacks.gro_receive) { 242 proto = ipv6_gro_pull_exthdrs(skb, hlen, proto); 243 244 ops = rcu_dereference(inet6_offloads[proto]); 245 if (!ops || !ops->callbacks.gro_receive) 246 goto out; 247 248 iph = skb_gro_network_header(skb); 249 } else { 250 skb_gro_pull(skb, sizeof(*iph)); 251 } 252 253 skb_set_transport_header(skb, skb_gro_offset(skb)); 254 255 NAPI_GRO_CB(skb)->proto = proto; 256 257 flush--; 258 nlen = skb_gro_offset(skb) - off; 259 260 list_for_each_entry(p, head, list) { 261 const struct ipv6hdr *iph2; 262 __be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */ 263 264 if (!NAPI_GRO_CB(p)->same_flow) 265 continue; 266 267 iph2 = (struct ipv6hdr *)(p->data + off); 268 first_word = *(__be32 *)iph ^ *(__be32 *)iph2; 269 270 /* All fields must match except length and Traffic Class. 271 * XXX skbs on the gro_list have all been parsed and pulled 272 * already so we don't need to compare nlen 273 * (nlen != (sizeof(*iph2) + ipv6_exthdrs_len(iph2, &ops))) 274 * memcmp() alone below is sufficient, right? 275 */ 276 if ((first_word & htonl(0xF00FFFFF)) || 277 !ipv6_addr_equal(&iph->saddr, &iph2->saddr) || 278 !ipv6_addr_equal(&iph->daddr, &iph2->daddr) || 279 iph->nexthdr != iph2->nexthdr) { 280 not_same_flow: 281 NAPI_GRO_CB(p)->same_flow = 0; 282 continue; 283 } 284 if (unlikely(nlen > sizeof(struct ipv6hdr))) { 285 if (memcmp(iph + 1, iph2 + 1, 286 nlen - sizeof(struct ipv6hdr))) 287 goto not_same_flow; 288 } 289 } 290 291 NAPI_GRO_CB(skb)->flush |= flush; 292 293 skb_gro_postpull_rcsum(skb, iph, nlen); 294 295 if (unlikely(gro_recursion_inc_test(skb))) { 296 flush = 1; 297 goto out; 298 } 299 300 if (likely(proto == IPPROTO_TCP)) 301 pp = tcp6_gro_receive(head, skb); 302 #if IS_BUILTIN(CONFIG_IPV6) 303 else if (likely(proto == IPPROTO_UDP)) > 304 pp = udp6_gro_receive(head, skb); 305 #endif 306 else 307 pp = ops->callbacks.gro_receive(head, skb); 308 out: 309 skb_gro_flush_final(skb, pp, flush); 310 311 return pp; 312 } 313 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 2/3] gro: inline tcp6_gro_receive() 2026-01-16 15:29 ` [PATCH net-next 2/3] gro: inline tcp6_gro_receive() Eric Dumazet 2026-01-17 1:52 ` kernel test robot @ 2026-01-17 2:05 ` kernel test robot 2026-01-17 2:05 ` kernel test robot 2 siblings, 0 replies; 7+ messages in thread From: kernel test robot @ 2026-01-17 2:05 UTC (permalink / raw) To: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni Cc: oe-kbuild-all, Simon Horman, netdev, Willem de Bruijn, Kuniyuki Iwashima, eric.dumazet, Eric Dumazet Hi Eric, kernel test robot noticed the following build warnings: [auto build test WARNING on net-next/main] url: https://github.com/intel-lab-lkp/linux/commits/Eric-Dumazet/net-always-inline-__skb_incr_checksum_unnecessary/20260116-233745 base: net-next/main patch link: https://lore.kernel.org/r/20260116152957.1825626-3-edumazet%40google.com patch subject: [PATCH net-next 2/3] gro: inline tcp6_gro_receive() config: i386-randconfig-015-20260117 (https://download.01.org/0day-ci/archive/20260117/202601170903.keV6lwyg-lkp@intel.com/config) compiler: gcc-12 (Debian 12.4.0-5) 12.4.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601170903.keV6lwyg-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202601170903.keV6lwyg-lkp@intel.com/ All warnings (new ones prefixed by >>): net/ipv6/ip6_offload.c: In function 'ipv6_gro_receive': net/ipv6/ip6_offload.c:304:22: error: implicit declaration of function 'udp6_gro_receive'; did you mean 'udp_gro_receive'? [-Werror=implicit-function-declaration] 304 | pp = udp6_gro_receive(head, skb); | ^~~~~~~~~~~~~~~~ | udp_gro_receive >> net/ipv6/ip6_offload.c:304:20: warning: assignment to 'struct sk_buff *' from 'int' makes pointer from integer without a cast [-Wint-conversion] 304 | pp = udp6_gro_receive(head, skb); | ^ cc1: some warnings being treated as errors vim +304 net/ipv6/ip6_offload.c 215 216 INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head, 217 struct sk_buff *skb) 218 { 219 const struct net_offload *ops; 220 struct sk_buff *pp = NULL; 221 struct sk_buff *p; 222 struct ipv6hdr *iph; 223 unsigned int nlen; 224 unsigned int hlen; 225 unsigned int off; 226 u16 flush = 1; 227 int proto; 228 229 off = skb_gro_offset(skb); 230 hlen = off + sizeof(*iph); 231 iph = skb_gro_header(skb, hlen, off); 232 if (unlikely(!iph)) 233 goto out; 234 235 NAPI_GRO_CB(skb)->network_offsets[NAPI_GRO_CB(skb)->encap_mark] = off; 236 237 flush += ntohs(iph->payload_len) != skb->len - hlen; 238 239 proto = iph->nexthdr; 240 ops = rcu_dereference(inet6_offloads[proto]); 241 if (!ops || !ops->callbacks.gro_receive) { 242 proto = ipv6_gro_pull_exthdrs(skb, hlen, proto); 243 244 ops = rcu_dereference(inet6_offloads[proto]); 245 if (!ops || !ops->callbacks.gro_receive) 246 goto out; 247 248 iph = skb_gro_network_header(skb); 249 } else { 250 skb_gro_pull(skb, sizeof(*iph)); 251 } 252 253 skb_set_transport_header(skb, skb_gro_offset(skb)); 254 255 NAPI_GRO_CB(skb)->proto = proto; 256 257 flush--; 258 nlen = skb_gro_offset(skb) - off; 259 260 list_for_each_entry(p, head, list) { 261 const struct ipv6hdr *iph2; 262 __be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */ 263 264 if (!NAPI_GRO_CB(p)->same_flow) 265 continue; 266 267 iph2 = (struct ipv6hdr *)(p->data + off); 268 first_word = *(__be32 *)iph ^ *(__be32 *)iph2; 269 270 /* All fields must match except length and Traffic Class. 271 * XXX skbs on the gro_list have all been parsed and pulled 272 * already so we don't need to compare nlen 273 * (nlen != (sizeof(*iph2) + ipv6_exthdrs_len(iph2, &ops))) 274 * memcmp() alone below is sufficient, right? 275 */ 276 if ((first_word & htonl(0xF00FFFFF)) || 277 !ipv6_addr_equal(&iph->saddr, &iph2->saddr) || 278 !ipv6_addr_equal(&iph->daddr, &iph2->daddr) || 279 iph->nexthdr != iph2->nexthdr) { 280 not_same_flow: 281 NAPI_GRO_CB(p)->same_flow = 0; 282 continue; 283 } 284 if (unlikely(nlen > sizeof(struct ipv6hdr))) { 285 if (memcmp(iph + 1, iph2 + 1, 286 nlen - sizeof(struct ipv6hdr))) 287 goto not_same_flow; 288 } 289 } 290 291 NAPI_GRO_CB(skb)->flush |= flush; 292 293 skb_gro_postpull_rcsum(skb, iph, nlen); 294 295 if (unlikely(gro_recursion_inc_test(skb))) { 296 flush = 1; 297 goto out; 298 } 299 300 if (likely(proto == IPPROTO_TCP)) 301 pp = tcp6_gro_receive(head, skb); 302 #if IS_BUILTIN(CONFIG_IPV6) 303 else if (likely(proto == IPPROTO_UDP)) > 304 pp = udp6_gro_receive(head, skb); 305 #endif 306 else 307 pp = ops->callbacks.gro_receive(head, skb); 308 out: 309 skb_gro_flush_final(skb, pp, flush); 310 311 return pp; 312 } 313 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 2/3] gro: inline tcp6_gro_receive() 2026-01-16 15:29 ` [PATCH net-next 2/3] gro: inline tcp6_gro_receive() Eric Dumazet 2026-01-17 1:52 ` kernel test robot 2026-01-17 2:05 ` kernel test robot @ 2026-01-17 2:05 ` kernel test robot 2 siblings, 0 replies; 7+ messages in thread From: kernel test robot @ 2026-01-17 2:05 UTC (permalink / raw) To: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni Cc: oe-kbuild-all, Simon Horman, netdev, Willem de Bruijn, Kuniyuki Iwashima, eric.dumazet, Eric Dumazet Hi Eric, kernel test robot noticed the following build errors: [auto build test ERROR on net-next/main] url: https://github.com/intel-lab-lkp/linux/commits/Eric-Dumazet/net-always-inline-__skb_incr_checksum_unnecessary/20260116-233745 base: net-next/main patch link: https://lore.kernel.org/r/20260116152957.1825626-3-edumazet%40google.com patch subject: [PATCH net-next 2/3] gro: inline tcp6_gro_receive() config: powerpc-ge_imp3a_defconfig (https://download.01.org/0day-ci/archive/20260117/202601170958.L4uFo8qq-lkp@intel.com/config) compiler: powerpc-linux-gcc (GCC) 15.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601170958.L4uFo8qq-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202601170958.L4uFo8qq-lkp@intel.com/ All errors (new ones prefixed by >>): net/ipv6/ip6_offload.c: In function 'ipv6_gro_receive': >> net/ipv6/ip6_offload.c:304:22: error: implicit declaration of function 'udp6_gro_receive'; did you mean 'udp_gro_receive'? [-Wimplicit-function-declaration] 304 | pp = udp6_gro_receive(head, skb); | ^~~~~~~~~~~~~~~~ | udp_gro_receive >> net/ipv6/ip6_offload.c:304:20: error: assignment to 'struct sk_buff *' from 'int' makes pointer from integer without a cast [-Wint-conversion] 304 | pp = udp6_gro_receive(head, skb); | ^ vim +304 net/ipv6/ip6_offload.c 215 216 INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head, 217 struct sk_buff *skb) 218 { 219 const struct net_offload *ops; 220 struct sk_buff *pp = NULL; 221 struct sk_buff *p; 222 struct ipv6hdr *iph; 223 unsigned int nlen; 224 unsigned int hlen; 225 unsigned int off; 226 u16 flush = 1; 227 int proto; 228 229 off = skb_gro_offset(skb); 230 hlen = off + sizeof(*iph); 231 iph = skb_gro_header(skb, hlen, off); 232 if (unlikely(!iph)) 233 goto out; 234 235 NAPI_GRO_CB(skb)->network_offsets[NAPI_GRO_CB(skb)->encap_mark] = off; 236 237 flush += ntohs(iph->payload_len) != skb->len - hlen; 238 239 proto = iph->nexthdr; 240 ops = rcu_dereference(inet6_offloads[proto]); 241 if (!ops || !ops->callbacks.gro_receive) { 242 proto = ipv6_gro_pull_exthdrs(skb, hlen, proto); 243 244 ops = rcu_dereference(inet6_offloads[proto]); 245 if (!ops || !ops->callbacks.gro_receive) 246 goto out; 247 248 iph = skb_gro_network_header(skb); 249 } else { 250 skb_gro_pull(skb, sizeof(*iph)); 251 } 252 253 skb_set_transport_header(skb, skb_gro_offset(skb)); 254 255 NAPI_GRO_CB(skb)->proto = proto; 256 257 flush--; 258 nlen = skb_gro_offset(skb) - off; 259 260 list_for_each_entry(p, head, list) { 261 const struct ipv6hdr *iph2; 262 __be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */ 263 264 if (!NAPI_GRO_CB(p)->same_flow) 265 continue; 266 267 iph2 = (struct ipv6hdr *)(p->data + off); 268 first_word = *(__be32 *)iph ^ *(__be32 *)iph2; 269 270 /* All fields must match except length and Traffic Class. 271 * XXX skbs on the gro_list have all been parsed and pulled 272 * already so we don't need to compare nlen 273 * (nlen != (sizeof(*iph2) + ipv6_exthdrs_len(iph2, &ops))) 274 * memcmp() alone below is sufficient, right? 275 */ 276 if ((first_word & htonl(0xF00FFFFF)) || 277 !ipv6_addr_equal(&iph->saddr, &iph2->saddr) || 278 !ipv6_addr_equal(&iph->daddr, &iph2->daddr) || 279 iph->nexthdr != iph2->nexthdr) { 280 not_same_flow: 281 NAPI_GRO_CB(p)->same_flow = 0; 282 continue; 283 } 284 if (unlikely(nlen > sizeof(struct ipv6hdr))) { 285 if (memcmp(iph + 1, iph2 + 1, 286 nlen - sizeof(struct ipv6hdr))) 287 goto not_same_flow; 288 } 289 } 290 291 NAPI_GRO_CB(skb)->flush |= flush; 292 293 skb_gro_postpull_rcsum(skb, iph, nlen); 294 295 if (unlikely(gro_recursion_inc_test(skb))) { 296 flush = 1; 297 goto out; 298 } 299 300 if (likely(proto == IPPROTO_TCP)) 301 pp = tcp6_gro_receive(head, skb); 302 #if IS_BUILTIN(CONFIG_IPV6) 303 else if (likely(proto == IPPROTO_UDP)) > 304 pp = udp6_gro_receive(head, skb); 305 #endif 306 else 307 pp = ops->callbacks.gro_receive(head, skb); 308 out: 309 skb_gro_flush_final(skb, pp, flush); 310 311 return pp; 312 } 313 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net-next 3/3] gro: inline tcp6_gro_complete() 2026-01-16 15:29 [PATCH net-next 0/3] gro: inline tcp6_gro_{receive,complete} Eric Dumazet 2026-01-16 15:29 ` [PATCH net-next 1/3] net: always inline __skb_incr_checksum_unnecessary() Eric Dumazet 2026-01-16 15:29 ` [PATCH net-next 2/3] gro: inline tcp6_gro_receive() Eric Dumazet @ 2026-01-16 15:29 ` Eric Dumazet 2 siblings, 0 replies; 7+ messages in thread From: Eric Dumazet @ 2026-01-16 15:29 UTC (permalink / raw) To: David S . Miller, Jakub Kicinski, Paolo Abeni Cc: Simon Horman, netdev, Willem de Bruijn, Kuniyuki Iwashima, eric.dumazet, Eric Dumazet Remove one function call from GRO stack for native IPv6 + TCP packets. $ scripts/bloat-o-meter -t vmlinux.2 vmlinux.3 add/remove: 0/0 grow/shrink: 1/1 up/down: 298/-5 (293) Function old new delta ipv6_gro_complete 435 733 +298 tcp6_gro_complete 311 306 -5 Total: Before=22593532, After=22593825, chg +0.00% Signed-off-by: Eric Dumazet <edumazet@google.com> --- include/net/tcp.h | 1 - net/ipv6/ip6_offload.c | 21 +++++++++------------ net/ipv6/tcpv6_offload.c | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 2a7744de226ed0a378719fd60fa2a3830bef2e7e..68bc08c40d5435ce196dd492b46b5d81f8e29b3f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2327,7 +2327,6 @@ struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb, struct tcphdr *th); INDIRECT_CALLABLE_DECLARE(int tcp4_gro_complete(struct sk_buff *skb, int thoff)); INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)); -INDIRECT_CALLABLE_DECLARE(int tcp6_gro_complete(struct sk_buff *skb, int thoff)); #ifdef CONFIG_INET void tcp_gro_complete(struct sk_buff *skb); #else diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 4d96154c0dcd019322908ab6ddaa663a2a565e44..32a104ead8760d33e152e0b0a6a6896d70d155b5 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -21,16 +21,6 @@ #include "ip6_offload.h" #include "tcpv6_offload.c" -/* All GRO functions are always builtin, except UDP over ipv6, which lays in - * ipv6 module, as it depends on UDPv6 lookup function, so we need special care - * when ipv6 is built as a module - */ -#if IS_BUILTIN(CONFIG_IPV6) -#define INDIRECT_CALL_L4(f, f2, f1, ...) INDIRECT_CALL_2(f, f2, f1, __VA_ARGS__) -#else -#define INDIRECT_CALL_L4(f, f2, f1, ...) INDIRECT_CALL_1(f, f2, __VA_ARGS__) -#endif - static int ipv6_gro_pull_exthdrs(struct sk_buff *skb, int off, int proto) { const struct net_offload *ops = NULL; @@ -383,11 +373,18 @@ INDIRECT_CALLABLE_SCOPE int ipv6_gro_complete(struct sk_buff *skb, int nhoff) } nhoff += sizeof(*iph) + ipv6_exthdrs_len(iph, &ops); + + if (likely(ops == &net_hotdata.tcpv6_offload)) + return tcp6_gro_complete(skb, nhoff); +#if IS_BUILTIN(CONFIG_IPV6) + if (ops == &net_hotdata.udpv6_offload) + return udp6_gro_complete(skb, nhoff); +#endif + if (WARN_ON(!ops || !ops->callbacks.gro_complete)) goto out; - err = INDIRECT_CALL_L4(ops->callbacks.gro_complete, tcp6_gro_complete, - udp6_gro_complete, skb, nhoff); + err = ops->callbacks.gro_complete(skb, nhoff); out: return err; diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index 7f19ce423058870f285b7f8ae2a4d116d783f9fb..46fa2069d321663ed232e2836db77e3fcb1f4f07 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c @@ -67,7 +67,7 @@ static __always_inline struct sk_buff *tcp6_gro_receive(struct list_head *head, return NULL; } -INDIRECT_CALLABLE_SCOPE int tcp6_gro_complete(struct sk_buff *skb, int thoff) +static __always_inline int tcp6_gro_complete(struct sk_buff *skb, int thoff) { const u16 offset = NAPI_GRO_CB(skb)->network_offsets[skb->encapsulation]; const struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + offset); -- 2.52.0.457.g6b5491de43-goog ^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-01-17 2:05 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-16 15:29 [PATCH net-next 0/3] gro: inline tcp6_gro_{receive,complete} Eric Dumazet
2026-01-16 15:29 ` [PATCH net-next 1/3] net: always inline __skb_incr_checksum_unnecessary() Eric Dumazet
2026-01-16 15:29 ` [PATCH net-next 2/3] gro: inline tcp6_gro_receive() Eric Dumazet
2026-01-17 1:52 ` kernel test robot
2026-01-17 2:05 ` kernel test robot
2026-01-17 2:05 ` kernel test robot
2026-01-16 15:29 ` [PATCH net-next 3/3] gro: inline tcp6_gro_complete() Eric Dumazet
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox