root/net/netfilter/nft_quota.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nft_overquota
  2. nft_quota_invert
  3. nft_quota_do_eval
  4. nft_quota_obj_eval
  5. nft_quota_do_init
  6. nft_quota_obj_init
  7. nft_quota_obj_update
  8. nft_quota_do_dump
  9. nft_quota_obj_dump
  10. nft_quota_eval
  11. nft_quota_init
  12. nft_quota_dump
  13. nft_quota_module_init
  14. nft_quota_module_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
   4  */
   5 
   6 #include <linux/kernel.h>
   7 #include <linux/init.h>
   8 #include <linux/module.h>
   9 #include <linux/atomic.h>
  10 #include <linux/netlink.h>
  11 #include <linux/netfilter.h>
  12 #include <linux/netfilter/nf_tables.h>
  13 #include <net/netfilter/nf_tables.h>
  14 
  15 struct nft_quota {
  16         atomic64_t      quota;
  17         unsigned long   flags;
  18         atomic64_t      consumed;
  19 };
  20 
  21 static inline bool nft_overquota(struct nft_quota *priv,
  22                                  const struct sk_buff *skb)
  23 {
  24         return atomic64_add_return(skb->len, &priv->consumed) >=
  25                atomic64_read(&priv->quota);
  26 }
  27 
  28 static inline bool nft_quota_invert(struct nft_quota *priv)
  29 {
  30         return priv->flags & NFT_QUOTA_F_INV;
  31 }
  32 
  33 static inline void nft_quota_do_eval(struct nft_quota *priv,
  34                                      struct nft_regs *regs,
  35                                      const struct nft_pktinfo *pkt)
  36 {
  37         if (nft_overquota(priv, pkt->skb) ^ nft_quota_invert(priv))
  38                 regs->verdict.code = NFT_BREAK;
  39 }
  40 
  41 static const struct nla_policy nft_quota_policy[NFTA_QUOTA_MAX + 1] = {
  42         [NFTA_QUOTA_BYTES]      = { .type = NLA_U64 },
  43         [NFTA_QUOTA_FLAGS]      = { .type = NLA_U32 },
  44         [NFTA_QUOTA_CONSUMED]   = { .type = NLA_U64 },
  45 };
  46 
  47 #define NFT_QUOTA_DEPLETED_BIT  1       /* From NFT_QUOTA_F_DEPLETED. */
  48 
  49 static void nft_quota_obj_eval(struct nft_object *obj,
  50                                struct nft_regs *regs,
  51                                const struct nft_pktinfo *pkt)
  52 {
  53         struct nft_quota *priv = nft_obj_data(obj);
  54         bool overquota;
  55 
  56         overquota = nft_overquota(priv, pkt->skb);
  57         if (overquota ^ nft_quota_invert(priv))
  58                 regs->verdict.code = NFT_BREAK;
  59 
  60         if (overquota &&
  61             !test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
  62                 nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0,
  63                                NFT_MSG_NEWOBJ, nft_pf(pkt), 0, GFP_ATOMIC);
  64 }
  65 
  66 static int nft_quota_do_init(const struct nlattr * const tb[],
  67                              struct nft_quota *priv)
  68 {
  69         unsigned long flags = 0;
  70         u64 quota, consumed = 0;
  71 
  72         if (!tb[NFTA_QUOTA_BYTES])
  73                 return -EINVAL;
  74 
  75         quota = be64_to_cpu(nla_get_be64(tb[NFTA_QUOTA_BYTES]));
  76         if (quota > S64_MAX)
  77                 return -EOVERFLOW;
  78 
  79         if (tb[NFTA_QUOTA_CONSUMED]) {
  80                 consumed = be64_to_cpu(nla_get_be64(tb[NFTA_QUOTA_CONSUMED]));
  81                 if (consumed > quota)
  82                         return -EINVAL;
  83         }
  84 
  85         if (tb[NFTA_QUOTA_FLAGS]) {
  86                 flags = ntohl(nla_get_be32(tb[NFTA_QUOTA_FLAGS]));
  87                 if (flags & ~NFT_QUOTA_F_INV)
  88                         return -EINVAL;
  89                 if (flags & NFT_QUOTA_F_DEPLETED)
  90                         return -EOPNOTSUPP;
  91         }
  92 
  93         atomic64_set(&priv->quota, quota);
  94         priv->flags = flags;
  95         atomic64_set(&priv->consumed, consumed);
  96 
  97         return 0;
  98 }
  99 
 100 static int nft_quota_obj_init(const struct nft_ctx *ctx,
 101                               const struct nlattr * const tb[],
 102                               struct nft_object *obj)
 103 {
 104         struct nft_quota *priv = nft_obj_data(obj);
 105 
 106         return nft_quota_do_init(tb, priv);
 107 }
 108 
 109 static void nft_quota_obj_update(struct nft_object *obj,
 110                                  struct nft_object *newobj)
 111 {
 112         struct nft_quota *newpriv = nft_obj_data(newobj);
 113         struct nft_quota *priv = nft_obj_data(obj);
 114         u64 newquota;
 115 
 116         newquota = atomic64_read(&newpriv->quota);
 117         atomic64_set(&priv->quota, newquota);
 118         priv->flags = newpriv->flags;
 119 }
 120 
 121 static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
 122                              bool reset)
 123 {
 124         u64 consumed, consumed_cap, quota;
 125         u32 flags = priv->flags;
 126 
 127         /* Since we inconditionally increment consumed quota for each packet
 128          * that we see, don't go over the quota boundary in what we send to
 129          * userspace.
 130          */
 131         consumed = atomic64_read(&priv->consumed);
 132         quota = atomic64_read(&priv->quota);
 133         if (consumed >= quota) {
 134                 consumed_cap = quota;
 135                 flags |= NFT_QUOTA_F_DEPLETED;
 136         } else {
 137                 consumed_cap = consumed;
 138         }
 139 
 140         if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(quota),
 141                          NFTA_QUOTA_PAD) ||
 142             nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap),
 143                          NFTA_QUOTA_PAD) ||
 144             nla_put_be32(skb, NFTA_QUOTA_FLAGS, htonl(flags)))
 145                 goto nla_put_failure;
 146 
 147         if (reset) {
 148                 atomic64_sub(consumed, &priv->consumed);
 149                 clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags);
 150         }
 151         return 0;
 152 
 153 nla_put_failure:
 154         return -1;
 155 }
 156 
 157 static int nft_quota_obj_dump(struct sk_buff *skb, struct nft_object *obj,
 158                               bool reset)
 159 {
 160         struct nft_quota *priv = nft_obj_data(obj);
 161 
 162         return nft_quota_do_dump(skb, priv, reset);
 163 }
 164 
 165 static struct nft_object_type nft_quota_obj_type;
 166 static const struct nft_object_ops nft_quota_obj_ops = {
 167         .type           = &nft_quota_obj_type,
 168         .size           = sizeof(struct nft_quota),
 169         .init           = nft_quota_obj_init,
 170         .eval           = nft_quota_obj_eval,
 171         .dump           = nft_quota_obj_dump,
 172         .update         = nft_quota_obj_update,
 173 };
 174 
 175 static struct nft_object_type nft_quota_obj_type __read_mostly = {
 176         .type           = NFT_OBJECT_QUOTA,
 177         .ops            = &nft_quota_obj_ops,
 178         .maxattr        = NFTA_QUOTA_MAX,
 179         .policy         = nft_quota_policy,
 180         .owner          = THIS_MODULE,
 181 };
 182 
 183 static void nft_quota_eval(const struct nft_expr *expr,
 184                            struct nft_regs *regs,
 185                            const struct nft_pktinfo *pkt)
 186 {
 187         struct nft_quota *priv = nft_expr_priv(expr);
 188 
 189         nft_quota_do_eval(priv, regs, pkt);
 190 }
 191 
 192 static int nft_quota_init(const struct nft_ctx *ctx,
 193                           const struct nft_expr *expr,
 194                           const struct nlattr * const tb[])
 195 {
 196         struct nft_quota *priv = nft_expr_priv(expr);
 197 
 198         return nft_quota_do_init(tb, priv);
 199 }
 200 
 201 static int nft_quota_dump(struct sk_buff *skb, const struct nft_expr *expr)
 202 {
 203         struct nft_quota *priv = nft_expr_priv(expr);
 204 
 205         return nft_quota_do_dump(skb, priv, false);
 206 }
 207 
 208 static struct nft_expr_type nft_quota_type;
 209 static const struct nft_expr_ops nft_quota_ops = {
 210         .type           = &nft_quota_type,
 211         .size           = NFT_EXPR_SIZE(sizeof(struct nft_quota)),
 212         .eval           = nft_quota_eval,
 213         .init           = nft_quota_init,
 214         .dump           = nft_quota_dump,
 215 };
 216 
 217 static struct nft_expr_type nft_quota_type __read_mostly = {
 218         .name           = "quota",
 219         .ops            = &nft_quota_ops,
 220         .policy         = nft_quota_policy,
 221         .maxattr        = NFTA_QUOTA_MAX,
 222         .flags          = NFT_EXPR_STATEFUL,
 223         .owner          = THIS_MODULE,
 224 };
 225 
 226 static int __init nft_quota_module_init(void)
 227 {
 228         int err;
 229 
 230         err = nft_register_obj(&nft_quota_obj_type);
 231         if (err < 0)
 232                 return err;
 233 
 234         err = nft_register_expr(&nft_quota_type);
 235         if (err < 0)
 236                 goto err1;
 237 
 238         return 0;
 239 err1:
 240         nft_unregister_obj(&nft_quota_obj_type);
 241         return err;
 242 }
 243 
 244 static void __exit nft_quota_module_exit(void)
 245 {
 246         nft_unregister_expr(&nft_quota_type);
 247         nft_unregister_obj(&nft_quota_obj_type);
 248 }
 249 
 250 module_init(nft_quota_module_init);
 251 module_exit(nft_quota_module_exit);
 252 
 253 MODULE_LICENSE("GPL");
 254 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
 255 MODULE_ALIAS_NFT_EXPR("quota");
 256 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_QUOTA);

/* [<][>][^][v][top][bottom][index][help] */