Commit 735795f6 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: flowtable: GC pushes back packets to classic path

Since 41f2c7c3 ("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: 41f2c7c3 ("net/sched: act_ct: Fix promotion of offloaded unreplied tuple")
Reported-by: default avatarVladimir Smelhaus <vl.sm@email.cz>
Reviewed-by: default avatarPaul Blakey <paulb@nvidia.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent d2a0fc37
...@@ -53,6 +53,7 @@ struct nf_flowtable_type { ...@@ -53,6 +53,7 @@ struct nf_flowtable_type {
struct list_head list; struct list_head list;
int family; int family;
int (*init)(struct nf_flowtable *ft); int (*init)(struct nf_flowtable *ft);
bool (*gc)(const struct flow_offload *flow);
int (*setup)(struct nf_flowtable *ft, int (*setup)(struct nf_flowtable *ft,
struct net_device *dev, struct net_device *dev,
enum flow_block_command cmd); enum flow_block_command cmd);
......
...@@ -316,12 +316,6 @@ void flow_offload_refresh(struct nf_flowtable *flow_table, ...@@ -316,12 +316,6 @@ void flow_offload_refresh(struct nf_flowtable *flow_table,
} }
EXPORT_SYMBOL_GPL(flow_offload_refresh); 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) static inline bool nf_flow_has_expired(const struct flow_offload *flow)
{ {
return nf_flow_timeout_delta(flow->timeout) <= 0; return nf_flow_timeout_delta(flow->timeout) <= 0;
...@@ -407,12 +401,18 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table, ...@@ -407,12 +401,18 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
return err; 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, static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
struct flow_offload *flow, void *data) struct flow_offload *flow, void *data)
{ {
if (nf_flow_has_expired(flow) || if (nf_flow_has_expired(flow) ||
nf_ct_is_dying(flow->ct) || nf_ct_is_dying(flow->ct) ||
nf_flow_is_outdated(flow)) nf_flow_custom_gc(flow_table, flow))
flow_offload_teardown(flow); flow_offload_teardown(flow);
if (test_bit(NF_FLOW_TEARDOWN, &flow->flags)) { if (test_bit(NF_FLOW_TEARDOWN, &flow->flags)) {
......
...@@ -278,7 +278,14 @@ static int tcf_ct_flow_table_fill_actions(struct net *net, ...@@ -278,7 +278,14 @@ static int tcf_ct_flow_table_fill_actions(struct net *net,
return err; 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 = { static struct nf_flowtable_type flowtable_ct = {
.gc = tcf_ct_flow_is_outdated,
.action = tcf_ct_flow_table_fill_actions, .action = tcf_ct_flow_table_fill_actions,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment