1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
5 * Development of this code funded by Astaro AG (http://www.astaro.com/)
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>
28 static inline bool nft_limit_eval(struct nft_limit
*limit
, u64 cost
)
33 spin_lock_bh(&limit
->lock
);
35 tokens
= limit
->tokens
+ now
- limit
->last
;
36 if (tokens
> limit
->tokens_max
)
37 tokens
= limit
->tokens_max
;
40 delta
= tokens
- cost
;
42 limit
->tokens
= delta
;
43 spin_unlock_bh(&limit
->lock
);
46 limit
->tokens
= tokens
;
47 spin_unlock_bh(&limit
->lock
);
48 return !limit
->invert
;
51 /* Use same default as in iptables. */
52 #define NFT_LIMIT_PKT_BURST_DEFAULT 5
54 static int nft_limit_init(struct nft_limit
*limit
,
55 const struct nlattr
* const tb
[], bool pkts
)
59 if (tb
[NFTA_LIMIT_RATE
] == NULL
||
60 tb
[NFTA_LIMIT_UNIT
] == NULL
)
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
)
69 if (tb
[NFTA_LIMIT_BURST
])
70 limit
->burst
= ntohl(nla_get_be32(tb
[NFTA_LIMIT_BURST
]));
72 if (pkts
&& limit
->burst
== 0)
73 limit
->burst
= NFT_LIMIT_PKT_BURST_DEFAULT
;
75 if (limit
->rate
+ limit
->burst
< limit
->rate
)
79 tokens
= div_u64(limit
->nsecs
, limit
->rate
) * limit
->burst
;
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.
85 tokens
= div_u64(limit
->nsecs
* (limit
->rate
+ limit
->burst
),
89 limit
->tokens
= tokens
;
90 limit
->tokens_max
= limit
->tokens
;
92 if (tb
[NFTA_LIMIT_FLAGS
]) {
93 u32 flags
= ntohl(nla_get_be32(tb
[NFTA_LIMIT_FLAGS
]));
95 if (flags
& NFT_LIMIT_F_INV
)
98 limit
->last
= ktime_get_ns();
99 spin_lock_init(&limit
->lock
);
104 static int nft_limit_dump(struct sk_buff
*skb
, const struct nft_limit
*limit
,
105 enum nft_limit_type type
)
107 u32 flags
= limit
->invert
? NFT_LIMIT_F_INV
: 0;
108 u64 secs
= div_u64(limit
->nsecs
, NSEC_PER_SEC
);
110 if (nla_put_be64(skb
, NFTA_LIMIT_RATE
, cpu_to_be64(limit
->rate
),
112 nla_put_be64(skb
, NFTA_LIMIT_UNIT
, cpu_to_be64(secs
),
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
;
124 struct nft_limit_pkts
{
125 struct nft_limit limit
;
129 static void nft_limit_pkts_eval(const struct nft_expr
*expr
,
130 struct nft_regs
*regs
,
131 const struct nft_pktinfo
*pkt
)
133 struct nft_limit_pkts
*priv
= nft_expr_priv(expr
);
135 if (nft_limit_eval(&priv
->limit
, priv
->cost
))
136 regs
->verdict
.code
= NFT_BREAK
;
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
},
147 static int nft_limit_pkts_init(const struct nft_ctx
*ctx
,
148 const struct nft_expr
*expr
,
149 const struct nlattr
* const tb
[])
151 struct nft_limit_pkts
*priv
= nft_expr_priv(expr
);
154 err
= nft_limit_init(&priv
->limit
, tb
, true);
158 priv
->cost
= div64_u64(priv
->limit
.nsecs
, priv
->limit
.rate
);
162 static int nft_limit_pkts_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
164 const struct nft_limit_pkts
*priv
= nft_expr_priv(expr
);
166 return nft_limit_dump(skb
, &priv
->limit
, NFT_LIMIT_PKTS
);
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
,
178 static void nft_limit_bytes_eval(const struct nft_expr
*expr
,
179 struct nft_regs
*regs
,
180 const struct nft_pktinfo
*pkt
)
182 struct nft_limit
*priv
= nft_expr_priv(expr
);
183 u64 cost
= div64_u64(priv
->nsecs
* pkt
->skb
->len
, priv
->rate
);
185 if (nft_limit_eval(priv
, cost
))
186 regs
->verdict
.code
= NFT_BREAK
;
189 static int nft_limit_bytes_init(const struct nft_ctx
*ctx
,
190 const struct nft_expr
*expr
,
191 const struct nlattr
* const tb
[])
193 struct nft_limit
*priv
= nft_expr_priv(expr
);
195 return nft_limit_init(priv
, tb
, false);
198 static int nft_limit_bytes_dump(struct sk_buff
*skb
,
199 const struct nft_expr
*expr
)
201 const struct nft_limit
*priv
= nft_expr_priv(expr
);
203 return nft_limit_dump(skb
, priv
, NFT_LIMIT_PKT_BYTES
);
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
,
214 static const struct nft_expr_ops
*
215 nft_limit_select_ops(const struct nft_ctx
*ctx
,
216 const struct nlattr
* const tb
[])
218 if (tb
[NFTA_LIMIT_TYPE
] == NULL
)
219 return &nft_limit_pkts_ops
;
221 switch (ntohl(nla_get_be32(tb
[NFTA_LIMIT_TYPE
]))) {
223 return &nft_limit_pkts_ops
;
224 case NFT_LIMIT_PKT_BYTES
:
225 return &nft_limit_bytes_ops
;
227 return ERR_PTR(-EOPNOTSUPP
);
230 static struct nft_expr_type nft_limit_type __read_mostly
= {
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
,
239 static void nft_limit_obj_pkts_eval(struct nft_object
*obj
,
240 struct nft_regs
*regs
,
241 const struct nft_pktinfo
*pkt
)
243 struct nft_limit_pkts
*priv
= nft_obj_data(obj
);
245 if (nft_limit_eval(&priv
->limit
, priv
->cost
))
246 regs
->verdict
.code
= NFT_BREAK
;
249 static int nft_limit_obj_pkts_init(const struct nft_ctx
*ctx
,
250 const struct nlattr
* const tb
[],
251 struct nft_object
*obj
)
253 struct nft_limit_pkts
*priv
= nft_obj_data(obj
);
256 err
= nft_limit_init(&priv
->limit
, tb
, true);
260 priv
->cost
= div64_u64(priv
->limit
.nsecs
, priv
->limit
.rate
);
264 static int nft_limit_obj_pkts_dump(struct sk_buff
*skb
,
265 struct nft_object
*obj
,
268 const struct nft_limit_pkts
*priv
= nft_obj_data(obj
);
270 return nft_limit_dump(skb
, &priv
->limit
, NFT_LIMIT_PKTS
);
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
,
282 static void nft_limit_obj_bytes_eval(struct nft_object
*obj
,
283 struct nft_regs
*regs
,
284 const struct nft_pktinfo
*pkt
)
286 struct nft_limit
*priv
= nft_obj_data(obj
);
287 u64 cost
= div64_u64(priv
->nsecs
* pkt
->skb
->len
, priv
->rate
);
289 if (nft_limit_eval(priv
, cost
))
290 regs
->verdict
.code
= NFT_BREAK
;
293 static int nft_limit_obj_bytes_init(const struct nft_ctx
*ctx
,
294 const struct nlattr
* const tb
[],
295 struct nft_object
*obj
)
297 struct nft_limit
*priv
= nft_obj_data(obj
);
299 return nft_limit_init(priv
, tb
, false);
302 static int nft_limit_obj_bytes_dump(struct sk_buff
*skb
,
303 struct nft_object
*obj
,
306 const struct nft_limit
*priv
= nft_obj_data(obj
);
308 return nft_limit_dump(skb
, priv
, NFT_LIMIT_PKT_BYTES
);
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
,
320 static const struct nft_object_ops
*
321 nft_limit_obj_select_ops(const struct nft_ctx
*ctx
,
322 const struct nlattr
* const tb
[])
324 if (!tb
[NFTA_LIMIT_TYPE
])
325 return &nft_limit_obj_pkts_ops
;
327 switch (ntohl(nla_get_be32(tb
[NFTA_LIMIT_TYPE
]))) {
329 return &nft_limit_obj_pkts_ops
;
330 case NFT_LIMIT_PKT_BYTES
:
331 return &nft_limit_obj_bytes_ops
;
333 return ERR_PTR(-EOPNOTSUPP
);
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
,
344 static int __init
nft_limit_module_init(void)
348 err
= nft_register_obj(&nft_limit_obj_type
);
352 err
= nft_register_expr(&nft_limit_type
);
358 nft_unregister_obj(&nft_limit_obj_type
);
362 static void __exit
nft_limit_module_exit(void)
364 nft_unregister_expr(&nft_limit_type
);
365 nft_unregister_obj(&nft_limit_obj_type
);
368 module_init(nft_limit_module_init
);
369 module_exit(nft_limit_module_exit
);
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
);