Netdev List
 help / color / mirror / Atom feed
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