Blame view
net/netfilter/nft_counter.c
4.94 KB
96518518c
|
1 |
/* |
ef1f7df91
|
2 |
* Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> |
96518518c
|
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Development of this code funded by Astaro AG (http://www.astaro.com/) */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/seqlock.h> #include <linux/netlink.h> #include <linux/netfilter.h> #include <linux/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h> struct nft_counter { |
96518518c
|
21 22 23 |
u64 bytes; u64 packets; }; |
0c45e7696
|
24 25 26 27 28 29 30 31 |
struct nft_counter_percpu { struct nft_counter counter; struct u64_stats_sync syncp; }; struct nft_counter_percpu_priv { struct nft_counter_percpu __percpu *counter; }; |
96518518c
|
32 |
static void nft_counter_eval(const struct nft_expr *expr, |
a55e22e92
|
33 |
struct nft_regs *regs, |
96518518c
|
34 35 |
const struct nft_pktinfo *pkt) { |
0c45e7696
|
36 37 38 39 40 41 42 43 44 45 |
struct nft_counter_percpu_priv *priv = nft_expr_priv(expr); struct nft_counter_percpu *this_cpu; local_bh_disable(); this_cpu = this_cpu_ptr(priv->counter); u64_stats_update_begin(&this_cpu->syncp); this_cpu->counter.bytes += pkt->skb->len; this_cpu->counter.packets++; u64_stats_update_end(&this_cpu->syncp); local_bh_enable(); |
96518518c
|
46 |
} |
086f33216
|
47 48 |
static void nft_counter_fetch(const struct nft_counter_percpu __percpu *counter, struct nft_counter *total) |
96518518c
|
49 |
{ |
086f33216
|
50 |
const struct nft_counter_percpu *cpu_stats; |
0c45e7696
|
51 |
u64 bytes, packets; |
96518518c
|
52 |
unsigned int seq; |
0c45e7696
|
53 |
int cpu; |
086f33216
|
54 |
memset(total, 0, sizeof(*total)); |
0c45e7696
|
55 |
for_each_possible_cpu(cpu) { |
086f33216
|
56 |
cpu_stats = per_cpu_ptr(counter, cpu); |
0c45e7696
|
57 58 59 60 61 |
do { seq = u64_stats_fetch_begin_irq(&cpu_stats->syncp); bytes = cpu_stats->counter.bytes; packets = cpu_stats->counter.packets; } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq)); |
086f33216
|
62 63 |
total->packets += packets; total->bytes += bytes; |
0c45e7696
|
64 |
} |
086f33216
|
65 66 67 68 69 70 71 72 |
} static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr) { struct nft_counter_percpu_priv *priv = nft_expr_priv(expr); struct nft_counter total; nft_counter_fetch(priv->counter, &total); |
0c45e7696
|
73 74 75 |
if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)) || nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.packets))) |
96518518c
|
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
goto nla_put_failure; return 0; nla_put_failure: return -1; } static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = { [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 }, [NFTA_COUNTER_BYTES] = { .type = NLA_U64 }, }; static int nft_counter_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { |
0c45e7696
|
92 93 94 95 96 97 |
struct nft_counter_percpu_priv *priv = nft_expr_priv(expr); struct nft_counter_percpu __percpu *cpu_stats; struct nft_counter_percpu *this_cpu; cpu_stats = netdev_alloc_pcpu_stats(struct nft_counter_percpu); if (cpu_stats == NULL) |
5cc6ce9ff
|
98 |
return -ENOMEM; |
0c45e7696
|
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
preempt_disable(); this_cpu = this_cpu_ptr(cpu_stats); if (tb[NFTA_COUNTER_PACKETS]) { this_cpu->counter.packets = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS])); } if (tb[NFTA_COUNTER_BYTES]) { this_cpu->counter.bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES])); } preempt_enable(); priv->counter = cpu_stats; return 0; } |
96518518c
|
114 |
|
0c45e7696
|
115 116 117 118 |
static void nft_counter_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct nft_counter_percpu_priv *priv = nft_expr_priv(expr); |
96518518c
|
119 |
|
0c45e7696
|
120 |
free_percpu(priv->counter); |
96518518c
|
121 |
} |
086f33216
|
122 123 124 125 126 127 128 129 130 131 132 133 134 |
static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src) { struct nft_counter_percpu_priv *priv = nft_expr_priv(src); struct nft_counter_percpu_priv *priv_clone = nft_expr_priv(dst); struct nft_counter_percpu __percpu *cpu_stats; struct nft_counter_percpu *this_cpu; struct nft_counter total; nft_counter_fetch(priv->counter, &total); cpu_stats = __netdev_alloc_pcpu_stats(struct nft_counter_percpu, GFP_ATOMIC); if (cpu_stats == NULL) |
5cc6ce9ff
|
135 |
return -ENOMEM; |
086f33216
|
136 137 138 139 140 141 142 143 144 145 |
preempt_disable(); this_cpu = this_cpu_ptr(cpu_stats); this_cpu->counter.packets = total.packets; this_cpu->counter.bytes = total.bytes; preempt_enable(); priv_clone->counter = cpu_stats; return 0; } |
ef1f7df91
|
146 147 148 |
static struct nft_expr_type nft_counter_type; static const struct nft_expr_ops nft_counter_ops = { .type = &nft_counter_type, |
0c45e7696
|
149 |
.size = NFT_EXPR_SIZE(sizeof(struct nft_counter_percpu_priv)), |
96518518c
|
150 151 |
.eval = nft_counter_eval, .init = nft_counter_init, |
0c45e7696
|
152 |
.destroy = nft_counter_destroy, |
96518518c
|
153 |
.dump = nft_counter_dump, |
086f33216
|
154 |
.clone = nft_counter_clone, |
96518518c
|
155 |
}; |
ef1f7df91
|
156 157 158 159 160 |
static struct nft_expr_type nft_counter_type __read_mostly = { .name = "counter", .ops = &nft_counter_ops, .policy = nft_counter_policy, .maxattr = NFTA_COUNTER_MAX, |
151d799a6
|
161 |
.flags = NFT_EXPR_STATEFUL, |
ef1f7df91
|
162 163 |
.owner = THIS_MODULE, }; |
96518518c
|
164 165 |
static int __init nft_counter_module_init(void) { |
ef1f7df91
|
166 |
return nft_register_expr(&nft_counter_type); |
96518518c
|
167 168 169 170 |
} static void __exit nft_counter_module_exit(void) { |
ef1f7df91
|
171 |
nft_unregister_expr(&nft_counter_type); |
96518518c
|
172 173 174 175 176 177 178 179 |
} module_init(nft_counter_module_init); module_exit(nft_counter_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); MODULE_ALIAS_NFT_EXPR("counter"); |