From: Antonio Quartulli <antonio@mandelbit.com>
To: pablo@netfilter.org, fw@strlen.de
Cc: Antonio Quartulli <antonio@mandelbit.com>,
phil@nwl.cc, steffen.klassert@secunet.com,
herbert@gondor.apana.org.au, davem@davemloft.net,
edumazet@kernel.org, kuba@kernel.org, pabeni@redhat.com,
horms@kernel.org, netfilter-devel@vger.kernel.org,
coreteam@netfilter.org, netdev@vger.kernel.org
Subject: [PATCH nf-next] netfilter: nf_nat: skip the xfrm re-lookup without outbound policies
Date: Wed, 11 Nov 2026 09:44:10 +0100 [thread overview]
Message-ID: <20261111084412.2702283-1-antonio@mandelbit.com> (raw)
nf_xfrm_me_harder() decodes the session and redoes the xfrm lookup for
every packet whose source or ports NAT changed, even when there is no
policy that could match. The session decode alone is a sizeable part of
the NAT path.
Skip it when there is no outbound policy, global or per socket, the
default outbound policy accepts and the dst is not a bundle: the lookup
would return the same route. xfrm_route_forward() takes the same
shortcut for forwarded packets.
This is the common case for masquerading routers built with
CONFIG_XFRM that never use IPsec. Forwarding a 1400-byte packet through
conntrack and masquerade (x86, qemu -icount) drops from 7533 to 7091
instructions for UDP (-5.9%) and from 7835 to 7395 for TCP (-5.6%).
With an outbound policy installed the full path still runs, and a
block policy matching only the masqueraded flow still drops it.
Signed-off-by: Antonio Quartulli <antonio@mandelbit.com>
---
net/netfilter/nf_nat_proto.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/net/netfilter/nf_nat_proto.c b/net/netfilter/nf_nat_proto.c
index 64b9bac228ea..69849d805984 100644
--- a/net/netfilter/nf_nat_proto.c
+++ b/net/netfilter/nf_nat_proto.c
@@ -600,12 +600,25 @@ nf_nat_ipv4_pre_routing(void *priv, struct sk_buff *skb,
#ifdef CONFIG_XFRM
static int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
{
+ const struct netns_xfrm *xfrm = &net->xfrm;
struct sock *sk = skb->sk;
struct dst_entry *dst;
unsigned int hh_len;
struct flowi fl;
int err;
+ /* Without any outbound policy, global or per socket, and with the
+ * default outbound policy accepting, the lookup below cannot change
+ * the route unless the dst is already a bundle: skip it, and the
+ * session decode it needs.
+ */
+ if (!READ_ONCE(xfrm->policy_count[XFRM_POLICY_OUT]) &&
+ !READ_ONCE(xfrm->policy_count[XFRM_POLICY_MAX + XFRM_POLICY_OUT]) &&
+ READ_ONCE(xfrm->policy_default[XFRM_POLICY_OUT]) ==
+ XFRM_USERPOLICY_ACCEPT &&
+ !skb_dst(skb)->xfrm)
+ return 0;
+
err = xfrm_decode_session(net, skb, &fl, family);
if (err < 0)
return err;
--
2.56.0
reply other threads:[~2026-11-11 8:44 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261111084412.2702283-1-antonio@mandelbit.com \
--to=antonio@mandelbit.com \
--cc=coreteam@netfilter.org \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=fw@strlen.de \
--cc=herbert@gondor.apana.org.au \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pablo@netfilter.org \
--cc=phil@nwl.cc \
--cc=steffen.klassert@secunet.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox