From: João Silva An expired hardware flow remains in the flowtable until its asynchronous hardware deletion completes. Teardown clears IPS_OFFLOAD_BIT, so a packet can create a replacement flow referencing the same conntrack entry while the old flow is still waiting for deletion. The next GC pass calls flow_offload_teardown() on the expired old flow again, clearing the replacement's offload bit. More packets can then create additional flows for the same conntrack entry. A pending hardware work item can also delay deletion and expose the same repeated teardown. Commit d2d31ea8cd80 ("netfilter: conntrack: fix erronous removal of offload bit") closed this window for software flows by unlinking them in the same GC pass and made the conntrack state fixup one-shot, but hardware flows stay linked until NF_FLOW_HW_DEAD is set. Make clearing IPS_OFFLOAD_BIT part of the existing one-time teardown transition, alongside the conntrack state fixup. Subsequent teardown calls must not alter the offload state now owned by a replacement flow. Fixes: e5eaac2beb54 ("netfilter: flowtable: fix TCP flow teardown") Signed-off-by: João Silva --- net/netfilter/nf_flow_table_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 0d72dc8ae47a..709b55b74cc7 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -398,9 +398,11 @@ static void flow_offload_del(struct nf_flowtable *flow_table, void flow_offload_teardown(struct flow_offload *flow) { + if (test_and_set_bit(NF_FLOW_TEARDOWN, &flow->flags)) + return; + clear_bit(IPS_OFFLOAD_BIT, &flow->ct->status); - if (!test_and_set_bit(NF_FLOW_TEARDOWN, &flow->flags)) - flow_offload_fixup_ct(flow); + flow_offload_fixup_ct(flow); } EXPORT_SYMBOL_GPL(flow_offload_teardown); --- base-commit: 734bef548a96e8774d6eef5dfa2026c6edc4e80b change-id: 20261103-flowtable-offload-bit-f15bfd1d38ed Best regards, -- João Silva