From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: davem@davemloft.net, netdev@vger.kernel.org, kuba@kernel.org,
pabeni@redhat.com, edumazet@google.com, fw@strlen.de,
horms@kernel.org
Subject: [PATCH net 03/13] netfilter: nf_conntrack_expect: add and use nf_ct_expect_related_pair()
Date: Wed, 22 Jul 2026 23:14:10 +0200 [thread overview]
Message-ID: <20260722211420.153933-4-pablo@netfilter.org> (raw)
In-Reply-To: <20260722211420.153933-1-pablo@netfilter.org>
Add a new function to insert a pair of expectations, this is required by
the SIP and H323 NAT helpers. The spinlock is held to check if there is
a slot for both expectations, in such case, insert them.
This removes the need for nf_ct_unexpect_related() inside the loop to
find a pair of consecutive ports, otherwise inserting expectations whose
dead flag is already set on can happen.
Bump master_help->expecting for the expectation class after checking if
the expectation fits in the master expectation list, which is needed for
this new _pair() function variant to run the eviction routine including
the preallocated slot for the first expectation in the pair.
Fixes: b8b09dc2bf35 ("netfilter: nf_conntrack_expect: use conntrack GC to reap expectations")
Reported-by: Jaeyeong Lee <iostreampy@proton.me>
Link: https://patch.msgid.link/178377968720.33756.12204817361601593230@proton.me/
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_conntrack_expect.h | 3 ++
net/ipv4/netfilter/nf_nat_h323.c | 22 +++++--------
net/netfilter/nf_conntrack_expect.c | 35 ++++++++++++++++++++-
net/netfilter/nf_nat_sip.c | 20 ++++--------
4 files changed, 50 insertions(+), 30 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index c024345c9bd8..26d6babd92fc 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -161,6 +161,9 @@ static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect,
return nf_ct_expect_related_report(expect, 0, 0, flags);
}
+int nf_ct_expect_related_pair(struct nf_conntrack_expect *expect[],
+ unsigned int flag);
+
struct nf_conn_help;
void nf_ct_expectation_gc(struct nf_conn_help *master_help);
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 183e8a3ff2ba..6bcd6734769b 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -182,6 +182,7 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp)
{
+ struct nf_conntrack_expect *rtp_pair[2] = { rtp_exp, rtcp_exp };
struct nf_ct_h323_master *info = nfct_help_data(ct);
int dir = CTINFO2DIR(ctinfo);
int i;
@@ -227,22 +228,13 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
int ret;
rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
- ret = nf_ct_expect_related(rtp_exp, 0);
+ rtcp_exp->tuple.dst.u.udp.port = htons(nated_port + 1);
+ ret = nf_ct_expect_related_pair(rtp_pair, 0);
if (ret == 0) {
- rtcp_exp->tuple.dst.u.udp.port =
- htons(nated_port + 1);
- ret = nf_ct_expect_related(rtcp_exp, 0);
- if (ret == 0)
- break;
- else if (ret == -EBUSY) {
- nf_ct_unexpect_related(rtp_exp);
- continue;
- } else if (ret < 0) {
- nf_ct_unexpect_related(rtp_exp);
- nated_port = 0;
- break;
- }
- } else if (ret != -EBUSY) {
+ break;
+ } else if (ret == -EBUSY) {
+ continue;
+ } else if (ret < 0) {
nated_port = 0;
break;
}
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 7ae68d60586a..8a3b9e33e94f 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -427,7 +427,6 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp,
exp->timeout += helper->expect_policy[exp->class].timeout * HZ;
hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
- master_help->expecting[exp->class]++;
hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
cnet = nf_ct_pernet(net);
@@ -534,6 +533,7 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
if (ret < 0)
goto out;
+ master_help->expecting[expect->class]++;
nf_ct_expect_insert(expect, master_help);
nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
@@ -546,6 +546,39 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
}
EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
+int nf_ct_expect_related_pair(struct nf_conntrack_expect *expect[],
+ unsigned int flags)
+{
+ struct nf_conn_help *master_help;
+ int i, ret;
+
+ spin_lock_bh(&nf_conntrack_expect_lock);
+ master_help = nfct_help(expect[0]->master);
+ if (!master_help || master_help != nfct_help(expect[1]->master)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = __nf_ct_expect_check(expect[i], master_help, flags);
+ if (ret < 0) {
+ if (i == 1)
+ master_help->expecting[expect[0]->class]--;
+ goto out;
+ }
+ master_help->expecting[expect[i]->class]++;
+ }
+
+ for (i = 0; i < 2; i++) {
+ nf_ct_expect_insert(expect[i], master_help);
+ nf_ct_expect_event_report(IPEXP_NEW, expect[i], 0, 0);
+ }
+out:
+ spin_unlock_bh(&nf_conntrack_expect_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nf_ct_expect_related_pair);
+
void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data),
void *data)
{
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c
index a93eaf0f7d30..133bd713fe0c 100644
--- a/net/netfilter/nf_nat_sip.c
+++ b/net/netfilter/nf_nat_sip.c
@@ -592,6 +592,7 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
unsigned int medialen,
union nf_inet_addr *rtp_addr)
{
+ struct nf_conntrack_expect *rtp_pair[2] = { rtp_exp, rtcp_exp };
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -622,24 +623,15 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
int ret;
rtp_exp->tuple.dst.u.udp.port = htons(port);
- ret = nf_ct_expect_related(rtp_exp,
- NF_CT_EXP_F_SKIP_MASTER);
- if (ret == -EBUSY)
- continue;
- else if (ret < 0) {
- port = 0;
- break;
- }
rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
- ret = nf_ct_expect_related(rtcp_exp,
- NF_CT_EXP_F_SKIP_MASTER);
+
+ ret = nf_ct_expect_related_pair(rtp_pair,
+ NF_CT_EXP_F_SKIP_MASTER);
if (ret == 0)
break;
- else if (ret == -EBUSY) {
- nf_ct_unexpect_related(rtp_exp);
+ else if (ret == -EBUSY)
continue;
- } else if (ret < 0) {
- nf_ct_unexpect_related(rtp_exp);
+ else if (ret < 0) {
port = 0;
break;
}
--
2.47.3
next prev parent reply other threads:[~2026-07-22 21:14 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-22 21:14 [PATCH net 00/13] Netfilter/IPVS fixes for net Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 01/13] netfilter: nf_conntrack_sip: widen NAT rewrite delta to s32 in sip_help_tcp() Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 02/13] selftests: netfilter: nft_flowtable.sh: fix offload counter verification for tunnel tests Pablo Neira Ayuso
2026-07-22 21:14 ` Pablo Neira Ayuso [this message]
2026-07-22 21:14 ` [PATCH net 04/13] netfilter: ipset: do not update comments from kernel-side hash adds Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 05/13] ipvs: do not propagate one-packet flag to synced conns Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 06/13] ipvs: adjust double hashing when fwd method changes Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 07/13] netfilter: nf_tables: make nft_object rhltable per table Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 08/13] netfilter: xt_hashlimit: validate hashtable supports XT_HASHLIMIT_RATE_MATCH Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 09/13] ipvs: fix the checksum validations Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 10/13] ipvs: fix places with wrong packet offsets Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 11/13] ipvs: do not mangle ICMP replies for non-first fragments Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 12/13] ipvs: clear the nfct flag under lock Pablo Neira Ayuso
2026-07-22 21:14 ` [PATCH net 13/13] netfilter: nft_payload: fix mask build for partial field offload Pablo Neira Ayuso
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=20260722211420.153933-4-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.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