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 01/14] netfilter: flowtable: fix offloaded ct timeout never being extended
Date: Sun, 21 Jun 2026 00:27:25 +0200 [thread overview]
Message-ID: <20260620222738.112506-2-pablo@netfilter.org> (raw)
In-Reply-To: <20260620222738.112506-1-pablo@netfilter.org>
From: Adrian Bente <adibente@gmail.com>
OpenWrt has recently migrated many platforms to kernel 6.18. On the
MediaTek platform, which supports hardware network offloading, WiFi
connections accelerated via the WED path were observed to drop after
roughly 300 seconds.
After several debugging sessions, assisted by the Claude LLM, the
problem was narrowed down as follows:
nf_flow_table_extend_ct_timeout() extends ct->timeout for offloaded
flows using:
cmpxchg(&ct->timeout, expires, new_timeout);
'expires' comes from nf_ct_expires(ct) and is a relative value, while
ct->timeout holds an absolute timestamp. The two are never equal, so
the cmpxchg always fails and the timeout is never extended.
This goes unnoticed for most flows, but a long-lived hardware (WED)
offloaded flow on MediaTek MT7986 eventually has ct->timeout decay to
zero, the conntrack entry is reaped and the connection breaks.
Open-code the relative value from a single READ_ONCE(ct->timeout)
snapshot and compare against that same absolute snapshot in the
cmpxchg, so the timeout extension actually takes effect while the
datapath remains authoritative if it updates ct->timeout concurrently.
Fixes: 03428ca5cee9 ("netfilter: conntrack: rework offload nf_conn timeout extension logic")
Cc: stable@vger.kernel.org
Suggested-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Adrian Bente <adibente@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_flow_table_core.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 785d8c244a77..99c5b9d671a0 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -505,8 +505,13 @@ static u32 nf_flow_table_tcp_timeout(const struct nf_conn *ct)
*/
static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct)
{
- static const u32 min_timeout = 5 * 60 * HZ;
- u32 expires = nf_ct_expires(ct);
+ static const s32 min_timeout = 5 * 60 * HZ;
+ u32 ct_timeout = READ_ONCE(ct->timeout);
+ s32 expires;
+
+ expires = ct_timeout - nfct_time_stamp;
+ if (expires <= 0) /* already expired */
+ return;
/* normal case: large enough timeout, nothing to do. */
if (likely(expires >= min_timeout))
@@ -524,7 +529,7 @@ static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct)
if (nf_ct_is_confirmed(ct) &&
test_bit(IPS_OFFLOAD_BIT, &ct->status)) {
u8 l4proto = nf_ct_protonum(ct);
- u32 new_timeout = true;
+ u32 new_timeout = 1;
switch (l4proto) {
case IPPROTO_UDP:
@@ -549,7 +554,7 @@ static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct)
*/
if (new_timeout) {
new_timeout += nfct_time_stamp;
- cmpxchg(&ct->timeout, expires, new_timeout);
+ cmpxchg(&ct->timeout, ct_timeout, new_timeout);
}
}
--
2.47.3
next prev parent reply other threads:[~2026-06-20 22:27 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-20 22:27 [PATCH net,v2 00/14] Netfilter fixes for net Pablo Neira Ayuso
2026-06-20 22:27 ` Pablo Neira Ayuso [this message]
2026-06-20 22:27 ` [PATCH net 02/14] netfilter: nf_queue: pin bridge device while NFQUEUE holds fake dst Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 03/14] netfilter: xt_cluster: reject template conntracks in hash match Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 04/14] netfilter: flowtable: fix and simplify IP6IP6 tunnel handling Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 05/14] netfilter: ipset: Don't use test_bit() in lockless RCU readers in hash types Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 06/14] netfilter: ipset: Don't use test_bit() in lockless RCU readers in bitmap types Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 07/14] netfilter: ipset: fix order of kfree_rcu() and rcu_assign_pointer() Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 08/14] netfilter: ipset: make sure gc is properly stopped Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 09/14] netfilter: nft_payload: reject offsets exceeding 65535 bytes Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 10/14] netfilter: nft_meta_bridge: add validate callback for get operations Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 11/14] netfilter: nft_flow_offload: zero device address for non-ether case Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 12/14] netfilter: nf_reject: skip iphdr options when looking for icmp header Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 13/14] netfilter: nf_conntrack_expect: use conntrack GC to reap expectations Pablo Neira Ayuso
2026-06-20 22:27 ` [PATCH net 14/14] netfilter: nft_meta_bridge: fix NFT_META_BRI_IIFPVID stack leak 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=20260620222738.112506-2-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