xref: /openbmc/linux/net/netfilter/nft_quota.c (revision aabef97a)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23d2f30a1SPablo Neira Ayuso /*
33d2f30a1SPablo Neira Ayuso  * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
43d2f30a1SPablo Neira Ayuso  */
53d2f30a1SPablo Neira Ayuso 
63d2f30a1SPablo Neira Ayuso #include <linux/kernel.h>
73d2f30a1SPablo Neira Ayuso #include <linux/init.h>
83d2f30a1SPablo Neira Ayuso #include <linux/module.h>
93d2f30a1SPablo Neira Ayuso #include <linux/atomic.h>
103d2f30a1SPablo Neira Ayuso #include <linux/netlink.h>
113d2f30a1SPablo Neira Ayuso #include <linux/netfilter.h>
123d2f30a1SPablo Neira Ayuso #include <linux/netfilter/nf_tables.h>
133d2f30a1SPablo Neira Ayuso #include <net/netfilter/nf_tables.h>
143d2f30a1SPablo Neira Ayuso 
153d2f30a1SPablo Neira Ayuso struct nft_quota {
1685936e56SFernando Fernandez Mancera 	atomic64_t	quota;
1718965317SPablo Neira Ayuso 	unsigned long	flags;
18ed0a0c60SPablo Neira Ayuso 	atomic64_t	*consumed;
193d2f30a1SPablo Neira Ayuso };
203d2f30a1SPablo Neira Ayuso 
nft_overquota(struct nft_quota * priv,const struct sk_buff * skb)2122609b43SPablo Neira Ayuso static inline bool nft_overquota(struct nft_quota *priv,
22795595f6SPablo Neira Ayuso 				 const struct sk_buff *skb)
233d2f30a1SPablo Neira Ayuso {
24ed0a0c60SPablo Neira Ayuso 	return atomic64_add_return(skb->len, priv->consumed) >=
2585936e56SFernando Fernandez Mancera 	       atomic64_read(&priv->quota);
263d2f30a1SPablo Neira Ayuso }
273d2f30a1SPablo Neira Ayuso 
nft_quota_invert(struct nft_quota * priv)2818965317SPablo Neira Ayuso static inline bool nft_quota_invert(struct nft_quota *priv)
2918965317SPablo Neira Ayuso {
3018965317SPablo Neira Ayuso 	return priv->flags & NFT_QUOTA_F_INV;
3118965317SPablo Neira Ayuso }
3218965317SPablo Neira Ayuso 
nft_quota_do_eval(struct nft_quota * priv,struct nft_regs * regs,const struct nft_pktinfo * pkt)33173705d9SPablo Neira Ayuso static inline void nft_quota_do_eval(struct nft_quota *priv,
343d2f30a1SPablo Neira Ayuso 				     struct nft_regs *regs,
353d2f30a1SPablo Neira Ayuso 				     const struct nft_pktinfo *pkt)
363d2f30a1SPablo Neira Ayuso {
3718965317SPablo Neira Ayuso 	if (nft_overquota(priv, pkt->skb) ^ nft_quota_invert(priv))
383d2f30a1SPablo Neira Ayuso 		regs->verdict.code = NFT_BREAK;
393d2f30a1SPablo Neira Ayuso }
403d2f30a1SPablo Neira Ayuso 
413d2f30a1SPablo Neira Ayuso static const struct nla_policy nft_quota_policy[NFTA_QUOTA_MAX + 1] = {
423d2f30a1SPablo Neira Ayuso 	[NFTA_QUOTA_BYTES]	= { .type = NLA_U64 },
433d2f30a1SPablo Neira Ayuso 	[NFTA_QUOTA_FLAGS]	= { .type = NLA_U32 },
4473c25fb1SPablo Neira Ayuso 	[NFTA_QUOTA_CONSUMED]	= { .type = NLA_U64 },
453d2f30a1SPablo Neira Ayuso };
463d2f30a1SPablo Neira Ayuso 
4718965317SPablo Neira Ayuso #define NFT_QUOTA_DEPLETED_BIT	1	/* From NFT_QUOTA_F_DEPLETED. */
4818965317SPablo Neira Ayuso 
nft_quota_obj_eval(struct nft_object * obj,struct nft_regs * regs,const struct nft_pktinfo * pkt)49173705d9SPablo Neira Ayuso static void nft_quota_obj_eval(struct nft_object *obj,
50173705d9SPablo Neira Ayuso 			       struct nft_regs *regs,
51173705d9SPablo Neira Ayuso 			       const struct nft_pktinfo *pkt)
523d2f30a1SPablo Neira Ayuso {
53173705d9SPablo Neira Ayuso 	struct nft_quota *priv = nft_obj_data(obj);
5418965317SPablo Neira Ayuso 	bool overquota;
55173705d9SPablo Neira Ayuso 
5618965317SPablo Neira Ayuso 	overquota = nft_overquota(priv, pkt->skb);
5718965317SPablo Neira Ayuso 	if (overquota ^ nft_quota_invert(priv))
5818965317SPablo Neira Ayuso 		regs->verdict.code = NFT_BREAK;
5918965317SPablo Neira Ayuso 
6018965317SPablo Neira Ayuso 	if (overquota &&
6118965317SPablo Neira Ayuso 	    !test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
62d152159bSFlorian Westphal 		nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0,
636fb721cfSPablo Neira Ayuso 			       NFT_MSG_NEWOBJ, 0, nft_pf(pkt), 0, GFP_ATOMIC);
64173705d9SPablo Neira Ayuso }
65173705d9SPablo Neira Ayuso 
nft_quota_do_init(const struct nlattr * const tb[],struct nft_quota * priv)66173705d9SPablo Neira Ayuso static int nft_quota_do_init(const struct nlattr * const tb[],
67173705d9SPablo Neira Ayuso 			     struct nft_quota *priv)
68173705d9SPablo Neira Ayuso {
6918965317SPablo Neira Ayuso 	unsigned long flags = 0;
7073c25fb1SPablo Neira Ayuso 	u64 quota, consumed = 0;
713d2f30a1SPablo Neira Ayuso 
723d2f30a1SPablo Neira Ayuso 	if (!tb[NFTA_QUOTA_BYTES])
733d2f30a1SPablo Neira Ayuso 		return -EINVAL;
743d2f30a1SPablo Neira Ayuso 
753d2f30a1SPablo Neira Ayuso 	quota = be64_to_cpu(nla_get_be64(tb[NFTA_QUOTA_BYTES]));
763d2f30a1SPablo Neira Ayuso 	if (quota > S64_MAX)
773d2f30a1SPablo Neira Ayuso 		return -EOVERFLOW;
783d2f30a1SPablo Neira Ayuso 
7973c25fb1SPablo Neira Ayuso 	if (tb[NFTA_QUOTA_CONSUMED]) {
8073c25fb1SPablo Neira Ayuso 		consumed = be64_to_cpu(nla_get_be64(tb[NFTA_QUOTA_CONSUMED]));
8173c25fb1SPablo Neira Ayuso 		if (consumed > quota)
8273c25fb1SPablo Neira Ayuso 			return -EINVAL;
8373c25fb1SPablo Neira Ayuso 	}
8473c25fb1SPablo Neira Ayuso 
853d2f30a1SPablo Neira Ayuso 	if (tb[NFTA_QUOTA_FLAGS]) {
863d2f30a1SPablo Neira Ayuso 		flags = ntohl(nla_get_be32(tb[NFTA_QUOTA_FLAGS]));
873d2f30a1SPablo Neira Ayuso 		if (flags & ~NFT_QUOTA_F_INV)
883d2f30a1SPablo Neira Ayuso 			return -EINVAL;
8918965317SPablo Neira Ayuso 		if (flags & NFT_QUOTA_F_DEPLETED)
9018965317SPablo Neira Ayuso 			return -EOPNOTSUPP;
913d2f30a1SPablo Neira Ayuso 	}
923d2f30a1SPablo Neira Ayuso 
9342193ffdSVasily Averin 	priv->consumed = kmalloc(sizeof(*priv->consumed), GFP_KERNEL_ACCOUNT);
94ed0a0c60SPablo Neira Ayuso 	if (!priv->consumed)
95ed0a0c60SPablo Neira Ayuso 		return -ENOMEM;
96ed0a0c60SPablo Neira Ayuso 
9785936e56SFernando Fernandez Mancera 	atomic64_set(&priv->quota, quota);
9818965317SPablo Neira Ayuso 	priv->flags = flags;
99ed0a0c60SPablo Neira Ayuso 	atomic64_set(priv->consumed, consumed);
1003d2f30a1SPablo Neira Ayuso 
1013d2f30a1SPablo Neira Ayuso 	return 0;
1023d2f30a1SPablo Neira Ayuso }
1033d2f30a1SPablo Neira Ayuso 
nft_quota_do_destroy(const struct nft_ctx * ctx,struct nft_quota * priv)104ed0a0c60SPablo Neira Ayuso static void nft_quota_do_destroy(const struct nft_ctx *ctx,
105ed0a0c60SPablo Neira Ayuso 				 struct nft_quota *priv)
106ed0a0c60SPablo Neira Ayuso {
107ed0a0c60SPablo Neira Ayuso 	kfree(priv->consumed);
108ed0a0c60SPablo Neira Ayuso }
109ed0a0c60SPablo Neira Ayuso 
nft_quota_obj_init(const struct nft_ctx * ctx,const struct nlattr * const tb[],struct nft_object * obj)11084fba055SFlorian Westphal static int nft_quota_obj_init(const struct nft_ctx *ctx,
11184fba055SFlorian Westphal 			      const struct nlattr * const tb[],
112173705d9SPablo Neira Ayuso 			      struct nft_object *obj)
1133d2f30a1SPablo Neira Ayuso {
114173705d9SPablo Neira Ayuso 	struct nft_quota *priv = nft_obj_data(obj);
115173705d9SPablo Neira Ayuso 
116173705d9SPablo Neira Ayuso 	return nft_quota_do_init(tb, priv);
117173705d9SPablo Neira Ayuso }
118173705d9SPablo Neira Ayuso 
nft_quota_obj_update(struct nft_object * obj,struct nft_object * newobj)11985936e56SFernando Fernandez Mancera static void nft_quota_obj_update(struct nft_object *obj,
12085936e56SFernando Fernandez Mancera 				 struct nft_object *newobj)
12185936e56SFernando Fernandez Mancera {
12285936e56SFernando Fernandez Mancera 	struct nft_quota *newpriv = nft_obj_data(newobj);
12385936e56SFernando Fernandez Mancera 	struct nft_quota *priv = nft_obj_data(obj);
12485936e56SFernando Fernandez Mancera 	u64 newquota;
12585936e56SFernando Fernandez Mancera 
12685936e56SFernando Fernandez Mancera 	newquota = atomic64_read(&newpriv->quota);
12785936e56SFernando Fernandez Mancera 	atomic64_set(&priv->quota, newquota);
12885936e56SFernando Fernandez Mancera 	priv->flags = newpriv->flags;
12985936e56SFernando Fernandez Mancera }
13085936e56SFernando Fernandez Mancera 
nft_quota_do_dump(struct sk_buff * skb,struct nft_quota * priv,bool reset)13143da04a5SPablo Neira Ayuso static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
13243da04a5SPablo Neira Ayuso 			     bool reset)
133173705d9SPablo Neira Ayuso {
13485936e56SFernando Fernandez Mancera 	u64 consumed, consumed_cap, quota;
13518965317SPablo Neira Ayuso 	u32 flags = priv->flags;
13643da04a5SPablo Neira Ayuso 
137795595f6SPablo Neira Ayuso 	/* Since we inconditionally increment consumed quota for each packet
138795595f6SPablo Neira Ayuso 	 * that we see, don't go over the quota boundary in what we send to
139795595f6SPablo Neira Ayuso 	 * userspace.
140795595f6SPablo Neira Ayuso 	 */
141ed0a0c60SPablo Neira Ayuso 	consumed = atomic64_read(priv->consumed);
14285936e56SFernando Fernandez Mancera 	quota = atomic64_read(&priv->quota);
14385936e56SFernando Fernandez Mancera 	if (consumed >= quota) {
14485936e56SFernando Fernandez Mancera 		consumed_cap = quota;
1458010d7feSPablo Neira Ayuso 		flags |= NFT_QUOTA_F_DEPLETED;
1468010d7feSPablo Neira Ayuso 	} else {
1478010d7feSPablo Neira Ayuso 		consumed_cap = consumed;
1488010d7feSPablo Neira Ayuso 	}
1493d2f30a1SPablo Neira Ayuso 
15085936e56SFernando Fernandez Mancera 	if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(quota),
1513d2f30a1SPablo Neira Ayuso 			 NFTA_QUOTA_PAD) ||
1528010d7feSPablo Neira Ayuso 	    nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap),
153795595f6SPablo Neira Ayuso 			 NFTA_QUOTA_PAD) ||
1543d2f30a1SPablo Neira Ayuso 	    nla_put_be32(skb, NFTA_QUOTA_FLAGS, htonl(flags)))
1553d2f30a1SPablo Neira Ayuso 		goto nla_put_failure;
1568010d7feSPablo Neira Ayuso 
1578010d7feSPablo Neira Ayuso 	if (reset) {
158ed0a0c60SPablo Neira Ayuso 		atomic64_sub(consumed, priv->consumed);
1598010d7feSPablo Neira Ayuso 		clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags);
1608010d7feSPablo Neira Ayuso 	}
1613d2f30a1SPablo Neira Ayuso 	return 0;
1623d2f30a1SPablo Neira Ayuso 
1633d2f30a1SPablo Neira Ayuso nla_put_failure:
1643d2f30a1SPablo Neira Ayuso 	return -1;
1653d2f30a1SPablo Neira Ayuso }
1663d2f30a1SPablo Neira Ayuso 
nft_quota_obj_dump(struct sk_buff * skb,struct nft_object * obj,bool reset)16743da04a5SPablo Neira Ayuso static int nft_quota_obj_dump(struct sk_buff *skb, struct nft_object *obj,
16843da04a5SPablo Neira Ayuso 			      bool reset)
169173705d9SPablo Neira Ayuso {
170173705d9SPablo Neira Ayuso 	struct nft_quota *priv = nft_obj_data(obj);
171173705d9SPablo Neira Ayuso 
17243da04a5SPablo Neira Ayuso 	return nft_quota_do_dump(skb, priv, reset);
173173705d9SPablo Neira Ayuso }
174173705d9SPablo Neira Ayuso 
nft_quota_obj_destroy(const struct nft_ctx * ctx,struct nft_object * obj)175ed0a0c60SPablo Neira Ayuso static void nft_quota_obj_destroy(const struct nft_ctx *ctx,
176ed0a0c60SPablo Neira Ayuso 				  struct nft_object *obj)
177ed0a0c60SPablo Neira Ayuso {
178ed0a0c60SPablo Neira Ayuso 	struct nft_quota *priv = nft_obj_data(obj);
179ed0a0c60SPablo Neira Ayuso 
180ed0a0c60SPablo Neira Ayuso 	return nft_quota_do_destroy(ctx, priv);
181ed0a0c60SPablo Neira Ayuso }
182ed0a0c60SPablo Neira Ayuso 
183dfc46034SPablo M. Bermudo Garay static struct nft_object_type nft_quota_obj_type;
184dfc46034SPablo M. Bermudo Garay static const struct nft_object_ops nft_quota_obj_ops = {
185dfc46034SPablo M. Bermudo Garay 	.type		= &nft_quota_obj_type,
186173705d9SPablo Neira Ayuso 	.size		= sizeof(struct nft_quota),
187173705d9SPablo Neira Ayuso 	.init		= nft_quota_obj_init,
188ed0a0c60SPablo Neira Ayuso 	.destroy	= nft_quota_obj_destroy,
189173705d9SPablo Neira Ayuso 	.eval		= nft_quota_obj_eval,
190173705d9SPablo Neira Ayuso 	.dump		= nft_quota_obj_dump,
19185936e56SFernando Fernandez Mancera 	.update		= nft_quota_obj_update,
192dfc46034SPablo M. Bermudo Garay };
193dfc46034SPablo M. Bermudo Garay 
194dfc46034SPablo M. Bermudo Garay static struct nft_object_type nft_quota_obj_type __read_mostly = {
195dfc46034SPablo M. Bermudo Garay 	.type		= NFT_OBJECT_QUOTA,
196dfc46034SPablo M. Bermudo Garay 	.ops		= &nft_quota_obj_ops,
197dfc46034SPablo M. Bermudo Garay 	.maxattr	= NFTA_QUOTA_MAX,
198dfc46034SPablo M. Bermudo Garay 	.policy		= nft_quota_policy,
199173705d9SPablo Neira Ayuso 	.owner		= THIS_MODULE,
200173705d9SPablo Neira Ayuso };
201173705d9SPablo Neira Ayuso 
nft_quota_eval(const struct nft_expr * expr,struct nft_regs * regs,const struct nft_pktinfo * pkt)202173705d9SPablo Neira Ayuso static void nft_quota_eval(const struct nft_expr *expr,
203173705d9SPablo Neira Ayuso 			   struct nft_regs *regs,
204173705d9SPablo Neira Ayuso 			   const struct nft_pktinfo *pkt)
205173705d9SPablo Neira Ayuso {
206173705d9SPablo Neira Ayuso 	struct nft_quota *priv = nft_expr_priv(expr);
207173705d9SPablo Neira Ayuso 
208173705d9SPablo Neira Ayuso 	nft_quota_do_eval(priv, regs, pkt);
209173705d9SPablo Neira Ayuso }
210173705d9SPablo Neira Ayuso 
nft_quota_init(const struct nft_ctx * ctx,const struct nft_expr * expr,const struct nlattr * const tb[])211173705d9SPablo Neira Ayuso static int nft_quota_init(const struct nft_ctx *ctx,
212173705d9SPablo Neira Ayuso 			  const struct nft_expr *expr,
213173705d9SPablo Neira Ayuso 			  const struct nlattr * const tb[])
214173705d9SPablo Neira Ayuso {
215173705d9SPablo Neira Ayuso 	struct nft_quota *priv = nft_expr_priv(expr);
216173705d9SPablo Neira Ayuso 
217173705d9SPablo Neira Ayuso 	return nft_quota_do_init(tb, priv);
218173705d9SPablo Neira Ayuso }
219173705d9SPablo Neira Ayuso 
nft_quota_dump(struct sk_buff * skb,const struct nft_expr * expr,bool reset)2207d34aa3eSPhil Sutter static int nft_quota_dump(struct sk_buff *skb,
2217d34aa3eSPhil Sutter 			  const struct nft_expr *expr, bool reset)
222173705d9SPablo Neira Ayuso {
22343da04a5SPablo Neira Ayuso 	struct nft_quota *priv = nft_expr_priv(expr);
224173705d9SPablo Neira Ayuso 
2258daa8fdeSPhil Sutter 	return nft_quota_do_dump(skb, priv, reset);
226173705d9SPablo Neira Ayuso }
227173705d9SPablo Neira Ayuso 
nft_quota_destroy(const struct nft_ctx * ctx,const struct nft_expr * expr)228ed0a0c60SPablo Neira Ayuso static void nft_quota_destroy(const struct nft_ctx *ctx,
229ed0a0c60SPablo Neira Ayuso 			      const struct nft_expr *expr)
230ed0a0c60SPablo Neira Ayuso {
231ed0a0c60SPablo Neira Ayuso 	struct nft_quota *priv = nft_expr_priv(expr);
232ed0a0c60SPablo Neira Ayuso 
233ed0a0c60SPablo Neira Ayuso 	return nft_quota_do_destroy(ctx, priv);
234ed0a0c60SPablo Neira Ayuso }
235ed0a0c60SPablo Neira Ayuso 
nft_quota_clone(struct nft_expr * dst,const struct nft_expr * src)236ed0a0c60SPablo Neira Ayuso static int nft_quota_clone(struct nft_expr *dst, const struct nft_expr *src)
237ed0a0c60SPablo Neira Ayuso {
238ed0a0c60SPablo Neira Ayuso 	struct nft_quota *priv_dst = nft_expr_priv(dst);
239*aabef97aSPablo Neira Ayuso 	struct nft_quota *priv_src = nft_expr_priv(src);
240*aabef97aSPablo Neira Ayuso 
241*aabef97aSPablo Neira Ayuso 	priv_dst->quota = priv_src->quota;
242*aabef97aSPablo Neira Ayuso 	priv_dst->flags = priv_src->flags;
243ed0a0c60SPablo Neira Ayuso 
244ed0a0c60SPablo Neira Ayuso 	priv_dst->consumed = kmalloc(sizeof(*priv_dst->consumed), GFP_ATOMIC);
24551edb2ffSPablo Neira Ayuso 	if (!priv_dst->consumed)
246ed0a0c60SPablo Neira Ayuso 		return -ENOMEM;
247ed0a0c60SPablo Neira Ayuso 
248*aabef97aSPablo Neira Ayuso 	*priv_dst->consumed = *priv_src->consumed;
249ed0a0c60SPablo Neira Ayuso 
250ed0a0c60SPablo Neira Ayuso 	return 0;
251ed0a0c60SPablo Neira Ayuso }
252ed0a0c60SPablo Neira Ayuso 
2533d2f30a1SPablo Neira Ayuso static struct nft_expr_type nft_quota_type;
2543d2f30a1SPablo Neira Ayuso static const struct nft_expr_ops nft_quota_ops = {
2553d2f30a1SPablo Neira Ayuso 	.type		= &nft_quota_type,
2563d2f30a1SPablo Neira Ayuso 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_quota)),
2573d2f30a1SPablo Neira Ayuso 	.eval		= nft_quota_eval,
2583d2f30a1SPablo Neira Ayuso 	.init		= nft_quota_init,
259ed0a0c60SPablo Neira Ayuso 	.destroy	= nft_quota_destroy,
260ed0a0c60SPablo Neira Ayuso 	.clone		= nft_quota_clone,
2613d2f30a1SPablo Neira Ayuso 	.dump		= nft_quota_dump,
262b2d30654SPablo Neira Ayuso 	.reduce		= NFT_REDUCE_READONLY,
2633d2f30a1SPablo Neira Ayuso };
2643d2f30a1SPablo Neira Ayuso 
2653d2f30a1SPablo Neira Ayuso static struct nft_expr_type nft_quota_type __read_mostly = {
2663d2f30a1SPablo Neira Ayuso 	.name		= "quota",
2673d2f30a1SPablo Neira Ayuso 	.ops		= &nft_quota_ops,
2683d2f30a1SPablo Neira Ayuso 	.policy		= nft_quota_policy,
2693d2f30a1SPablo Neira Ayuso 	.maxattr	= NFTA_QUOTA_MAX,
2703d2f30a1SPablo Neira Ayuso 	.flags		= NFT_EXPR_STATEFUL,
2713d2f30a1SPablo Neira Ayuso 	.owner		= THIS_MODULE,
2723d2f30a1SPablo Neira Ayuso };
2733d2f30a1SPablo Neira Ayuso 
nft_quota_module_init(void)2743d2f30a1SPablo Neira Ayuso static int __init nft_quota_module_init(void)
2753d2f30a1SPablo Neira Ayuso {
276173705d9SPablo Neira Ayuso 	int err;
277173705d9SPablo Neira Ayuso 
278dfc46034SPablo M. Bermudo Garay 	err = nft_register_obj(&nft_quota_obj_type);
279173705d9SPablo Neira Ayuso 	if (err < 0)
280173705d9SPablo Neira Ayuso 		return err;
281173705d9SPablo Neira Ayuso 
282173705d9SPablo Neira Ayuso 	err = nft_register_expr(&nft_quota_type);
283173705d9SPablo Neira Ayuso 	if (err < 0)
284173705d9SPablo Neira Ayuso 		goto err1;
285173705d9SPablo Neira Ayuso 
286173705d9SPablo Neira Ayuso 	return 0;
287173705d9SPablo Neira Ayuso err1:
288dfc46034SPablo M. Bermudo Garay 	nft_unregister_obj(&nft_quota_obj_type);
289173705d9SPablo Neira Ayuso 	return err;
2903d2f30a1SPablo Neira Ayuso }
2913d2f30a1SPablo Neira Ayuso 
nft_quota_module_exit(void)2923d2f30a1SPablo Neira Ayuso static void __exit nft_quota_module_exit(void)
2933d2f30a1SPablo Neira Ayuso {
2943d2f30a1SPablo Neira Ayuso 	nft_unregister_expr(&nft_quota_type);
295dfc46034SPablo M. Bermudo Garay 	nft_unregister_obj(&nft_quota_obj_type);
2963d2f30a1SPablo Neira Ayuso }
2973d2f30a1SPablo Neira Ayuso 
2983d2f30a1SPablo Neira Ayuso module_init(nft_quota_module_init);
2993d2f30a1SPablo Neira Ayuso module_exit(nft_quota_module_exit);
3003d2f30a1SPablo Neira Ayuso 
3013d2f30a1SPablo Neira Ayuso MODULE_LICENSE("GPL");
3023d2f30a1SPablo Neira Ayuso MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
3033d2f30a1SPablo Neira Ayuso MODULE_ALIAS_NFT_EXPR("quota");
304173705d9SPablo Neira Ayuso MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_QUOTA);
3054cacc395SRob Gill MODULE_DESCRIPTION("Netfilter nftables quota module");
306