@@ -65,8 +65,7 @@ static inline void nf_ct_set_acct(struct net *net, bool enable)
#endif
}
-void nf_ct_acct_add(struct nf_conn *ct, u32 dir, unsigned int packets,
- unsigned int bytes);
+void nf_ct_acct_add(struct nf_conn *ct, u32 dir, u64 packets, u64 bytes);
static inline void nf_ct_acct_update(struct nf_conn *ct, u32 dir,
unsigned int bytes)
@@ -171,6 +171,9 @@ struct flow_offload_tuple {
u32 iifidx;
} tc;
};
+
+ atomic64_t packets;
+ atomic64_t bytes;
};
struct flow_offload_tuple_rhash {
@@ -921,8 +921,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
}
EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
-void nf_ct_acct_add(struct nf_conn *ct, u32 dir, unsigned int packets,
- unsigned int bytes)
+void nf_ct_acct_add(struct nf_conn *ct, u32 dir, u64 packets, u64 bytes)
{
struct nf_conn_acct *acct;
@@ -13,6 +13,7 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_tuple.h>
+#include <net/netfilter/nf_conntrack_acct.h>
static DEFINE_MUTEX(flowtable_lock);
static LIST_HEAD(flowtables);
@@ -565,6 +566,21 @@ static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct)
nf_ct_put(ct);
}
+static void __nf_flow_sync_ct_stats(struct flow_offload *flow, int dir)
+{
+ u64 pkts, bytes;
+
+ pkts = atomic64_xchg(&flow->tuplehash[dir].tuple.packets, 0);
+ bytes = atomic64_xchg(&flow->tuplehash[dir].tuple.bytes, 0);
+ nf_ct_acct_add(flow->ct, dir, pkts, bytes);
+}
+
+static void nf_flow_sync_ct_stats(struct flow_offload *flow)
+{
+ __nf_flow_sync_ct_stats(flow, FLOW_OFFLOAD_DIR_ORIGINAL);
+ __nf_flow_sync_ct_stats(flow, FLOW_OFFLOAD_DIR_REPLY);
+}
+
static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
struct flow_offload *flow, void *data)
{
@@ -581,6 +597,8 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
nf_flow_table_extend_ct_timeout(flow->ct);
}
+ nf_flow_sync_ct_stats(flow);
+
if (teardown) {
if (test_bit(NF_FLOW_HW, &flow->flags)) {
if (!test_bit(NF_FLOW_HW_DYING, &flow->flags))
@@ -509,8 +509,10 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
ip_decrease_ttl(iph);
skb_clear_tstamp(skb);
- if (flow_table->flags & NF_FLOWTABLE_COUNTER)
- nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
+ if (flow_table->flags & NF_FLOWTABLE_COUNTER) {
+ atomic64_add(1, &tuplehash->tuple.packets);
+ atomic64_add(skb->len, &tuplehash->tuple.bytes);
+ }
return 1;
}
@@ -1104,8 +1106,10 @@ static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx,
ip6h->hop_limit--;
skb_clear_tstamp(skb);
- if (flow_table->flags & NF_FLOWTABLE_COUNTER)
- nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
+ if (flow_table->flags & NF_FLOWTABLE_COUNTER) {
+ atomic64_add(1, &tuplehash->tuple.packets);
+ atomic64_add(skb->len, &tuplehash->tuple.bytes);
+ }
return 1;
}
@@ -726,8 +726,10 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
nf_conntrack_get(&ct->ct_general);
nf_ct_set(skb, ct, ctinfo);
- if (nf_ft->flags & NF_FLOWTABLE_COUNTER)
- nf_ct_acct_update(ct, dir, skb->len);
+ if (nf_ft->flags & NF_FLOWTABLE_COUNTER) {
+ atomic64_add(1, &tuplehash->tuple.packets);
+ atomic64_add(skb->len, &tuplehash->tuple.bytes);
+ }
return true;
}
Use the existing gc worker to sync flow stats with ct stats. It is not safe to access flow->ct from datapath since the GC worker drops the ct refcount on teardown while datapath could still be accessing the ct object to update the stats, this is related to conntrack typesafe RCU. Update nf_ct_acct_add() to take u64 for packets and bytes to ensure u32 truncation is not an issue. Fixes: 53c2b2899af7 ("netfilter: flowtable: add counter support") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- v2: - update flowtable ipv6 and tc act_ct too - update nf_ct_acct_add() to use u64 to prevent truncation - move nf_flow_sync_ct_stats() call after teardown check, still race with GC could lead to miss some final packets due to lockless rhashtable lookups winning race on teardown, this is best effort. Best way would be to expose a netlink interface for flow entries, instead of synchronizing with ct. include/net/netfilter/nf_conntrack_acct.h | 3 +-- include/net/netfilter/nf_flow_table.h | 3 +++ net/netfilter/nf_conntrack_core.c | 3 +-- net/netfilter/nf_flow_table_core.c | 18 ++++++++++++++++++ net/netfilter/nf_flow_table_ip.c | 12 ++++++++---- net/sched/act_ct.c | 6 ++++-- 6 files changed, 35 insertions(+), 10 deletions(-)