Blame view
net/netfilter/nft_counter.c
7.46 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
96518518c netfilter: add nf... |
2 |
/* |
ef1f7df91 netfilter: nf_tab... |
3 |
* Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> |
96518518c netfilter: add nf... |
4 |
* |
96518518c netfilter: add nf... |
5 6 7 8 9 10 11 12 13 14 15 16 17 |
* 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 { |
d84701ecb netfilter: nft_co... |
18 19 |
s64 bytes; s64 packets; |
0c45e7696 netfilter: nft_co... |
20 21 22 |
}; struct nft_counter_percpu_priv { |
d84701ecb netfilter: nft_co... |
23 |
struct nft_counter __percpu *counter; |
0c45e7696 netfilter: nft_co... |
24 |
}; |
d84701ecb netfilter: nft_co... |
25 |
static DEFINE_PER_CPU(seqcount_t, nft_counter_seq); |
b1ce0ced1 netfilter: nft_co... |
26 27 28 |
static inline void nft_counter_do_eval(struct nft_counter_percpu_priv *priv, struct nft_regs *regs, const struct nft_pktinfo *pkt) |
96518518c netfilter: add nf... |
29 |
{ |
d84701ecb netfilter: nft_co... |
30 31 |
struct nft_counter *this_cpu; seqcount_t *myseq; |
0c45e7696 netfilter: nft_co... |
32 33 34 |
local_bh_disable(); this_cpu = this_cpu_ptr(priv->counter); |
d84701ecb netfilter: nft_co... |
35 36 37 38 39 40 41 42 |
myseq = this_cpu_ptr(&nft_counter_seq); write_seqcount_begin(myseq); this_cpu->bytes += pkt->skb->len; this_cpu->packets++; write_seqcount_end(myseq); |
0c45e7696 netfilter: nft_co... |
43 |
local_bh_enable(); |
96518518c netfilter: add nf... |
44 |
} |
b1ce0ced1 netfilter: nft_co... |
45 46 47 48 49 50 51 52 53 54 55 56 |
static inline void nft_counter_obj_eval(struct nft_object *obj, struct nft_regs *regs, const struct nft_pktinfo *pkt) { struct nft_counter_percpu_priv *priv = nft_obj_data(obj); nft_counter_do_eval(priv, regs, pkt); } static int nft_counter_do_init(const struct nlattr * const tb[], struct nft_counter_percpu_priv *priv) { |
d84701ecb netfilter: nft_co... |
57 58 |
struct nft_counter __percpu *cpu_stats; struct nft_counter *this_cpu; |
b1ce0ced1 netfilter: nft_co... |
59 |
|
d84701ecb netfilter: nft_co... |
60 |
cpu_stats = alloc_percpu(struct nft_counter); |
b1ce0ced1 netfilter: nft_co... |
61 62 63 64 65 66 |
if (cpu_stats == NULL) return -ENOMEM; preempt_disable(); this_cpu = this_cpu_ptr(cpu_stats); if (tb[NFTA_COUNTER_PACKETS]) { |
d84701ecb netfilter: nft_co... |
67 |
this_cpu->packets = |
b1ce0ced1 netfilter: nft_co... |
68 69 70 |
be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS])); } if (tb[NFTA_COUNTER_BYTES]) { |
d84701ecb netfilter: nft_co... |
71 |
this_cpu->bytes = |
b1ce0ced1 netfilter: nft_co... |
72 73 74 75 76 77 |
be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES])); } preempt_enable(); priv->counter = cpu_stats; return 0; } |
84fba0551 netfilter: provid... |
78 79 |
static int nft_counter_obj_init(const struct nft_ctx *ctx, const struct nlattr * const tb[], |
b1ce0ced1 netfilter: nft_co... |
80 81 82 83 84 85 86 87 88 89 90 |
struct nft_object *obj) { struct nft_counter_percpu_priv *priv = nft_obj_data(obj); return nft_counter_do_init(tb, priv); } static void nft_counter_do_destroy(struct nft_counter_percpu_priv *priv) { free_percpu(priv->counter); } |
00bfb3205 netfilter: nf_tab... |
91 92 |
static void nft_counter_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj) |
b1ce0ced1 netfilter: nft_co... |
93 94 95 96 97 |
{ struct nft_counter_percpu_priv *priv = nft_obj_data(obj); nft_counter_do_destroy(priv); } |
dd03b1ad2 netfilter: nft_co... |
98 |
static void nft_counter_reset(struct nft_counter_percpu_priv *priv, |
086f33216 netfilter: nf_tab... |
99 |
struct nft_counter *total) |
96518518c netfilter: add nf... |
100 |
{ |
d84701ecb netfilter: nft_co... |
101 |
struct nft_counter *this_cpu; |
0c45e7696 netfilter: nft_co... |
102 |
|
d84701ecb netfilter: nft_co... |
103 104 105 106 107 |
local_bh_disable(); this_cpu = this_cpu_ptr(priv->counter); this_cpu->packets -= total->packets; this_cpu->bytes -= total->bytes; local_bh_enable(); |
43da04a59 netfilter: nf_tab... |
108 |
} |
d84701ecb netfilter: nft_co... |
109 |
static void nft_counter_fetch(struct nft_counter_percpu_priv *priv, |
43da04a59 netfilter: nf_tab... |
110 111 |
struct nft_counter *total) { |
d84701ecb netfilter: nft_co... |
112 113 |
struct nft_counter *this_cpu; const seqcount_t *myseq; |
43da04a59 netfilter: nf_tab... |
114 115 116 117 118 119 |
u64 bytes, packets; unsigned int seq; int cpu; memset(total, 0, sizeof(*total)); for_each_possible_cpu(cpu) { |
d84701ecb netfilter: nft_co... |
120 121 |
myseq = per_cpu_ptr(&nft_counter_seq, cpu); this_cpu = per_cpu_ptr(priv->counter, cpu); |
43da04a59 netfilter: nf_tab... |
122 |
do { |
d84701ecb netfilter: nft_co... |
123 124 125 126 |
seq = read_seqcount_begin(myseq); bytes = this_cpu->bytes; packets = this_cpu->packets; } while (read_seqcount_retry(myseq, seq)); |
43da04a59 netfilter: nf_tab... |
127 |
|
d84701ecb netfilter: nft_co... |
128 129 |
total->bytes += bytes; total->packets += packets; |
43da04a59 netfilter: nf_tab... |
130 131 |
} } |
b1ce0ced1 netfilter: nft_co... |
132 |
static int nft_counter_do_dump(struct sk_buff *skb, |
d84701ecb netfilter: nft_co... |
133 |
struct nft_counter_percpu_priv *priv, |
43da04a59 netfilter: nf_tab... |
134 |
bool reset) |
086f33216 netfilter: nf_tab... |
135 |
{ |
086f33216 netfilter: nf_tab... |
136 |
struct nft_counter total; |
d84701ecb netfilter: nft_co... |
137 |
nft_counter_fetch(priv, &total); |
0c45e7696 netfilter: nft_co... |
138 |
|
b46f6ded9 libnl: nla_put_be... |
139 140 141 142 |
if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes), NFTA_COUNTER_PAD) || nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.packets), NFTA_COUNTER_PAD)) |
96518518c netfilter: add nf... |
143 |
goto nla_put_failure; |
d84701ecb netfilter: nft_co... |
144 145 146 |
if (reset) nft_counter_reset(priv, &total); |
96518518c netfilter: add nf... |
147 148 149 150 151 |
return 0; nla_put_failure: return -1; } |
b1ce0ced1 netfilter: nft_co... |
152 |
static int nft_counter_obj_dump(struct sk_buff *skb, |
43da04a59 netfilter: nf_tab... |
153 |
struct nft_object *obj, bool reset) |
b1ce0ced1 netfilter: nft_co... |
154 |
{ |
43da04a59 netfilter: nf_tab... |
155 |
struct nft_counter_percpu_priv *priv = nft_obj_data(obj); |
b1ce0ced1 netfilter: nft_co... |
156 |
|
43da04a59 netfilter: nf_tab... |
157 |
return nft_counter_do_dump(skb, priv, reset); |
b1ce0ced1 netfilter: nft_co... |
158 |
} |
96518518c netfilter: add nf... |
159 160 161 162 |
static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = { [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 }, [NFTA_COUNTER_BYTES] = { .type = NLA_U64 }, }; |
dfc46034b netfilter: nf_tab... |
163 164 165 |
static struct nft_object_type nft_counter_obj_type; static const struct nft_object_ops nft_counter_obj_ops = { .type = &nft_counter_obj_type, |
b1ce0ced1 netfilter: nft_co... |
166 |
.size = sizeof(struct nft_counter_percpu_priv), |
b1ce0ced1 netfilter: nft_co... |
167 168 169 170 |
.eval = nft_counter_obj_eval, .init = nft_counter_obj_init, .destroy = nft_counter_obj_destroy, .dump = nft_counter_obj_dump, |
dfc46034b netfilter: nf_tab... |
171 172 173 174 175 176 177 |
}; static struct nft_object_type nft_counter_obj_type __read_mostly = { .type = NFT_OBJECT_COUNTER, .ops = &nft_counter_obj_ops, .maxattr = NFTA_COUNTER_MAX, .policy = nft_counter_policy, |
b1ce0ced1 netfilter: nft_co... |
178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
.owner = THIS_MODULE, }; static void nft_counter_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { struct nft_counter_percpu_priv *priv = nft_expr_priv(expr); nft_counter_do_eval(priv, regs, pkt); } static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr) { |
d84701ecb netfilter: nft_co... |
192 |
struct nft_counter_percpu_priv *priv = nft_expr_priv(expr); |
b1ce0ced1 netfilter: nft_co... |
193 |
|
43da04a59 netfilter: nf_tab... |
194 |
return nft_counter_do_dump(skb, priv, false); |
b1ce0ced1 netfilter: nft_co... |
195 |
} |
96518518c netfilter: add nf... |
196 197 198 199 |
static int nft_counter_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { |
0c45e7696 netfilter: nft_co... |
200 |
struct nft_counter_percpu_priv *priv = nft_expr_priv(expr); |
0c45e7696 netfilter: nft_co... |
201 |
|
b1ce0ced1 netfilter: nft_co... |
202 |
return nft_counter_do_init(tb, priv); |
0c45e7696 netfilter: nft_co... |
203 |
} |
96518518c netfilter: add nf... |
204 |
|
0c45e7696 netfilter: nft_co... |
205 206 207 208 |
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 netfilter: add nf... |
209 |
|
b1ce0ced1 netfilter: nft_co... |
210 |
nft_counter_do_destroy(priv); |
96518518c netfilter: add nf... |
211 |
} |
086f33216 netfilter: nf_tab... |
212 213 214 215 |
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); |
d84701ecb netfilter: nft_co... |
216 217 |
struct nft_counter __percpu *cpu_stats; struct nft_counter *this_cpu; |
086f33216 netfilter: nf_tab... |
218 |
struct nft_counter total; |
d84701ecb netfilter: nft_co... |
219 |
nft_counter_fetch(priv, &total); |
086f33216 netfilter: nf_tab... |
220 |
|
d84701ecb netfilter: nft_co... |
221 |
cpu_stats = alloc_percpu_gfp(struct nft_counter, GFP_ATOMIC); |
086f33216 netfilter: nf_tab... |
222 |
if (cpu_stats == NULL) |
5cc6ce9ff netfilter: nft_co... |
223 |
return -ENOMEM; |
086f33216 netfilter: nf_tab... |
224 225 226 |
preempt_disable(); this_cpu = this_cpu_ptr(cpu_stats); |
d84701ecb netfilter: nft_co... |
227 228 |
this_cpu->packets = total.packets; this_cpu->bytes = total.bytes; |
086f33216 netfilter: nf_tab... |
229 230 231 232 233 |
preempt_enable(); priv_clone->counter = cpu_stats; return 0; } |
ef1f7df91 netfilter: nf_tab... |
234 235 236 |
static struct nft_expr_type nft_counter_type; static const struct nft_expr_ops nft_counter_ops = { .type = &nft_counter_type, |
0c45e7696 netfilter: nft_co... |
237 |
.size = NFT_EXPR_SIZE(sizeof(struct nft_counter_percpu_priv)), |
96518518c netfilter: add nf... |
238 239 |
.eval = nft_counter_eval, .init = nft_counter_init, |
0c45e7696 netfilter: nft_co... |
240 |
.destroy = nft_counter_destroy, |
371ebcbb9 netfilter: nf_tab... |
241 |
.destroy_clone = nft_counter_destroy, |
96518518c netfilter: add nf... |
242 |
.dump = nft_counter_dump, |
086f33216 netfilter: nf_tab... |
243 |
.clone = nft_counter_clone, |
96518518c netfilter: add nf... |
244 |
}; |
ef1f7df91 netfilter: nf_tab... |
245 246 247 248 249 |
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 netfilter: nf_tab... |
250 |
.flags = NFT_EXPR_STATEFUL, |
ef1f7df91 netfilter: nf_tab... |
251 252 |
.owner = THIS_MODULE, }; |
96518518c netfilter: add nf... |
253 254 |
static int __init nft_counter_module_init(void) { |
d84701ecb netfilter: nft_co... |
255 256 257 258 |
int cpu, err; for_each_possible_cpu(cpu) seqcount_init(per_cpu_ptr(&nft_counter_seq, cpu)); |
b1ce0ced1 netfilter: nft_co... |
259 |
|
dfc46034b netfilter: nf_tab... |
260 |
err = nft_register_obj(&nft_counter_obj_type); |
b1ce0ced1 netfilter: nft_co... |
261 262 263 264 265 266 267 268 269 |
if (err < 0) return err; err = nft_register_expr(&nft_counter_type); if (err < 0) goto err1; return 0; err1: |
dfc46034b netfilter: nf_tab... |
270 |
nft_unregister_obj(&nft_counter_obj_type); |
b1ce0ced1 netfilter: nft_co... |
271 |
return err; |
96518518c netfilter: add nf... |
272 273 274 275 |
} static void __exit nft_counter_module_exit(void) { |
ef1f7df91 netfilter: nf_tab... |
276 |
nft_unregister_expr(&nft_counter_type); |
dfc46034b netfilter: nf_tab... |
277 |
nft_unregister_obj(&nft_counter_obj_type); |
96518518c netfilter: add nf... |
278 279 280 281 282 283 284 285 |
} 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"); |
b1ce0ced1 netfilter: nft_co... |
286 |
MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_COUNTER); |
4cacc3951 netfilter: Add MO... |
287 |
MODULE_DESCRIPTION("nftables counter rule support"); |