]> Git Repo - J-linux.git/blob - net/netfilter/nft_limit.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / net / netfilter / nft_limit.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2008-2009 Patrick McHardy <[email protected]>
4  *
5  * Development of this code funded by Astaro AG (http://www.astaro.com/)
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/spinlock.h>
12 #include <linux/netlink.h>
13 #include <linux/netfilter.h>
14 #include <linux/netfilter/nf_tables.h>
15 #include <net/netfilter/nf_tables.h>
16
17 struct nft_limit {
18         spinlock_t      lock;
19         u64             last;
20         u64             tokens;
21 };
22
23 struct nft_limit_priv {
24         struct nft_limit *limit;
25         u64             tokens_max;
26         u64             rate;
27         u64             nsecs;
28         u32             burst;
29         bool            invert;
30 };
31
32 static inline bool nft_limit_eval(struct nft_limit_priv *priv, u64 cost)
33 {
34         u64 now, tokens;
35         s64 delta;
36
37         spin_lock_bh(&priv->limit->lock);
38         now = ktime_get_ns();
39         tokens = priv->limit->tokens + now - priv->limit->last;
40         if (tokens > priv->tokens_max)
41                 tokens = priv->tokens_max;
42
43         priv->limit->last = now;
44         delta = tokens - cost;
45         if (delta >= 0) {
46                 priv->limit->tokens = delta;
47                 spin_unlock_bh(&priv->limit->lock);
48                 return priv->invert;
49         }
50         priv->limit->tokens = tokens;
51         spin_unlock_bh(&priv->limit->lock);
52         return !priv->invert;
53 }
54
55 /* Use same default as in iptables. */
56 #define NFT_LIMIT_PKT_BURST_DEFAULT     5
57
58 static int nft_limit_init(struct nft_limit_priv *priv,
59                           const struct nlattr * const tb[], bool pkts)
60 {
61         u64 unit, tokens, rate_with_burst;
62         bool invert = false;
63
64         if (tb[NFTA_LIMIT_RATE] == NULL ||
65             tb[NFTA_LIMIT_UNIT] == NULL)
66                 return -EINVAL;
67
68         priv->rate = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_RATE]));
69         if (priv->rate == 0)
70                 return -EINVAL;
71
72         unit = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_UNIT]));
73         if (check_mul_overflow(unit, NSEC_PER_SEC, &priv->nsecs))
74                 return -EOVERFLOW;
75
76         if (tb[NFTA_LIMIT_BURST])
77                 priv->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST]));
78
79         if (pkts && priv->burst == 0)
80                 priv->burst = NFT_LIMIT_PKT_BURST_DEFAULT;
81
82         if (check_add_overflow(priv->rate, priv->burst, &rate_with_burst))
83                 return -EOVERFLOW;
84
85         if (pkts) {
86                 u64 tmp = div64_u64(priv->nsecs, priv->rate);
87
88                 if (check_mul_overflow(tmp, priv->burst, &tokens))
89                         return -EOVERFLOW;
90         } else {
91                 u64 tmp;
92
93                 /* The token bucket size limits the number of tokens can be
94                  * accumulated. tokens_max specifies the bucket size.
95                  * tokens_max = unit * (rate + burst) / rate.
96                  */
97                 if (check_mul_overflow(priv->nsecs, rate_with_burst, &tmp))
98                         return -EOVERFLOW;
99
100                 tokens = div64_u64(tmp, priv->rate);
101         }
102
103         if (tb[NFTA_LIMIT_FLAGS]) {
104                 u32 flags = ntohl(nla_get_be32(tb[NFTA_LIMIT_FLAGS]));
105
106                 if (flags & ~NFT_LIMIT_F_INV)
107                         return -EOPNOTSUPP;
108
109                 if (flags & NFT_LIMIT_F_INV)
110                         invert = true;
111         }
112
113         priv->limit = kmalloc(sizeof(*priv->limit), GFP_KERNEL_ACCOUNT);
114         if (!priv->limit)
115                 return -ENOMEM;
116
117         priv->limit->tokens = tokens;
118         priv->tokens_max = priv->limit->tokens;
119         priv->invert = invert;
120         priv->limit->last = ktime_get_ns();
121         spin_lock_init(&priv->limit->lock);
122
123         return 0;
124 }
125
126 static int nft_limit_dump(struct sk_buff *skb, const struct nft_limit_priv *priv,
127                           enum nft_limit_type type)
128 {
129         u32 flags = priv->invert ? NFT_LIMIT_F_INV : 0;
130         u64 secs = div_u64(priv->nsecs, NSEC_PER_SEC);
131
132         if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(priv->rate),
133                          NFTA_LIMIT_PAD) ||
134             nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(secs),
135                          NFTA_LIMIT_PAD) ||
136             nla_put_be32(skb, NFTA_LIMIT_BURST, htonl(priv->burst)) ||
137             nla_put_be32(skb, NFTA_LIMIT_TYPE, htonl(type)) ||
138             nla_put_be32(skb, NFTA_LIMIT_FLAGS, htonl(flags)))
139                 goto nla_put_failure;
140         return 0;
141
142 nla_put_failure:
143         return -1;
144 }
145
146 static void nft_limit_destroy(const struct nft_ctx *ctx,
147                               const struct nft_limit_priv *priv)
148 {
149         kfree(priv->limit);
150 }
151
152 static int nft_limit_clone(struct nft_limit_priv *priv_dst,
153                            const struct nft_limit_priv *priv_src, gfp_t gfp)
154 {
155         priv_dst->tokens_max = priv_src->tokens_max;
156         priv_dst->rate = priv_src->rate;
157         priv_dst->nsecs = priv_src->nsecs;
158         priv_dst->burst = priv_src->burst;
159         priv_dst->invert = priv_src->invert;
160
161         priv_dst->limit = kmalloc(sizeof(*priv_dst->limit), gfp);
162         if (!priv_dst->limit)
163                 return -ENOMEM;
164
165         spin_lock_init(&priv_dst->limit->lock);
166         priv_dst->limit->tokens = priv_src->tokens_max;
167         priv_dst->limit->last = ktime_get_ns();
168
169         return 0;
170 }
171
172 struct nft_limit_priv_pkts {
173         struct nft_limit_priv   limit;
174         u64                     cost;
175 };
176
177 static void nft_limit_pkts_eval(const struct nft_expr *expr,
178                                 struct nft_regs *regs,
179                                 const struct nft_pktinfo *pkt)
180 {
181         struct nft_limit_priv_pkts *priv = nft_expr_priv(expr);
182
183         if (nft_limit_eval(&priv->limit, priv->cost))
184                 regs->verdict.code = NFT_BREAK;
185 }
186
187 static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = {
188         [NFTA_LIMIT_RATE]       = { .type = NLA_U64 },
189         [NFTA_LIMIT_UNIT]       = { .type = NLA_U64 },
190         [NFTA_LIMIT_BURST]      = { .type = NLA_U32 },
191         [NFTA_LIMIT_TYPE]       = { .type = NLA_U32 },
192         [NFTA_LIMIT_FLAGS]      = { .type = NLA_U32 },
193 };
194
195 static int nft_limit_pkts_init(const struct nft_ctx *ctx,
196                                const struct nft_expr *expr,
197                                const struct nlattr * const tb[])
198 {
199         struct nft_limit_priv_pkts *priv = nft_expr_priv(expr);
200         int err;
201
202         err = nft_limit_init(&priv->limit, tb, true);
203         if (err < 0)
204                 return err;
205
206         priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate);
207         return 0;
208 }
209
210 static int nft_limit_pkts_dump(struct sk_buff *skb,
211                                const struct nft_expr *expr, bool reset)
212 {
213         const struct nft_limit_priv_pkts *priv = nft_expr_priv(expr);
214
215         return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS);
216 }
217
218 static void nft_limit_pkts_destroy(const struct nft_ctx *ctx,
219                                    const struct nft_expr *expr)
220 {
221         const struct nft_limit_priv_pkts *priv = nft_expr_priv(expr);
222
223         nft_limit_destroy(ctx, &priv->limit);
224 }
225
226 static int nft_limit_pkts_clone(struct nft_expr *dst, const struct nft_expr *src,
227                                 gfp_t gfp)
228 {
229         struct nft_limit_priv_pkts *priv_dst = nft_expr_priv(dst);
230         struct nft_limit_priv_pkts *priv_src = nft_expr_priv(src);
231
232         priv_dst->cost = priv_src->cost;
233
234         return nft_limit_clone(&priv_dst->limit, &priv_src->limit, gfp);
235 }
236
237 static struct nft_expr_type nft_limit_type;
238 static const struct nft_expr_ops nft_limit_pkts_ops = {
239         .type           = &nft_limit_type,
240         .size           = NFT_EXPR_SIZE(sizeof(struct nft_limit_priv_pkts)),
241         .eval           = nft_limit_pkts_eval,
242         .init           = nft_limit_pkts_init,
243         .destroy        = nft_limit_pkts_destroy,
244         .clone          = nft_limit_pkts_clone,
245         .dump           = nft_limit_pkts_dump,
246         .reduce         = NFT_REDUCE_READONLY,
247 };
248
249 static void nft_limit_bytes_eval(const struct nft_expr *expr,
250                                  struct nft_regs *regs,
251                                  const struct nft_pktinfo *pkt)
252 {
253         struct nft_limit_priv *priv = nft_expr_priv(expr);
254         u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate);
255
256         if (nft_limit_eval(priv, cost))
257                 regs->verdict.code = NFT_BREAK;
258 }
259
260 static int nft_limit_bytes_init(const struct nft_ctx *ctx,
261                                 const struct nft_expr *expr,
262                                 const struct nlattr * const tb[])
263 {
264         struct nft_limit_priv *priv = nft_expr_priv(expr);
265
266         return nft_limit_init(priv, tb, false);
267 }
268
269 static int nft_limit_bytes_dump(struct sk_buff *skb,
270                                 const struct nft_expr *expr, bool reset)
271 {
272         const struct nft_limit_priv *priv = nft_expr_priv(expr);
273
274         return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES);
275 }
276
277 static void nft_limit_bytes_destroy(const struct nft_ctx *ctx,
278                                     const struct nft_expr *expr)
279 {
280         const struct nft_limit_priv *priv = nft_expr_priv(expr);
281
282         nft_limit_destroy(ctx, priv);
283 }
284
285 static int nft_limit_bytes_clone(struct nft_expr *dst, const struct nft_expr *src,
286                                  gfp_t gfp)
287 {
288         struct nft_limit_priv *priv_dst = nft_expr_priv(dst);
289         struct nft_limit_priv *priv_src = nft_expr_priv(src);
290
291         return nft_limit_clone(priv_dst, priv_src, gfp);
292 }
293
294 static const struct nft_expr_ops nft_limit_bytes_ops = {
295         .type           = &nft_limit_type,
296         .size           = NFT_EXPR_SIZE(sizeof(struct nft_limit_priv)),
297         .eval           = nft_limit_bytes_eval,
298         .init           = nft_limit_bytes_init,
299         .dump           = nft_limit_bytes_dump,
300         .clone          = nft_limit_bytes_clone,
301         .destroy        = nft_limit_bytes_destroy,
302         .reduce         = NFT_REDUCE_READONLY,
303 };
304
305 static const struct nft_expr_ops *
306 nft_limit_select_ops(const struct nft_ctx *ctx,
307                      const struct nlattr * const tb[])
308 {
309         if (tb[NFTA_LIMIT_TYPE] == NULL)
310                 return &nft_limit_pkts_ops;
311
312         switch (ntohl(nla_get_be32(tb[NFTA_LIMIT_TYPE]))) {
313         case NFT_LIMIT_PKTS:
314                 return &nft_limit_pkts_ops;
315         case NFT_LIMIT_PKT_BYTES:
316                 return &nft_limit_bytes_ops;
317         }
318         return ERR_PTR(-EOPNOTSUPP);
319 }
320
321 static struct nft_expr_type nft_limit_type __read_mostly = {
322         .name           = "limit",
323         .select_ops     = nft_limit_select_ops,
324         .policy         = nft_limit_policy,
325         .maxattr        = NFTA_LIMIT_MAX,
326         .flags          = NFT_EXPR_STATEFUL,
327         .owner          = THIS_MODULE,
328 };
329
330 static void nft_limit_obj_pkts_eval(struct nft_object *obj,
331                                     struct nft_regs *regs,
332                                     const struct nft_pktinfo *pkt)
333 {
334         struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
335
336         if (nft_limit_eval(&priv->limit, priv->cost))
337                 regs->verdict.code = NFT_BREAK;
338 }
339
340 static int nft_limit_obj_pkts_init(const struct nft_ctx *ctx,
341                                    const struct nlattr * const tb[],
342                                    struct nft_object *obj)
343 {
344         struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
345         int err;
346
347         err = nft_limit_init(&priv->limit, tb, true);
348         if (err < 0)
349                 return err;
350
351         priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate);
352         return 0;
353 }
354
355 static int nft_limit_obj_pkts_dump(struct sk_buff *skb,
356                                    struct nft_object *obj,
357                                    bool reset)
358 {
359         const struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
360
361         return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS);
362 }
363
364 static void nft_limit_obj_pkts_destroy(const struct nft_ctx *ctx,
365                                        struct nft_object *obj)
366 {
367         struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
368
369         nft_limit_destroy(ctx, &priv->limit);
370 }
371
372 static struct nft_object_type nft_limit_obj_type;
373 static const struct nft_object_ops nft_limit_obj_pkts_ops = {
374         .type           = &nft_limit_obj_type,
375         .size           = NFT_EXPR_SIZE(sizeof(struct nft_limit_priv_pkts)),
376         .init           = nft_limit_obj_pkts_init,
377         .destroy        = nft_limit_obj_pkts_destroy,
378         .eval           = nft_limit_obj_pkts_eval,
379         .dump           = nft_limit_obj_pkts_dump,
380 };
381
382 static void nft_limit_obj_bytes_eval(struct nft_object *obj,
383                                      struct nft_regs *regs,
384                                      const struct nft_pktinfo *pkt)
385 {
386         struct nft_limit_priv *priv = nft_obj_data(obj);
387         u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate);
388
389         if (nft_limit_eval(priv, cost))
390                 regs->verdict.code = NFT_BREAK;
391 }
392
393 static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx,
394                                     const struct nlattr * const tb[],
395                                     struct nft_object *obj)
396 {
397         struct nft_limit_priv *priv = nft_obj_data(obj);
398
399         return nft_limit_init(priv, tb, false);
400 }
401
402 static int nft_limit_obj_bytes_dump(struct sk_buff *skb,
403                                     struct nft_object *obj,
404                                     bool reset)
405 {
406         const struct nft_limit_priv *priv = nft_obj_data(obj);
407
408         return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES);
409 }
410
411 static void nft_limit_obj_bytes_destroy(const struct nft_ctx *ctx,
412                                         struct nft_object *obj)
413 {
414         struct nft_limit_priv *priv = nft_obj_data(obj);
415
416         nft_limit_destroy(ctx, priv);
417 }
418
419 static struct nft_object_type nft_limit_obj_type;
420 static const struct nft_object_ops nft_limit_obj_bytes_ops = {
421         .type           = &nft_limit_obj_type,
422         .size           = sizeof(struct nft_limit_priv),
423         .init           = nft_limit_obj_bytes_init,
424         .destroy        = nft_limit_obj_bytes_destroy,
425         .eval           = nft_limit_obj_bytes_eval,
426         .dump           = nft_limit_obj_bytes_dump,
427 };
428
429 static const struct nft_object_ops *
430 nft_limit_obj_select_ops(const struct nft_ctx *ctx,
431                          const struct nlattr * const tb[])
432 {
433         if (!tb[NFTA_LIMIT_TYPE])
434                 return &nft_limit_obj_pkts_ops;
435
436         switch (ntohl(nla_get_be32(tb[NFTA_LIMIT_TYPE]))) {
437         case NFT_LIMIT_PKTS:
438                 return &nft_limit_obj_pkts_ops;
439         case NFT_LIMIT_PKT_BYTES:
440                 return &nft_limit_obj_bytes_ops;
441         }
442         return ERR_PTR(-EOPNOTSUPP);
443 }
444
445 static struct nft_object_type nft_limit_obj_type __read_mostly = {
446         .select_ops     = nft_limit_obj_select_ops,
447         .type           = NFT_OBJECT_LIMIT,
448         .maxattr        = NFTA_LIMIT_MAX,
449         .policy         = nft_limit_policy,
450         .owner          = THIS_MODULE,
451 };
452
453 static int __init nft_limit_module_init(void)
454 {
455         int err;
456
457         err = nft_register_obj(&nft_limit_obj_type);
458         if (err < 0)
459                 return err;
460
461         err = nft_register_expr(&nft_limit_type);
462         if (err < 0)
463                 goto err1;
464
465         return 0;
466 err1:
467         nft_unregister_obj(&nft_limit_obj_type);
468         return err;
469 }
470
471 static void __exit nft_limit_module_exit(void)
472 {
473         nft_unregister_expr(&nft_limit_type);
474         nft_unregister_obj(&nft_limit_obj_type);
475 }
476
477 module_init(nft_limit_module_init);
478 module_exit(nft_limit_module_exit);
479
480 MODULE_LICENSE("GPL");
481 MODULE_AUTHOR("Patrick McHardy <[email protected]>");
482 MODULE_ALIAS_NFT_EXPR("limit");
483 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_LIMIT);
484 MODULE_DESCRIPTION("nftables limit expression support");
This page took 0.051778 seconds and 4 git commands to generate.