Retrieve stats too when deleting a flow from hardware. Apparently, the existing approach is missing last stats sync with the conntrack entry. Pass the stats object to the driver so it has a chance to populate it at deletion time. Drivers need to be updated to use this new approach. Reported-by: Valentin Berezhnoy Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_flow_table_offload.c | 43 ++++++++++++++++----------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c index 4365859220e6..53182323f73c 100644 --- a/net/netfilter/nf_flow_table_offload.c +++ b/net/netfilter/nf_flow_table_offload.c @@ -934,6 +934,27 @@ static int nf_flow_offload_tuple(struct nf_flowtable *flowtable, return i; } +static void flow_offload_update_stats(struct flow_offload_work *offload, + struct flow_stats *stats) +{ + u64 lastused; + + lastused = max_t(u64, stats[0].lastused, stats[1].lastused); + offload->flow->timeout = max_t(u64, offload->flow->timeout, + lastused + flow_offload_get_timeout(offload->flow)); + + if (offload->flowtable->flags & NF_FLOWTABLE_COUNTER) { + if (stats[0].pkts) + nf_ct_acct_add(offload->flow->ct, + FLOW_OFFLOAD_DIR_ORIGINAL, + stats[0].pkts, stats[0].bytes); + if (stats[1].pkts) + nf_ct_acct_add(offload->flow->ct, + FLOW_OFFLOAD_DIR_REPLY, + stats[1].pkts, stats[1].bytes); + } +} + static int flow_offload_tuple_add(struct flow_offload_work *offload, struct nf_flow_rule *flow_rule, enum flow_offload_tuple_dir dir) @@ -948,10 +969,13 @@ static int flow_offload_tuple_add(struct flow_offload_work *offload, static void flow_offload_tuple_del(struct flow_offload_work *offload, enum flow_offload_tuple_dir dir) { + struct flow_stats stats[FLOW_OFFLOAD_DIR_MAX] = {}; + nf_flow_offload_tuple(offload->flowtable, offload->flow, NULL, dir, offload->flowtable->priority, - FLOW_CLS_DESTROY, NULL, + FLOW_CLS_DESTROY, stats, &offload->flowtable->flow_block.cb_list); + flow_offload_update_stats(offload, stats); } static int flow_offload_rule_add(struct flow_offload_work *offload, @@ -1011,27 +1035,12 @@ static void flow_offload_tuple_stats(struct flow_offload_work *offload, static void flow_offload_work_stats(struct flow_offload_work *offload) { struct flow_stats stats[FLOW_OFFLOAD_DIR_MAX] = {}; - u64 lastused; flow_offload_tuple_stats(offload, FLOW_OFFLOAD_DIR_ORIGINAL, &stats[0]); if (test_bit(NF_FLOW_HW_BIDIRECTIONAL, &offload->flow->flags)) flow_offload_tuple_stats(offload, FLOW_OFFLOAD_DIR_REPLY, &stats[1]); - - lastused = max_t(u64, stats[0].lastused, stats[1].lastused); - offload->flow->timeout = max_t(u64, offload->flow->timeout, - lastused + flow_offload_get_timeout(offload->flow)); - - if (offload->flowtable->flags & NF_FLOWTABLE_COUNTER) { - if (stats[0].pkts) - nf_ct_acct_add(offload->flow->ct, - FLOW_OFFLOAD_DIR_ORIGINAL, - stats[0].pkts, stats[0].bytes); - if (stats[1].pkts) - nf_ct_acct_add(offload->flow->ct, - FLOW_OFFLOAD_DIR_REPLY, - stats[1].pkts, stats[1].bytes); - } + flow_offload_update_stats(offload, stats); } static void flow_offload_work_handler(struct work_struct *work) -- 2.47.3