netfilter: nf_flow_table: conntrack picks up expired flows
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 9 Aug 2019 09:01:33 +0000 (11:01 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 9 Aug 2019 12:41:20 +0000 (14:41 +0200)
Update conntrack entry to pick up expired flows, otherwise the conntrack
entry gets stuck with the internal offload timeout (one day). The TCP
state also needs to be adjusted to ESTABLISHED state and tracking is set
to liberal mode in order to give conntrack a chance to pick up the
expired flow.

Fixes: ac2a66665e23 ("netfilter: add generic flow table infrastructure")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_flow_table_core.c

index e3d797252a981cdc7e3362be0e157c6db1d429a1..68a24471ffee33d43fdee85b14a2585ad6d50ece 100644 (file)
@@ -111,7 +111,7 @@ static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp)
 #define NF_FLOWTABLE_TCP_PICKUP_TIMEOUT        (120 * HZ)
 #define NF_FLOWTABLE_UDP_PICKUP_TIMEOUT        (30 * HZ)
 
-static void flow_offload_fixup_ct_state(struct nf_conn *ct)
+static void flow_offload_fixup_ct(struct nf_conn *ct)
 {
        const struct nf_conntrack_l4proto *l4proto;
        unsigned int timeout;
@@ -208,6 +208,11 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
 }
 EXPORT_SYMBOL_GPL(flow_offload_add);
 
+static inline bool nf_flow_has_expired(const struct flow_offload *flow)
+{
+       return (__s32)(flow->timeout - (u32)jiffies) <= 0;
+}
+
 static void flow_offload_del(struct nf_flowtable *flow_table,
                             struct flow_offload *flow)
 {
@@ -223,6 +228,9 @@ static void flow_offload_del(struct nf_flowtable *flow_table,
        e = container_of(flow, struct flow_offload_entry, flow);
        clear_bit(IPS_OFFLOAD_BIT, &e->ct->status);
 
+       if (nf_flow_has_expired(flow))
+               flow_offload_fixup_ct(e->ct);
+
        flow_offload_free(flow);
 }
 
@@ -233,7 +241,7 @@ void flow_offload_teardown(struct flow_offload *flow)
        flow->flags |= FLOW_OFFLOAD_TEARDOWN;
 
        e = container_of(flow, struct flow_offload_entry, flow);
-       flow_offload_fixup_ct_state(e->ct);
+       flow_offload_fixup_ct(e->ct);
 }
 EXPORT_SYMBOL_GPL(flow_offload_teardown);
 
@@ -298,11 +306,6 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
        return err;
 }
 
-static inline bool nf_flow_has_expired(const struct flow_offload *flow)
-{
-       return (__s32)(flow->timeout - (u32)jiffies) <= 0;
-}
-
 static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data)
 {
        struct nf_flowtable *flow_table = data;