]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfilter: flowtable: GC pushes back packets to classic path
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 24 Oct 2023 19:09:47 +0000 (21:09 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 25 Oct 2023 09:35:46 +0000 (11:35 +0200)
Since 41f2c7c342d3 ("net/sched: act_ct: Fix promotion of offloaded
unreplied tuple"), flowtable GC pushes back flows with IPS_SEEN_REPLY
back to classic path in every run, ie. every second. This is because of
a new check for NF_FLOW_HW_ESTABLISHED which is specific of sched/act_ct.

In Netfilter's flowtable case, NF_FLOW_HW_ESTABLISHED never gets set on
and IPS_SEEN_REPLY is unreliable since users decide when to offload the
flow before, such bit might be set on at a later stage.

Fix it by adding a custom .gc handler that sched/act_ct can use to
deal with its NF_FLOW_HW_ESTABLISHED bit.

Fixes: 41f2c7c342d3 ("net/sched: act_ct: Fix promotion of offloaded unreplied tuple")
Reported-by: Vladimir Smelhaus <vl.sm@email.cz>
Reviewed-by: Paul Blakey <paulb@nvidia.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_flow_table.h
net/netfilter/nf_flow_table_core.c
net/sched/act_ct.c

index d466e1a3b0b1984c96439a31cbd0b5ff3a415740..fe1507c1db828b14e6d684f1f1bca514dbb4103d 100644 (file)
@@ -53,6 +53,7 @@ struct nf_flowtable_type {
        struct list_head                list;
        int                             family;
        int                             (*init)(struct nf_flowtable *ft);
+       bool                            (*gc)(const struct flow_offload *flow);
        int                             (*setup)(struct nf_flowtable *ft,
                                                 struct net_device *dev,
                                                 enum flow_block_command cmd);
index 1d34d700bd09b279b8e06b274d4b004fdc00f15e..920a5a29ae1dceba6849aaad6d62701567d3ec99 100644 (file)
@@ -316,12 +316,6 @@ void flow_offload_refresh(struct nf_flowtable *flow_table,
 }
 EXPORT_SYMBOL_GPL(flow_offload_refresh);
 
-static bool nf_flow_is_outdated(const struct flow_offload *flow)
-{
-       return test_bit(IPS_SEEN_REPLY_BIT, &flow->ct->status) &&
-               !test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags);
-}
-
 static inline bool nf_flow_has_expired(const struct flow_offload *flow)
 {
        return nf_flow_timeout_delta(flow->timeout) <= 0;
@@ -407,12 +401,18 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
        return err;
 }
 
+static bool nf_flow_custom_gc(struct nf_flowtable *flow_table,
+                             const struct flow_offload *flow)
+{
+       return flow_table->type->gc && flow_table->type->gc(flow);
+}
+
 static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
                                    struct flow_offload *flow, void *data)
 {
        if (nf_flow_has_expired(flow) ||
            nf_ct_is_dying(flow->ct) ||
-           nf_flow_is_outdated(flow))
+           nf_flow_custom_gc(flow_table, flow))
                flow_offload_teardown(flow);
 
        if (test_bit(NF_FLOW_TEARDOWN, &flow->flags)) {
index 7c652d14528be9da4904466c7452dbea6020fbfb..0d44da4e8c8ed38d6cc40ed804fe8774828dbcb0 100644 (file)
@@ -278,7 +278,14 @@ err_nat:
        return err;
 }
 
+static bool tcf_ct_flow_is_outdated(const struct flow_offload *flow)
+{
+       return test_bit(IPS_SEEN_REPLY_BIT, &flow->ct->status) &&
+              !test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags);
+}
+
 static struct nf_flowtable_type flowtable_ct = {
+       .gc             = tcf_ct_flow_is_outdated,
        .action         = tcf_ct_flow_table_fill_actions,
        .owner          = THIS_MODULE,
 };