Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
0004  *
0005  * Development of this code funded by Astaro AG (http://www.astaro.com/)
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/init.h>
0010 #include <linux/module.h>
0011 #include <linux/spinlock.h>
0012 #include <linux/netlink.h>
0013 #include <linux/netfilter.h>
0014 #include <linux/netfilter/nf_tables.h>
0015 #include <net/netfilter/nf_tables.h>
0016 
0017 struct nft_limit {
0018     spinlock_t  lock;
0019     u64     last;
0020     u64     tokens;
0021 };
0022 
0023 struct nft_limit_priv {
0024     struct nft_limit *limit;
0025     u64     tokens_max;
0026     u64     rate;
0027     u64     nsecs;
0028     u32     burst;
0029     bool        invert;
0030 };
0031 
0032 static inline bool nft_limit_eval(struct nft_limit_priv *priv, u64 cost)
0033 {
0034     u64 now, tokens;
0035     s64 delta;
0036 
0037     spin_lock_bh(&priv->limit->lock);
0038     now = ktime_get_ns();
0039     tokens = priv->limit->tokens + now - priv->limit->last;
0040     if (tokens > priv->tokens_max)
0041         tokens = priv->tokens_max;
0042 
0043     priv->limit->last = now;
0044     delta = tokens - cost;
0045     if (delta >= 0) {
0046         priv->limit->tokens = delta;
0047         spin_unlock_bh(&priv->limit->lock);
0048         return priv->invert;
0049     }
0050     priv->limit->tokens = tokens;
0051     spin_unlock_bh(&priv->limit->lock);
0052     return !priv->invert;
0053 }
0054 
0055 /* Use same default as in iptables. */
0056 #define NFT_LIMIT_PKT_BURST_DEFAULT 5
0057 
0058 static int nft_limit_init(struct nft_limit_priv *priv,
0059               const struct nlattr * const tb[], bool pkts)
0060 {
0061     u64 unit, tokens;
0062 
0063     if (tb[NFTA_LIMIT_RATE] == NULL ||
0064         tb[NFTA_LIMIT_UNIT] == NULL)
0065         return -EINVAL;
0066 
0067     priv->rate = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_RATE]));
0068     unit = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_UNIT]));
0069     priv->nsecs = unit * NSEC_PER_SEC;
0070     if (priv->rate == 0 || priv->nsecs < unit)
0071         return -EOVERFLOW;
0072 
0073     if (tb[NFTA_LIMIT_BURST])
0074         priv->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST]));
0075 
0076     if (pkts && priv->burst == 0)
0077         priv->burst = NFT_LIMIT_PKT_BURST_DEFAULT;
0078 
0079     if (priv->rate + priv->burst < priv->rate)
0080         return -EOVERFLOW;
0081 
0082     if (pkts) {
0083         tokens = div64_u64(priv->nsecs, priv->rate) * priv->burst;
0084     } else {
0085         /* The token bucket size limits the number of tokens can be
0086          * accumulated. tokens_max specifies the bucket size.
0087          * tokens_max = unit * (rate + burst) / rate.
0088          */
0089         tokens = div64_u64(priv->nsecs * (priv->rate + priv->burst),
0090                  priv->rate);
0091     }
0092 
0093     priv->limit = kmalloc(sizeof(*priv->limit), GFP_KERNEL_ACCOUNT);
0094     if (!priv->limit)
0095         return -ENOMEM;
0096 
0097     priv->limit->tokens = tokens;
0098     priv->tokens_max = priv->limit->tokens;
0099 
0100     if (tb[NFTA_LIMIT_FLAGS]) {
0101         u32 flags = ntohl(nla_get_be32(tb[NFTA_LIMIT_FLAGS]));
0102 
0103         if (flags & NFT_LIMIT_F_INV)
0104             priv->invert = true;
0105     }
0106     priv->limit->last = ktime_get_ns();
0107     spin_lock_init(&priv->limit->lock);
0108 
0109     return 0;
0110 }
0111 
0112 static int nft_limit_dump(struct sk_buff *skb, const struct nft_limit_priv *priv,
0113               enum nft_limit_type type)
0114 {
0115     u32 flags = priv->invert ? NFT_LIMIT_F_INV : 0;
0116     u64 secs = div_u64(priv->nsecs, NSEC_PER_SEC);
0117 
0118     if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(priv->rate),
0119              NFTA_LIMIT_PAD) ||
0120         nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(secs),
0121              NFTA_LIMIT_PAD) ||
0122         nla_put_be32(skb, NFTA_LIMIT_BURST, htonl(priv->burst)) ||
0123         nla_put_be32(skb, NFTA_LIMIT_TYPE, htonl(type)) ||
0124         nla_put_be32(skb, NFTA_LIMIT_FLAGS, htonl(flags)))
0125         goto nla_put_failure;
0126     return 0;
0127 
0128 nla_put_failure:
0129     return -1;
0130 }
0131 
0132 static void nft_limit_destroy(const struct nft_ctx *ctx,
0133                   const struct nft_limit_priv *priv)
0134 {
0135     kfree(priv->limit);
0136 }
0137 
0138 static int nft_limit_clone(struct nft_limit_priv *priv_dst,
0139                const struct nft_limit_priv *priv_src)
0140 {
0141     priv_dst->tokens_max = priv_src->tokens_max;
0142     priv_dst->rate = priv_src->rate;
0143     priv_dst->nsecs = priv_src->nsecs;
0144     priv_dst->burst = priv_src->burst;
0145     priv_dst->invert = priv_src->invert;
0146 
0147     priv_dst->limit = kmalloc(sizeof(*priv_dst->limit), GFP_ATOMIC);
0148     if (!priv_dst->limit)
0149         return -ENOMEM;
0150 
0151     spin_lock_init(&priv_dst->limit->lock);
0152     priv_dst->limit->tokens = priv_src->tokens_max;
0153     priv_dst->limit->last = ktime_get_ns();
0154 
0155     return 0;
0156 }
0157 
0158 struct nft_limit_priv_pkts {
0159     struct nft_limit_priv   limit;
0160     u64         cost;
0161 };
0162 
0163 static void nft_limit_pkts_eval(const struct nft_expr *expr,
0164                 struct nft_regs *regs,
0165                 const struct nft_pktinfo *pkt)
0166 {
0167     struct nft_limit_priv_pkts *priv = nft_expr_priv(expr);
0168 
0169     if (nft_limit_eval(&priv->limit, priv->cost))
0170         regs->verdict.code = NFT_BREAK;
0171 }
0172 
0173 static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = {
0174     [NFTA_LIMIT_RATE]   = { .type = NLA_U64 },
0175     [NFTA_LIMIT_UNIT]   = { .type = NLA_U64 },
0176     [NFTA_LIMIT_BURST]  = { .type = NLA_U32 },
0177     [NFTA_LIMIT_TYPE]   = { .type = NLA_U32 },
0178     [NFTA_LIMIT_FLAGS]  = { .type = NLA_U32 },
0179 };
0180 
0181 static int nft_limit_pkts_init(const struct nft_ctx *ctx,
0182                    const struct nft_expr *expr,
0183                    const struct nlattr * const tb[])
0184 {
0185     struct nft_limit_priv_pkts *priv = nft_expr_priv(expr);
0186     int err;
0187 
0188     err = nft_limit_init(&priv->limit, tb, true);
0189     if (err < 0)
0190         return err;
0191 
0192     priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate);
0193     return 0;
0194 }
0195 
0196 static int nft_limit_pkts_dump(struct sk_buff *skb, const struct nft_expr *expr)
0197 {
0198     const struct nft_limit_priv_pkts *priv = nft_expr_priv(expr);
0199 
0200     return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS);
0201 }
0202 
0203 static void nft_limit_pkts_destroy(const struct nft_ctx *ctx,
0204                    const struct nft_expr *expr)
0205 {
0206     const struct nft_limit_priv_pkts *priv = nft_expr_priv(expr);
0207 
0208     nft_limit_destroy(ctx, &priv->limit);
0209 }
0210 
0211 static int nft_limit_pkts_clone(struct nft_expr *dst, const struct nft_expr *src)
0212 {
0213     struct nft_limit_priv_pkts *priv_dst = nft_expr_priv(dst);
0214     struct nft_limit_priv_pkts *priv_src = nft_expr_priv(src);
0215 
0216     priv_dst->cost = priv_src->cost;
0217 
0218     return nft_limit_clone(&priv_dst->limit, &priv_src->limit);
0219 }
0220 
0221 static struct nft_expr_type nft_limit_type;
0222 static const struct nft_expr_ops nft_limit_pkts_ops = {
0223     .type       = &nft_limit_type,
0224     .size       = NFT_EXPR_SIZE(sizeof(struct nft_limit_priv_pkts)),
0225     .eval       = nft_limit_pkts_eval,
0226     .init       = nft_limit_pkts_init,
0227     .destroy    = nft_limit_pkts_destroy,
0228     .clone      = nft_limit_pkts_clone,
0229     .dump       = nft_limit_pkts_dump,
0230     .reduce     = NFT_REDUCE_READONLY,
0231 };
0232 
0233 static void nft_limit_bytes_eval(const struct nft_expr *expr,
0234                  struct nft_regs *regs,
0235                  const struct nft_pktinfo *pkt)
0236 {
0237     struct nft_limit_priv *priv = nft_expr_priv(expr);
0238     u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate);
0239 
0240     if (nft_limit_eval(priv, cost))
0241         regs->verdict.code = NFT_BREAK;
0242 }
0243 
0244 static int nft_limit_bytes_init(const struct nft_ctx *ctx,
0245                 const struct nft_expr *expr,
0246                 const struct nlattr * const tb[])
0247 {
0248     struct nft_limit_priv *priv = nft_expr_priv(expr);
0249 
0250     return nft_limit_init(priv, tb, false);
0251 }
0252 
0253 static int nft_limit_bytes_dump(struct sk_buff *skb,
0254                 const struct nft_expr *expr)
0255 {
0256     const struct nft_limit_priv *priv = nft_expr_priv(expr);
0257 
0258     return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES);
0259 }
0260 
0261 static void nft_limit_bytes_destroy(const struct nft_ctx *ctx,
0262                     const struct nft_expr *expr)
0263 {
0264     const struct nft_limit_priv *priv = nft_expr_priv(expr);
0265 
0266     nft_limit_destroy(ctx, priv);
0267 }
0268 
0269 static int nft_limit_bytes_clone(struct nft_expr *dst, const struct nft_expr *src)
0270 {
0271     struct nft_limit_priv *priv_dst = nft_expr_priv(dst);
0272     struct nft_limit_priv *priv_src = nft_expr_priv(src);
0273 
0274     return nft_limit_clone(priv_dst, priv_src);
0275 }
0276 
0277 static const struct nft_expr_ops nft_limit_bytes_ops = {
0278     .type       = &nft_limit_type,
0279     .size       = NFT_EXPR_SIZE(sizeof(struct nft_limit_priv)),
0280     .eval       = nft_limit_bytes_eval,
0281     .init       = nft_limit_bytes_init,
0282     .dump       = nft_limit_bytes_dump,
0283     .clone      = nft_limit_bytes_clone,
0284     .destroy    = nft_limit_bytes_destroy,
0285     .reduce     = NFT_REDUCE_READONLY,
0286 };
0287 
0288 static const struct nft_expr_ops *
0289 nft_limit_select_ops(const struct nft_ctx *ctx,
0290              const struct nlattr * const tb[])
0291 {
0292     if (tb[NFTA_LIMIT_TYPE] == NULL)
0293         return &nft_limit_pkts_ops;
0294 
0295     switch (ntohl(nla_get_be32(tb[NFTA_LIMIT_TYPE]))) {
0296     case NFT_LIMIT_PKTS:
0297         return &nft_limit_pkts_ops;
0298     case NFT_LIMIT_PKT_BYTES:
0299         return &nft_limit_bytes_ops;
0300     }
0301     return ERR_PTR(-EOPNOTSUPP);
0302 }
0303 
0304 static struct nft_expr_type nft_limit_type __read_mostly = {
0305     .name       = "limit",
0306     .select_ops = nft_limit_select_ops,
0307     .policy     = nft_limit_policy,
0308     .maxattr    = NFTA_LIMIT_MAX,
0309     .flags      = NFT_EXPR_STATEFUL,
0310     .owner      = THIS_MODULE,
0311 };
0312 
0313 static void nft_limit_obj_pkts_eval(struct nft_object *obj,
0314                     struct nft_regs *regs,
0315                     const struct nft_pktinfo *pkt)
0316 {
0317     struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
0318 
0319     if (nft_limit_eval(&priv->limit, priv->cost))
0320         regs->verdict.code = NFT_BREAK;
0321 }
0322 
0323 static int nft_limit_obj_pkts_init(const struct nft_ctx *ctx,
0324                    const struct nlattr * const tb[],
0325                    struct nft_object *obj)
0326 {
0327     struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
0328     int err;
0329 
0330     err = nft_limit_init(&priv->limit, tb, true);
0331     if (err < 0)
0332         return err;
0333 
0334     priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate);
0335     return 0;
0336 }
0337 
0338 static int nft_limit_obj_pkts_dump(struct sk_buff *skb,
0339                    struct nft_object *obj,
0340                    bool reset)
0341 {
0342     const struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
0343 
0344     return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS);
0345 }
0346 
0347 static void nft_limit_obj_pkts_destroy(const struct nft_ctx *ctx,
0348                        struct nft_object *obj)
0349 {
0350     struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
0351 
0352     nft_limit_destroy(ctx, &priv->limit);
0353 }
0354 
0355 static struct nft_object_type nft_limit_obj_type;
0356 static const struct nft_object_ops nft_limit_obj_pkts_ops = {
0357     .type       = &nft_limit_obj_type,
0358     .size       = NFT_EXPR_SIZE(sizeof(struct nft_limit_priv_pkts)),
0359     .init       = nft_limit_obj_pkts_init,
0360     .destroy    = nft_limit_obj_pkts_destroy,
0361     .eval       = nft_limit_obj_pkts_eval,
0362     .dump       = nft_limit_obj_pkts_dump,
0363 };
0364 
0365 static void nft_limit_obj_bytes_eval(struct nft_object *obj,
0366                      struct nft_regs *regs,
0367                      const struct nft_pktinfo *pkt)
0368 {
0369     struct nft_limit_priv *priv = nft_obj_data(obj);
0370     u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate);
0371 
0372     if (nft_limit_eval(priv, cost))
0373         regs->verdict.code = NFT_BREAK;
0374 }
0375 
0376 static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx,
0377                     const struct nlattr * const tb[],
0378                     struct nft_object *obj)
0379 {
0380     struct nft_limit_priv *priv = nft_obj_data(obj);
0381 
0382     return nft_limit_init(priv, tb, false);
0383 }
0384 
0385 static int nft_limit_obj_bytes_dump(struct sk_buff *skb,
0386                     struct nft_object *obj,
0387                     bool reset)
0388 {
0389     const struct nft_limit_priv *priv = nft_obj_data(obj);
0390 
0391     return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES);
0392 }
0393 
0394 static void nft_limit_obj_bytes_destroy(const struct nft_ctx *ctx,
0395                     struct nft_object *obj)
0396 {
0397     struct nft_limit_priv *priv = nft_obj_data(obj);
0398 
0399     nft_limit_destroy(ctx, priv);
0400 }
0401 
0402 static struct nft_object_type nft_limit_obj_type;
0403 static const struct nft_object_ops nft_limit_obj_bytes_ops = {
0404     .type       = &nft_limit_obj_type,
0405     .size       = sizeof(struct nft_limit_priv),
0406     .init       = nft_limit_obj_bytes_init,
0407     .destroy    = nft_limit_obj_bytes_destroy,
0408     .eval       = nft_limit_obj_bytes_eval,
0409     .dump       = nft_limit_obj_bytes_dump,
0410 };
0411 
0412 static const struct nft_object_ops *
0413 nft_limit_obj_select_ops(const struct nft_ctx *ctx,
0414              const struct nlattr * const tb[])
0415 {
0416     if (!tb[NFTA_LIMIT_TYPE])
0417         return &nft_limit_obj_pkts_ops;
0418 
0419     switch (ntohl(nla_get_be32(tb[NFTA_LIMIT_TYPE]))) {
0420     case NFT_LIMIT_PKTS:
0421         return &nft_limit_obj_pkts_ops;
0422     case NFT_LIMIT_PKT_BYTES:
0423         return &nft_limit_obj_bytes_ops;
0424     }
0425     return ERR_PTR(-EOPNOTSUPP);
0426 }
0427 
0428 static struct nft_object_type nft_limit_obj_type __read_mostly = {
0429     .select_ops = nft_limit_obj_select_ops,
0430     .type       = NFT_OBJECT_LIMIT,
0431     .maxattr    = NFTA_LIMIT_MAX,
0432     .policy     = nft_limit_policy,
0433     .owner      = THIS_MODULE,
0434 };
0435 
0436 static int __init nft_limit_module_init(void)
0437 {
0438     int err;
0439 
0440     err = nft_register_obj(&nft_limit_obj_type);
0441     if (err < 0)
0442         return err;
0443 
0444     err = nft_register_expr(&nft_limit_type);
0445     if (err < 0)
0446         goto err1;
0447 
0448     return 0;
0449 err1:
0450     nft_unregister_obj(&nft_limit_obj_type);
0451     return err;
0452 }
0453 
0454 static void __exit nft_limit_module_exit(void)
0455 {
0456     nft_unregister_expr(&nft_limit_type);
0457     nft_unregister_obj(&nft_limit_obj_type);
0458 }
0459 
0460 module_init(nft_limit_module_init);
0461 module_exit(nft_limit_module_exit);
0462 
0463 MODULE_LICENSE("GPL");
0464 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
0465 MODULE_ALIAS_NFT_EXPR("limit");
0466 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_LIMIT);
0467 MODULE_DESCRIPTION("nftables limit expression support");