Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Eric Dumazet and committed by
Pablo Neira Ayuso
b3e0bfa7 76ad94fc

+33 -33
+2 -2
include/net/netfilter/nf_conntrack_acct.h
··· 15 15 #include <net/netfilter/nf_conntrack_extend.h> 16 16 17 17 struct nf_conn_counter { 18 - u_int64_t packets; 19 - u_int64_t bytes; 18 + atomic64_t packets; 19 + atomic64_t bytes; 20 20 }; 21 21 22 22 static inline
+2 -2
net/netfilter/nf_conntrack_acct.c
··· 46 46 return 0; 47 47 48 48 return seq_printf(s, "packets=%llu bytes=%llu ", 49 - (unsigned long long)acct[dir].packets, 50 - (unsigned long long)acct[dir].bytes); 49 + (unsigned long long)atomic64_read(&acct[dir].packets), 50 + (unsigned long long)atomic64_read(&acct[dir].bytes)); 51 51 }; 52 52 EXPORT_SYMBOL_GPL(seq_print_acct); 53 53
+5 -9
net/netfilter/nf_conntrack_core.c
··· 1044 1044 1045 1045 acct = nf_conn_acct_find(ct); 1046 1046 if (acct) { 1047 - spin_lock_bh(&ct->lock); 1048 - acct[CTINFO2DIR(ctinfo)].packets++; 1049 - acct[CTINFO2DIR(ctinfo)].bytes += skb->len; 1050 - spin_unlock_bh(&ct->lock); 1047 + atomic64_inc(&acct[CTINFO2DIR(ctinfo)].packets); 1048 + atomic64_add(skb->len, &acct[CTINFO2DIR(ctinfo)].bytes); 1051 1049 } 1052 1050 } 1053 1051 } ··· 1061 1063 1062 1064 acct = nf_conn_acct_find(ct); 1063 1065 if (acct) { 1064 - spin_lock_bh(&ct->lock); 1065 - acct[CTINFO2DIR(ctinfo)].packets++; 1066 - acct[CTINFO2DIR(ctinfo)].bytes += 1067 - skb->len - skb_network_offset(skb); 1068 - spin_unlock_bh(&ct->lock); 1066 + atomic64_inc(&acct[CTINFO2DIR(ctinfo)].packets); 1067 + atomic64_add(skb->len - skb_network_offset(skb), 1068 + &acct[CTINFO2DIR(ctinfo)].bytes); 1069 1069 } 1070 1070 } 1071 1071
+8 -4
net/netfilter/nf_conntrack_netlink.c
··· 219 219 goto nla_put_failure; 220 220 221 221 NLA_PUT_BE64(skb, CTA_COUNTERS_PACKETS, 222 - cpu_to_be64(acct[dir].packets)); 222 + cpu_to_be64(atomic64_read(&acct[dir].packets))); 223 223 NLA_PUT_BE64(skb, CTA_COUNTERS_BYTES, 224 - cpu_to_be64(acct[dir].bytes)); 224 + cpu_to_be64(atomic64_read(&acct[dir].bytes))); 225 225 226 226 nla_nest_end(skb, nest_count); 227 227 ··· 720 720 struct nf_conn_counter *acct; 721 721 722 722 acct = nf_conn_acct_find(ct); 723 - if (acct) 724 - memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX])); 723 + if (acct) { 724 + atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, 0); 725 + atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, 0); 726 + atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, 0); 727 + atomic64_set(&acct[IP_CT_DIR_REPLY].packets, 0); 728 + } 725 729 } 726 730 } 727 731 if (cb->args[1]) {
+16 -16
net/netfilter/xt_connbytes.c
··· 40 40 case XT_CONNBYTES_PKTS: 41 41 switch (sinfo->direction) { 42 42 case XT_CONNBYTES_DIR_ORIGINAL: 43 - what = counters[IP_CT_DIR_ORIGINAL].packets; 43 + what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets); 44 44 break; 45 45 case XT_CONNBYTES_DIR_REPLY: 46 - what = counters[IP_CT_DIR_REPLY].packets; 46 + what = atomic64_read(&counters[IP_CT_DIR_REPLY].packets); 47 47 break; 48 48 case XT_CONNBYTES_DIR_BOTH: 49 - what = counters[IP_CT_DIR_ORIGINAL].packets; 50 - what += counters[IP_CT_DIR_REPLY].packets; 49 + what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets); 50 + what += atomic64_read(&counters[IP_CT_DIR_REPLY].packets); 51 51 break; 52 52 } 53 53 break; 54 54 case XT_CONNBYTES_BYTES: 55 55 switch (sinfo->direction) { 56 56 case XT_CONNBYTES_DIR_ORIGINAL: 57 - what = counters[IP_CT_DIR_ORIGINAL].bytes; 57 + what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes); 58 58 break; 59 59 case XT_CONNBYTES_DIR_REPLY: 60 - what = counters[IP_CT_DIR_REPLY].bytes; 60 + what = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes); 61 61 break; 62 62 case XT_CONNBYTES_DIR_BOTH: 63 - what = counters[IP_CT_DIR_ORIGINAL].bytes; 64 - what += counters[IP_CT_DIR_REPLY].bytes; 63 + what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes); 64 + what += atomic64_read(&counters[IP_CT_DIR_REPLY].bytes); 65 65 break; 66 66 } 67 67 break; 68 68 case XT_CONNBYTES_AVGPKT: 69 69 switch (sinfo->direction) { 70 70 case XT_CONNBYTES_DIR_ORIGINAL: 71 - bytes = counters[IP_CT_DIR_ORIGINAL].bytes; 72 - pkts = counters[IP_CT_DIR_ORIGINAL].packets; 71 + bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes); 72 + pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets); 73 73 break; 74 74 case XT_CONNBYTES_DIR_REPLY: 75 - bytes = counters[IP_CT_DIR_REPLY].bytes; 76 - pkts = counters[IP_CT_DIR_REPLY].packets; 75 + bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes); 76 + pkts = atomic64_read(&counters[IP_CT_DIR_REPLY].packets); 77 77 break; 78 78 case XT_CONNBYTES_DIR_BOTH: 79 - bytes = counters[IP_CT_DIR_ORIGINAL].bytes + 80 - counters[IP_CT_DIR_REPLY].bytes; 81 - pkts = counters[IP_CT_DIR_ORIGINAL].packets + 82 - counters[IP_CT_DIR_REPLY].packets; 79 + bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes) + 80 + atomic64_read(&counters[IP_CT_DIR_REPLY].bytes); 81 + pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets) + 82 + atomic64_read(&counters[IP_CT_DIR_REPLY].packets); 83 83 break; 84 84 } 85 85 if (pkts != 0)