Skip to content

Commit ad6a4ea

Browse files
committed
kernel: fix WED offloaded flow timeout
Add a pending patch to fix the WED flow timeout. 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. Signed-off-by: Qingfang Deng <dqfext@gmail.com> Signed-off-by: Robert Marko <robimarko@gmail.com>
1 parent a11e66c commit ad6a4ea

1 file changed

Lines changed: 76 additions & 0 deletions

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
From 53b3e60edb674b442b2b3bbdba484667b0f47a5d Mon Sep 17 00:00:00 2001
2+
From: Adrian Bente <adibente@gmail.com>
3+
Date: Thu, 28 May 2026 10:08:51 +0300
4+
Subject: [PATCH] netfilter: flowtable: fix offloaded ct timeout never being extended
5+
6+
OpenWrt has recently migrated many platforms to kernel 6.18. On the
7+
MediaTek platform, which supports hardware network offloading, WiFi
8+
connections accelerated via the WED path were observed to drop after
9+
roughly 300 seconds.
10+
11+
After several debugging sessions, assisted by the Claude LLM, the
12+
problem was narrowed down as follows:
13+
14+
nf_flow_table_extend_ct_timeout() extends ct->timeout for offloaded
15+
flows using:
16+
17+
cmpxchg(&ct->timeout, expires, new_timeout);
18+
19+
'expires' comes from nf_ct_expires(ct) and is a relative value, while
20+
ct->timeout holds an absolute timestamp. The two are never equal, so
21+
the cmpxchg always fails and the timeout is never extended.
22+
23+
This goes unnoticed for most flows, but a long-lived hardware (WED)
24+
offloaded flow on MediaTek MT7986 eventually has ct->timeout decay to
25+
zero, the conntrack entry is reaped and the connection breaks.
26+
27+
Open-code the relative value from a single READ_ONCE(ct->timeout)
28+
snapshot and compare against that same absolute snapshot in the
29+
cmpxchg, so the timeout extension actually takes effect while the
30+
datapath remains authoritative if it updates ct->timeout concurrently.
31+
32+
Fixes: 03428ca5cee9 ("netfilter: conntrack: rework offload nf_conn timeout extension logic")
33+
Cc: stable@vger.kernel.org
34+
Suggested-by: Florian Westphal <fw@strlen.de>
35+
Signed-off-by: Adrian Bente <adibente@gmail.com>
36+
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
37+
---
38+
net/netfilter/nf_flow_table_core.c | 13 +++++++++----
39+
1 file changed, 9 insertions(+), 4 deletions(-)
40+
41+
--- a/net/netfilter/nf_flow_table_core.c
42+
+++ b/net/netfilter/nf_flow_table_core.c
43+
@@ -500,8 +500,13 @@ static u32 nf_flow_table_tcp_timeout(con
44+
*/
45+
static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct)
46+
{
47+
- static const u32 min_timeout = 5 * 60 * HZ;
48+
- u32 expires = nf_ct_expires(ct);
49+
+ static const s32 min_timeout = 5 * 60 * HZ;
50+
+ u32 ct_timeout = READ_ONCE(ct->timeout);
51+
+ s32 expires;
52+
+
53+
+ expires = ct_timeout - nfct_time_stamp;
54+
+ if (expires <= 0) /* already expired */
55+
+ return;
56+
57+
/* normal case: large enough timeout, nothing to do. */
58+
if (likely(expires >= min_timeout))
59+
@@ -519,7 +524,7 @@ static void nf_flow_table_extend_ct_time
60+
if (nf_ct_is_confirmed(ct) &&
61+
test_bit(IPS_OFFLOAD_BIT, &ct->status)) {
62+
u8 l4proto = nf_ct_protonum(ct);
63+
- u32 new_timeout = true;
64+
+ u32 new_timeout = 1;
65+
66+
switch (l4proto) {
67+
case IPPROTO_UDP:
68+
@@ -544,7 +549,7 @@ static void nf_flow_table_extend_ct_time
69+
*/
70+
if (new_timeout) {
71+
new_timeout += nfct_time_stamp;
72+
- cmpxchg(&ct->timeout, expires, new_timeout);
73+
+ cmpxchg(&ct->timeout, ct_timeout, new_timeout);
74+
}
75+
}
76+

0 commit comments

Comments
 (0)