From: Alexander Lobakin <hidden> Date: 2021-03-18 18:43:12
dev_gro_receive() uses indirect calls for IP GRO functions, but
it works only for the outermost headers and untagged frames.
Simple VLAN tag before an IP header restores the performance hit.
This simple series straightens the GRO calls for IP headers going
after VLAN tag or inner Ethernet header (GENEVE, NvGRE, VxLAN)
for retpolined kernels.
Alexander Lobakin (4):
gro: make net/gro.h self-contained
gro: add combined call_gro_receive() + INDIRECT_CALL_INET() helper
vlan/8021q: avoid retpoline overhead on GRO
ethernet: avoid retpoline overhead on TEB (GENEVE, NvGRE, VxLAN) GRO
include/net/gro.h | 13 +++++++++++++
net/8021q/vlan_core.c | 10 ++++++++--
net/ethernet/eth.c | 11 ++++++++---
3 files changed, 29 insertions(+), 5 deletions(-)
--
2.31.0
From: Alexander Lobakin <hidden> Date: 2021-03-18 18:43:12
If some source file includes <net/gro.h>, but doesn't include
<linux/indirect_call_wrapper.h>:
In file included from net/8021q/vlan_core.c:7:
./include/net/gro.h:6:1: warning: data definition has no type or storage class
6 | INDIRECT_CALLABLE_DECLARE(struct sk_buff *ipv6_gro_receive(struct list_head *,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
./include/net/gro.h:6:1: error: type defaults to ‘int’ in declaration of ‘INDIRECT_CALLABLE_DECLARE’ [-Werror=implicit-int]
[...]
Include <linux/indirect_call_wrapper.h> directly. It's small and
won't pull lots of dependencies.
Also add some incomplete struct declarations to be fully stacked.
Fixes: 04f00ab2275f ("net/core: move gro function declarations to separate header ")
Signed-off-by: Alexander Lobakin <redacted>
---
include/net/gro.h | 5 +++++
1 file changed, 5 insertions(+)
From: Alexander Lobakin <hidden> Date: 2021-03-18 18:43:12
call_gro_receive() is used to limit GRO recursion, but it works only
with callback pointers.
There's a combined version of call_gro_receive() + INDIRECT_CALL_2()
in <net/inet_common.h>, but it doesn't check for IPv6 modularity.
Add a similar new helper to cover both of these. It can and will be
used to avoid retpoline overhead when IP header lies behind another
offloaded proto.
Signed-off-by: Alexander Lobakin <redacted>
---
include/net/gro.h | 8 ++++++++
1 file changed, 8 insertions(+)
From: Alexander Lobakin <hidden> Date: 2021-03-18 18:43:44
The two most popular headers going after VLAN are IPv4 and IPv6.
Retpoline overhead for them is addressed only in dev_gro_receive(),
when they lie right after the outermost Ethernet header.
Use the indirect call wrappers in VLAN GRO receive code to reduce
the penalty on receiving tagged frames (when hardware stripping is
off or not available).
Signed-off-by: Alexander Lobakin <redacted>
---
net/8021q/vlan_core.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
From: Alexander Lobakin <hidden> Date: 2021-03-18 18:43:44
The two most popular headers going after Ethernet are IPv4 and IPv6.
Retpoline overhead for them is addressed only in dev_gro_receive(),
when they lie right after the outermost Ethernet header.
Use the indirect call wrappers in TEB (Transparent Ethernet Bridging,
such as GENEVE, NvGRE, VxLAN etc.) GRO receive code to reduce the
penalty when processing the inner headers.
Signed-off-by: Alexander Lobakin <redacted>
---
net/ethernet/eth.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
@@ -473,8 +477,9 @@ int eth_gro_complete(struct sk_buff *skb, int nhoff)rcu_read_lock();ptype=gro_find_complete_by_type(type);if(ptype!=NULL)-err=ptype->callbacks.gro_complete(skb,nhoff+-sizeof(structethhdr));+err=INDIRECT_CALL_INET(ptype->callbacks.gro_complete,+ipv6_gro_complete,inet_gro_complete,+skb,nhoff+sizeof(*eh));rcu_read_unlock();returnerr;--
From: Paolo Abeni <pabeni@redhat.com> Date: 2021-03-19 10:54:57
Hello,
On Thu, 2021-03-18 at 18:42 +0000, Alexander Lobakin wrote:
call_gro_receive() is used to limit GRO recursion, but it works only
with callback pointers.
There's a combined version of call_gro_receive() + INDIRECT_CALL_2()
in <net/inet_common.h>, but it doesn't check for IPv6 modularity.
AFAICS, ip6_offload is builtin even when IPv6 is a module, so the above
should not be needed.
Cheers,
Paolo
From: Alexander Lobakin <hidden> Date: 2021-03-19 11:14:08
From: Paolo Abeni <pabeni@redhat.com>
Date: Fri, 19 Mar 2021 11:53:42 +0100
Hello,
Hi!
On Thu, 2021-03-18 at 18:42 +0000, Alexander Lobakin wrote:
quoted
call_gro_receive() is used to limit GRO recursion, but it works only
with callback pointers.
There's a combined version of call_gro_receive() + INDIRECT_CALL_2()
in <net/inet_common.h>, but it doesn't check for IPv6 modularity.
AFAICS, ip6_offload is builtin even when IPv6 is a module, so the above
should not be needed.
Aww, you are right. I overlooked that since dev_gro_receive() still
use INDIRECT_CALL_INET(), though all GRO callbacks were made
built-in.
Seems like more code can be optimized, thanks!
From: Alexander Lobakin <hidden> Date: 2021-03-19 11:43:56
From: Alexander Lobakin <redacted>
Date: Fri, 19 Mar 2021 11:13:25 +0000
From: Paolo Abeni <pabeni@redhat.com>
Date: Fri, 19 Mar 2021 11:53:42 +0100
quoted
Hello,
Hi!
quoted
On Thu, 2021-03-18 at 18:42 +0000, Alexander Lobakin wrote:
quoted
call_gro_receive() is used to limit GRO recursion, but it works only
with callback pointers.
There's a combined version of call_gro_receive() + INDIRECT_CALL_2()
in <net/inet_common.h>, but it doesn't check for IPv6 modularity.
AFAICS, ip6_offload is builtin even when IPv6 is a module, so the above
should not be needed.
Aww, you are right. I overlooked that since dev_gro_receive() still
use INDIRECT_CALL_INET(), though all GRO callbacks were made
built-in.
I'm not sure if you did it on purpose in commit aaa5d90b395a7
("net: use indirect call wrappers at GRO network layer").
Was that intentional for the sake of more optimized path for the
kernels with moduled IPv6, or I can replace INDIRECT_CALL_INET()
with INDIRECT_CALL_2() here too? I want to keep GRO callbacks that
make use of indirect call wrappers unified.
From: Alexander Lobakin <hidden> Date: 2021-03-19 12:50:50
From: Paolo Abeni <pabeni@redhat.com>
Date: Fri, 19 Mar 2021 13:35:41 +0100
On Fri, 2021-03-19 at 11:43 +0000, Alexander Lobakin wrote:
quoted
I'm not sure if you did it on purpose in commit aaa5d90b395a7
("net: use indirect call wrappers at GRO network layer").
Was that intentional
I must admit that 2y+ later my own intentions are not so clear to me
too;)
Heh, know that feel (=
quoted
for the sake of more optimized path for the
kernels with moduled IPv6,
Uhm... no I guess that was more an underlook on my side.
quoted
or I can replace INDIRECT_CALL_INET()
with INDIRECT_CALL_2() here too?
If that build with IPV6=nmy, I would say yes.
I think you used INDIRECT_CALL_INET() to protect from CONFIG_INET=n.
But this also hurts with retpoline when CONFIG_IPV6=m. Not so common
case, but still.
Plain INDIRECT_CALL_2() won't build without CONFIG_INET, so we either
introduce a new one (e.g. _INET_2() similarly to _INET_1()), or leave
it as it is for now (Dave's already picked this series to net-next).
quoted
I want to keep GRO callbacks that
make use of indirect call wrappers unified.
L4 will still need some special handling as ipv6 udp gro callbacks are
not builtin with CONFIG_IPV6=m :(
Yep, I remember. I meant {inet,ipv6}_gro_{complete,receive}()
callers, but didn't mention that for some reason.