Commit b3e0bfa7 authored by Eric Dumazet's avatar Eric Dumazet Committed by Pablo Neira Ayuso

netfilter: nf_conntrack: use atomic64 for accounting counters

We can use atomic64_t infrastructure to avoid taking a spinlock in fast
path, and remove inaccuracies while reading values in
ctnetlink_dump_counters() and connbytes_mt() on 32bit arches.

Suggested by Pablo.
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 76ad94fc
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
#include <net/netfilter/nf_conntrack_extend.h> #include <net/netfilter/nf_conntrack_extend.h>
struct nf_conn_counter { struct nf_conn_counter {
u_int64_t packets; atomic64_t packets;
u_int64_t bytes; atomic64_t bytes;
}; };
static inline static inline
......
...@@ -46,8 +46,8 @@ seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) ...@@ -46,8 +46,8 @@ seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
return 0; return 0;
return seq_printf(s, "packets=%llu bytes=%llu ", return seq_printf(s, "packets=%llu bytes=%llu ",
(unsigned long long)acct[dir].packets, (unsigned long long)atomic64_read(&acct[dir].packets),
(unsigned long long)acct[dir].bytes); (unsigned long long)atomic64_read(&acct[dir].bytes));
}; };
EXPORT_SYMBOL_GPL(seq_print_acct); EXPORT_SYMBOL_GPL(seq_print_acct);
......
...@@ -1044,10 +1044,8 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, ...@@ -1044,10 +1044,8 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
acct = nf_conn_acct_find(ct); acct = nf_conn_acct_find(ct);
if (acct) { if (acct) {
spin_lock_bh(&ct->lock); atomic64_inc(&acct[CTINFO2DIR(ctinfo)].packets);
acct[CTINFO2DIR(ctinfo)].packets++; atomic64_add(skb->len, &acct[CTINFO2DIR(ctinfo)].bytes);
acct[CTINFO2DIR(ctinfo)].bytes += skb->len;
spin_unlock_bh(&ct->lock);
} }
} }
} }
...@@ -1063,11 +1061,9 @@ bool __nf_ct_kill_acct(struct nf_conn *ct, ...@@ -1063,11 +1061,9 @@ bool __nf_ct_kill_acct(struct nf_conn *ct,
acct = nf_conn_acct_find(ct); acct = nf_conn_acct_find(ct);
if (acct) { if (acct) {
spin_lock_bh(&ct->lock); atomic64_inc(&acct[CTINFO2DIR(ctinfo)].packets);
acct[CTINFO2DIR(ctinfo)].packets++; atomic64_add(skb->len - skb_network_offset(skb),
acct[CTINFO2DIR(ctinfo)].bytes += &acct[CTINFO2DIR(ctinfo)].bytes);
skb->len - skb_network_offset(skb);
spin_unlock_bh(&ct->lock);
} }
} }
......
...@@ -219,9 +219,9 @@ ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct, ...@@ -219,9 +219,9 @@ ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,
goto nla_put_failure; goto nla_put_failure;
NLA_PUT_BE64(skb, CTA_COUNTERS_PACKETS, NLA_PUT_BE64(skb, CTA_COUNTERS_PACKETS,
cpu_to_be64(acct[dir].packets)); cpu_to_be64(atomic64_read(&acct[dir].packets)));
NLA_PUT_BE64(skb, CTA_COUNTERS_BYTES, NLA_PUT_BE64(skb, CTA_COUNTERS_BYTES,
cpu_to_be64(acct[dir].bytes)); cpu_to_be64(atomic64_read(&acct[dir].bytes)));
nla_nest_end(skb, nest_count); nla_nest_end(skb, nest_count);
...@@ -720,8 +720,12 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -720,8 +720,12 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct nf_conn_counter *acct; struct nf_conn_counter *acct;
acct = nf_conn_acct_find(ct); acct = nf_conn_acct_find(ct);
if (acct) if (acct) {
memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX])); atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, 0);
atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, 0);
atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, 0);
atomic64_set(&acct[IP_CT_DIR_REPLY].packets, 0);
}
} }
} }
if (cb->args[1]) { if (cb->args[1]) {
......
...@@ -40,46 +40,46 @@ connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -40,46 +40,46 @@ connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
case XT_CONNBYTES_PKTS: case XT_CONNBYTES_PKTS:
switch (sinfo->direction) { switch (sinfo->direction) {
case XT_CONNBYTES_DIR_ORIGINAL: case XT_CONNBYTES_DIR_ORIGINAL:
what = counters[IP_CT_DIR_ORIGINAL].packets; what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
break; break;
case XT_CONNBYTES_DIR_REPLY: case XT_CONNBYTES_DIR_REPLY:
what = counters[IP_CT_DIR_REPLY].packets; what = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
break; break;
case XT_CONNBYTES_DIR_BOTH: case XT_CONNBYTES_DIR_BOTH:
what = counters[IP_CT_DIR_ORIGINAL].packets; what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
what += counters[IP_CT_DIR_REPLY].packets; what += atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
break; break;
} }
break; break;
case XT_CONNBYTES_BYTES: case XT_CONNBYTES_BYTES:
switch (sinfo->direction) { switch (sinfo->direction) {
case XT_CONNBYTES_DIR_ORIGINAL: case XT_CONNBYTES_DIR_ORIGINAL:
what = counters[IP_CT_DIR_ORIGINAL].bytes; what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
break; break;
case XT_CONNBYTES_DIR_REPLY: case XT_CONNBYTES_DIR_REPLY:
what = counters[IP_CT_DIR_REPLY].bytes; what = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
break; break;
case XT_CONNBYTES_DIR_BOTH: case XT_CONNBYTES_DIR_BOTH:
what = counters[IP_CT_DIR_ORIGINAL].bytes; what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
what += counters[IP_CT_DIR_REPLY].bytes; what += atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
break; break;
} }
break; break;
case XT_CONNBYTES_AVGPKT: case XT_CONNBYTES_AVGPKT:
switch (sinfo->direction) { switch (sinfo->direction) {
case XT_CONNBYTES_DIR_ORIGINAL: case XT_CONNBYTES_DIR_ORIGINAL:
bytes = counters[IP_CT_DIR_ORIGINAL].bytes; bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
pkts = counters[IP_CT_DIR_ORIGINAL].packets; pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
break; break;
case XT_CONNBYTES_DIR_REPLY: case XT_CONNBYTES_DIR_REPLY:
bytes = counters[IP_CT_DIR_REPLY].bytes; bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
pkts = counters[IP_CT_DIR_REPLY].packets; pkts = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
break; break;
case XT_CONNBYTES_DIR_BOTH: case XT_CONNBYTES_DIR_BOTH:
bytes = counters[IP_CT_DIR_ORIGINAL].bytes + bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes) +
counters[IP_CT_DIR_REPLY].bytes; atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
pkts = counters[IP_CT_DIR_ORIGINAL].packets + pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets) +
counters[IP_CT_DIR_REPLY].packets; atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
break; break;
} }
if (pkts != 0) if (pkts != 0)
......
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