1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
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 	u64		tokens_max;
22 	u64		rate;
23 	u64		nsecs;
24 	u32		burst;
25 	bool		invert;
26 };
27 
nft_limit_eval(struct nft_limit * limit,u64 cost)28 static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
29 {
30 	u64 now, tokens;
31 	s64 delta;
32 
33 	spin_lock_bh(&limit->lock);
34 	now = ktime_get_ns();
35 	tokens = limit->tokens + now - limit->last;
36 	if (tokens > limit->tokens_max)
37 		tokens = limit->tokens_max;
38 
39 	limit->last = now;
40 	delta = tokens - cost;
41 	if (delta >= 0) {
42 		limit->tokens = delta;
43 		spin_unlock_bh(&limit->lock);
44 		return limit->invert;
45 	}
46 	limit->tokens = tokens;
47 	spin_unlock_bh(&limit->lock);
48 	return !limit->invert;
49 }
50 
51 /* Use same default as in iptables. */
52 #define NFT_LIMIT_PKT_BURST_DEFAULT	5
53 
nft_limit_init(struct nft_limit * limit,const struct nlattr * const tb[],bool pkts)54 static int nft_limit_init(struct nft_limit *limit,
55 			  const struct nlattr * const tb[], bool pkts)
56 {
57 	u64 unit, tokens;
58 
59 	if (tb[NFTA_LIMIT_RATE] == NULL ||
60 	    tb[NFTA_LIMIT_UNIT] == NULL)
61 		return -EINVAL;
62 
63 	limit->rate = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_RATE]));
64 	unit = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_UNIT]));
65 	limit->nsecs = unit * NSEC_PER_SEC;
66 	if (limit->rate == 0 || limit->nsecs < unit)
67 		return -EOVERFLOW;
68 
69 	if (tb[NFTA_LIMIT_BURST])
70 		limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST]));
71 
72 	if (pkts && limit->burst == 0)
73 		limit->burst = NFT_LIMIT_PKT_BURST_DEFAULT;
74 
75 	if (limit->rate + limit->burst < limit->rate)
76 		return -EOVERFLOW;
77 
78 	if (pkts) {
79 		tokens = div64_u64(limit->nsecs, limit->rate) * limit->burst;
80 	} else {
81 		/* The token bucket size limits the number of tokens can be
82 		 * accumulated. tokens_max specifies the bucket size.
83 		 * tokens_max = unit * (rate + burst) / rate.
84 		 */
85 		tokens = div64_u64(limit->nsecs * (limit->rate + limit->burst),
86 				 limit->rate);
87 	}
88 
89 	limit->tokens = tokens;
90 	limit->tokens_max = limit->tokens;
91 
92 	if (tb[NFTA_LIMIT_FLAGS]) {
93 		u32 flags = ntohl(nla_get_be32(tb[NFTA_LIMIT_FLAGS]));
94 
95 		if (flags & NFT_LIMIT_F_INV)
96 			limit->invert = true;
97 	}
98 	limit->last = ktime_get_ns();
99 	spin_lock_init(&limit->lock);
100 
101 	return 0;
102 }
103 
nft_limit_dump(struct sk_buff * skb,const struct nft_limit * limit,enum nft_limit_type type)104 static int nft_limit_dump(struct sk_buff *skb, const struct nft_limit *limit,
105 			  enum nft_limit_type type)
106 {
107 	u32 flags = limit->invert ? NFT_LIMIT_F_INV : 0;
108 	u64 secs = div_u64(limit->nsecs, NSEC_PER_SEC);
109 
110 	if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(limit->rate),
111 			 NFTA_LIMIT_PAD) ||
112 	    nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(secs),
113 			 NFTA_LIMIT_PAD) ||
114 	    nla_put_be32(skb, NFTA_LIMIT_BURST, htonl(limit->burst)) ||
115 	    nla_put_be32(skb, NFTA_LIMIT_TYPE, htonl(type)) ||
116 	    nla_put_be32(skb, NFTA_LIMIT_FLAGS, htonl(flags)))
117 		goto nla_put_failure;
118 	return 0;
119 
120 nla_put_failure:
121 	return -1;
122 }
123 
124 struct nft_limit_pkts {
125 	struct nft_limit	limit;
126 	u64			cost;
127 };
128 
nft_limit_pkts_eval(const struct nft_expr * expr,struct nft_regs * regs,const struct nft_pktinfo * pkt)129 static void nft_limit_pkts_eval(const struct nft_expr *expr,
130 				struct nft_regs *regs,
131 				const struct nft_pktinfo *pkt)
132 {
133 	struct nft_limit_pkts *priv = nft_expr_priv(expr);
134 
135 	if (nft_limit_eval(&priv->limit, priv->cost))
136 		regs->verdict.code = NFT_BREAK;
137 }
138 
139 static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = {
140 	[NFTA_LIMIT_RATE]	= { .type = NLA_U64 },
141 	[NFTA_LIMIT_UNIT]	= { .type = NLA_U64 },
142 	[NFTA_LIMIT_BURST]	= { .type = NLA_U32 },
143 	[NFTA_LIMIT_TYPE]	= { .type = NLA_U32 },
144 	[NFTA_LIMIT_FLAGS]	= { .type = NLA_U32 },
145 };
146 
nft_limit_pkts_init(const struct nft_ctx * ctx,const struct nft_expr * expr,const struct nlattr * const tb[])147 static int nft_limit_pkts_init(const struct nft_ctx *ctx,
148 			       const struct nft_expr *expr,
149 			       const struct nlattr * const tb[])
150 {
151 	struct nft_limit_pkts *priv = nft_expr_priv(expr);
152 	int err;
153 
154 	err = nft_limit_init(&priv->limit, tb, true);
155 	if (err < 0)
156 		return err;
157 
158 	priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate);
159 	return 0;
160 }
161 
nft_limit_pkts_dump(struct sk_buff * skb,const struct nft_expr * expr)162 static int nft_limit_pkts_dump(struct sk_buff *skb, const struct nft_expr *expr)
163 {
164 	const struct nft_limit_pkts *priv = nft_expr_priv(expr);
165 
166 	return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS);
167 }
168 
169 static struct nft_expr_type nft_limit_type;
170 static const struct nft_expr_ops nft_limit_pkts_ops = {
171 	.type		= &nft_limit_type,
172 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_limit_pkts)),
173 	.eval		= nft_limit_pkts_eval,
174 	.init		= nft_limit_pkts_init,
175 	.dump		= nft_limit_pkts_dump,
176 };
177 
nft_limit_bytes_eval(const struct nft_expr * expr,struct nft_regs * regs,const struct nft_pktinfo * pkt)178 static void nft_limit_bytes_eval(const struct nft_expr *expr,
179 				 struct nft_regs *regs,
180 				 const struct nft_pktinfo *pkt)
181 {
182 	struct nft_limit *priv = nft_expr_priv(expr);
183 	u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate);
184 
185 	if (nft_limit_eval(priv, cost))
186 		regs->verdict.code = NFT_BREAK;
187 }
188 
nft_limit_bytes_init(const struct nft_ctx * ctx,const struct nft_expr * expr,const struct nlattr * const tb[])189 static int nft_limit_bytes_init(const struct nft_ctx *ctx,
190 				const struct nft_expr *expr,
191 				const struct nlattr * const tb[])
192 {
193 	struct nft_limit *priv = nft_expr_priv(expr);
194 
195 	return nft_limit_init(priv, tb, false);
196 }
197 
nft_limit_bytes_dump(struct sk_buff * skb,const struct nft_expr * expr)198 static int nft_limit_bytes_dump(struct sk_buff *skb,
199 				const struct nft_expr *expr)
200 {
201 	const struct nft_limit *priv = nft_expr_priv(expr);
202 
203 	return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES);
204 }
205 
206 static const struct nft_expr_ops nft_limit_bytes_ops = {
207 	.type		= &nft_limit_type,
208 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_limit)),
209 	.eval		= nft_limit_bytes_eval,
210 	.init		= nft_limit_bytes_init,
211 	.dump		= nft_limit_bytes_dump,
212 };
213 
214 static const struct nft_expr_ops *
nft_limit_select_ops(const struct nft_ctx * ctx,const struct nlattr * const tb[])215 nft_limit_select_ops(const struct nft_ctx *ctx,
216 		     const struct nlattr * const tb[])
217 {
218 	if (tb[NFTA_LIMIT_TYPE] == NULL)
219 		return &nft_limit_pkts_ops;
220 
221 	switch (ntohl(nla_get_be32(tb[NFTA_LIMIT_TYPE]))) {
222 	case NFT_LIMIT_PKTS:
223 		return &nft_limit_pkts_ops;
224 	case NFT_LIMIT_PKT_BYTES:
225 		return &nft_limit_bytes_ops;
226 	}
227 	return ERR_PTR(-EOPNOTSUPP);
228 }
229 
230 static struct nft_expr_type nft_limit_type __read_mostly = {
231 	.name		= "limit",
232 	.select_ops	= nft_limit_select_ops,
233 	.policy		= nft_limit_policy,
234 	.maxattr	= NFTA_LIMIT_MAX,
235 	.flags		= NFT_EXPR_STATEFUL,
236 	.owner		= THIS_MODULE,
237 };
238 
nft_limit_obj_pkts_eval(struct nft_object * obj,struct nft_regs * regs,const struct nft_pktinfo * pkt)239 static void nft_limit_obj_pkts_eval(struct nft_object *obj,
240 				    struct nft_regs *regs,
241 				    const struct nft_pktinfo *pkt)
242 {
243 	struct nft_limit_pkts *priv = nft_obj_data(obj);
244 
245 	if (nft_limit_eval(&priv->limit, priv->cost))
246 		regs->verdict.code = NFT_BREAK;
247 }
248 
nft_limit_obj_pkts_init(const struct nft_ctx * ctx,const struct nlattr * const tb[],struct nft_object * obj)249 static int nft_limit_obj_pkts_init(const struct nft_ctx *ctx,
250 				   const struct nlattr * const tb[],
251 				   struct nft_object *obj)
252 {
253 	struct nft_limit_pkts *priv = nft_obj_data(obj);
254 	int err;
255 
256 	err = nft_limit_init(&priv->limit, tb, true);
257 	if (err < 0)
258 		return err;
259 
260 	priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate);
261 	return 0;
262 }
263 
nft_limit_obj_pkts_dump(struct sk_buff * skb,struct nft_object * obj,bool reset)264 static int nft_limit_obj_pkts_dump(struct sk_buff *skb,
265 				   struct nft_object *obj,
266 				   bool reset)
267 {
268 	const struct nft_limit_pkts *priv = nft_obj_data(obj);
269 
270 	return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS);
271 }
272 
273 static struct nft_object_type nft_limit_obj_type;
274 static const struct nft_object_ops nft_limit_obj_pkts_ops = {
275 	.type		= &nft_limit_obj_type,
276 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_limit_pkts)),
277 	.init		= nft_limit_obj_pkts_init,
278 	.eval		= nft_limit_obj_pkts_eval,
279 	.dump		= nft_limit_obj_pkts_dump,
280 };
281 
nft_limit_obj_bytes_eval(struct nft_object * obj,struct nft_regs * regs,const struct nft_pktinfo * pkt)282 static void nft_limit_obj_bytes_eval(struct nft_object *obj,
283 				     struct nft_regs *regs,
284 				     const struct nft_pktinfo *pkt)
285 {
286 	struct nft_limit *priv = nft_obj_data(obj);
287 	u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate);
288 
289 	if (nft_limit_eval(priv, cost))
290 		regs->verdict.code = NFT_BREAK;
291 }
292 
nft_limit_obj_bytes_init(const struct nft_ctx * ctx,const struct nlattr * const tb[],struct nft_object * obj)293 static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx,
294 				    const struct nlattr * const tb[],
295 				    struct nft_object *obj)
296 {
297 	struct nft_limit *priv = nft_obj_data(obj);
298 
299 	return nft_limit_init(priv, tb, false);
300 }
301 
nft_limit_obj_bytes_dump(struct sk_buff * skb,struct nft_object * obj,bool reset)302 static int nft_limit_obj_bytes_dump(struct sk_buff *skb,
303 				    struct nft_object *obj,
304 				    bool reset)
305 {
306 	const struct nft_limit *priv = nft_obj_data(obj);
307 
308 	return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES);
309 }
310 
311 static struct nft_object_type nft_limit_obj_type;
312 static const struct nft_object_ops nft_limit_obj_bytes_ops = {
313 	.type		= &nft_limit_obj_type,
314 	.size		= sizeof(struct nft_limit),
315 	.init		= nft_limit_obj_bytes_init,
316 	.eval		= nft_limit_obj_bytes_eval,
317 	.dump		= nft_limit_obj_bytes_dump,
318 };
319 
320 static const struct nft_object_ops *
nft_limit_obj_select_ops(const struct nft_ctx * ctx,const struct nlattr * const tb[])321 nft_limit_obj_select_ops(const struct nft_ctx *ctx,
322 			 const struct nlattr * const tb[])
323 {
324 	if (!tb[NFTA_LIMIT_TYPE])
325 		return &nft_limit_obj_pkts_ops;
326 
327 	switch (ntohl(nla_get_be32(tb[NFTA_LIMIT_TYPE]))) {
328 	case NFT_LIMIT_PKTS:
329 		return &nft_limit_obj_pkts_ops;
330 	case NFT_LIMIT_PKT_BYTES:
331 		return &nft_limit_obj_bytes_ops;
332 	}
333 	return ERR_PTR(-EOPNOTSUPP);
334 }
335 
336 static struct nft_object_type nft_limit_obj_type __read_mostly = {
337 	.select_ops	= nft_limit_obj_select_ops,
338 	.type		= NFT_OBJECT_LIMIT,
339 	.maxattr	= NFTA_LIMIT_MAX,
340 	.policy		= nft_limit_policy,
341 	.owner		= THIS_MODULE,
342 };
343 
nft_limit_module_init(void)344 static int __init nft_limit_module_init(void)
345 {
346 	int err;
347 
348 	err = nft_register_obj(&nft_limit_obj_type);
349 	if (err < 0)
350 		return err;
351 
352 	err = nft_register_expr(&nft_limit_type);
353 	if (err < 0)
354 		goto err1;
355 
356 	return 0;
357 err1:
358 	nft_unregister_obj(&nft_limit_obj_type);
359 	return err;
360 }
361 
nft_limit_module_exit(void)362 static void __exit nft_limit_module_exit(void)
363 {
364 	nft_unregister_expr(&nft_limit_type);
365 	nft_unregister_obj(&nft_limit_obj_type);
366 }
367 
368 module_init(nft_limit_module_init);
369 module_exit(nft_limit_module_exit);
370 
371 MODULE_LICENSE("GPL");
372 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
373 MODULE_ALIAS_NFT_EXPR("limit");
374 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_LIMIT);
375 MODULE_DESCRIPTION("nftables limit expression support");
376