Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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