Skip to content

Commit 41f2c7c

Browse files
Paul BlakeyPaolo Abeni
authored andcommitted
net/sched: act_ct: Fix promotion of offloaded unreplied tuple
Currently UNREPLIED and UNASSURED connections are added to the nf flow table. This causes the following connection packets to be processed by the flow table which then skips conntrack_in(), and thus such the connections will remain UNREPLIED and UNASSURED even if reply traffic is then seen. Even still, the unoffloaded reply packets are the ones triggering hardware update from new to established state, and if there aren't any to triger an update and/or previous update was missed, hardware can get out of sync with sw and still mark packets as new. Fix the above by: 1) Not skipping conntrack_in() for UNASSURED packets, but still refresh for hardware, as before the cited patch. 2) Try and force a refresh by reply-direction packets that update the hardware rules from new to established state. 3) Remove any bidirectional flows that didn't failed to update in hardware for re-insertion as bidrectional once any new packet arrives. Fixes: 6a9bad0 ("net/sched: act_ct: offload UDP NEW connections") Co-developed-by: Vlad Buslov <vladbu@nvidia.com> Signed-off-by: Vlad Buslov <vladbu@nvidia.com> Signed-off-by: Paul Blakey <paulb@nvidia.com> Reviewed-by: Florian Westphal <fw@strlen.de> Link: https://lore.kernel.org/r/1686313379-117663-1-git-send-email-paulb@nvidia.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 07b1cc8 commit 41f2c7c

4 files changed

Lines changed: 21 additions & 7 deletions

File tree

include/net/netfilter/nf_flow_table.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ int flow_offload_route_init(struct flow_offload *flow,
268268

269269
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
270270
void flow_offload_refresh(struct nf_flowtable *flow_table,
271-
struct flow_offload *flow);
271+
struct flow_offload *flow, bool force);
272272

273273
struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table,
274274
struct flow_offload_tuple *tuple);

net/netfilter/nf_flow_table_core.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,12 +317,12 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
317317
EXPORT_SYMBOL_GPL(flow_offload_add);
318318

319319
void flow_offload_refresh(struct nf_flowtable *flow_table,
320-
struct flow_offload *flow)
320+
struct flow_offload *flow, bool force)
321321
{
322322
u32 timeout;
323323

324324
timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
325-
if (timeout - READ_ONCE(flow->timeout) > HZ)
325+
if (force || timeout - READ_ONCE(flow->timeout) > HZ)
326326
WRITE_ONCE(flow->timeout, timeout);
327327
else
328328
return;
@@ -334,6 +334,12 @@ void flow_offload_refresh(struct nf_flowtable *flow_table,
334334
}
335335
EXPORT_SYMBOL_GPL(flow_offload_refresh);
336336

337+
static bool nf_flow_is_outdated(const struct flow_offload *flow)
338+
{
339+
return test_bit(IPS_SEEN_REPLY_BIT, &flow->ct->status) &&
340+
!test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags);
341+
}
342+
337343
static inline bool nf_flow_has_expired(const struct flow_offload *flow)
338344
{
339345
return nf_flow_timeout_delta(flow->timeout) <= 0;
@@ -423,7 +429,8 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
423429
struct flow_offload *flow, void *data)
424430
{
425431
if (nf_flow_has_expired(flow) ||
426-
nf_ct_is_dying(flow->ct))
432+
nf_ct_is_dying(flow->ct) ||
433+
nf_flow_is_outdated(flow))
427434
flow_offload_teardown(flow);
428435

429436
if (test_bit(NF_FLOW_TEARDOWN, &flow->flags)) {

net/netfilter/nf_flow_table_ip.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
384384
if (skb_try_make_writable(skb, thoff + hdrsize))
385385
return NF_DROP;
386386

387-
flow_offload_refresh(flow_table, flow);
387+
flow_offload_refresh(flow_table, flow, false);
388388

389389
nf_flow_encap_pop(skb, tuplehash);
390390
thoff -= offset;
@@ -650,7 +650,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
650650
if (skb_try_make_writable(skb, thoff + hdrsize))
651651
return NF_DROP;
652652

653-
flow_offload_refresh(flow_table, flow);
653+
flow_offload_refresh(flow_table, flow, false);
654654

655655
nf_flow_encap_pop(skb, tuplehash);
656656

net/sched/act_ct.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,7 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
610610
struct flow_offload_tuple tuple = {};
611611
enum ip_conntrack_info ctinfo;
612612
struct tcphdr *tcph = NULL;
613+
bool force_refresh = false;
613614
struct flow_offload *flow;
614615
struct nf_conn *ct;
615616
u8 dir;
@@ -647,6 +648,7 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
647648
* established state, then don't refresh.
648649
*/
649650
return false;
651+
force_refresh = true;
650652
}
651653

652654
if (tcph && (unlikely(tcph->fin || tcph->rst))) {
@@ -660,7 +662,12 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
660662
else
661663
ctinfo = IP_CT_ESTABLISHED_REPLY;
662664

663-
flow_offload_refresh(nf_ft, flow);
665+
flow_offload_refresh(nf_ft, flow, force_refresh);
666+
if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
667+
/* Process this flow in SW to allow promoting to ASSURED */
668+
return false;
669+
}
670+
664671
nf_conntrack_get(&ct->ct_general);
665672
nf_ct_set(skb, ct, ctinfo);
666673
if (nf_ft->flags & NF_FLOWTABLE_COUNTER)

0 commit comments

Comments
 (0)