1 /* 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> 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 * Development of this code funded by Astaro AG (http://www.astaro.com/) 9 */ 10 11 #include <linux/kernel.h> 12 #include <linux/init.h> 13 #include <linux/module.h> 14 #include <linux/spinlock.h> 15 #include <linux/netlink.h> 16 #include <linux/netfilter.h> 17 #include <linux/netfilter/nf_tables.h> 18 #include <net/netfilter/nf_tables.h> 19 20 struct nft_limit { 21 spinlock_t lock; 22 u64 last; 23 u64 tokens; 24 u64 tokens_max; 25 u64 rate; 26 u64 nsecs; 27 u32 burst; 28 bool invert; 29 }; 30 31 static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost) 32 { 33 u64 now, tokens; 34 s64 delta; 35 36 spin_lock_bh(&limit->lock); 37 now = ktime_get_ns(); 38 tokens = limit->tokens + now - limit->last; 39 if (tokens > limit->tokens_max) 40 tokens = limit->tokens_max; 41 42 limit->last = now; 43 delta = tokens - cost; 44 if (delta >= 0) { 45 limit->tokens = delta; 46 spin_unlock_bh(&limit->lock); 47 return limit->invert; 48 } 49 limit->tokens = tokens; 50 spin_unlock_bh(&limit->lock); 51 return !limit->invert; 52 } 53 54 static int nft_limit_init(struct nft_limit *limit, 55 const struct nlattr * const tb[]) 56 { 57 u64 unit; 58 59 if (tb[NFTA_LIMIT_RATE] == NULL || 60 tb[NFTA_LIMIT_UNIT] == NULL) 61 return -EINVAL; 62 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) 67 return -EOVERFLOW; 68 69 if (tb[NFTA_LIMIT_BURST]) 70 limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST])); 71 else 72 limit->burst = 0; 73 74 if (limit->rate + limit->burst < limit->rate) 75 return -EOVERFLOW; 76 77 /* The token bucket size limits the number of tokens can be 78 * accumulated. tokens_max specifies the bucket size. 79 * tokens_max = unit * (rate + burst) / rate. 80 */ 81 limit->tokens = div_u64(limit->nsecs * (limit->rate + limit->burst), 82 limit->rate); 83 limit->tokens_max = limit->tokens; 84 85 if (tb[NFTA_LIMIT_FLAGS]) { 86 u32 flags = ntohl(nla_get_be32(tb[NFTA_LIMIT_FLAGS])); 87 88 if (flags & NFT_LIMIT_F_INV) 89 limit->invert = true; 90 } 91 limit->last = ktime_get_ns(); 92 spin_lock_init(&limit->lock); 93 94 return 0; 95 } 96 97 static int nft_limit_dump(struct sk_buff *skb, const struct nft_limit *limit, 98 enum nft_limit_type type) 99 { 100 u32 flags = limit->invert ? NFT_LIMIT_F_INV : 0; 101 u64 secs = div_u64(limit->nsecs, NSEC_PER_SEC); 102 103 if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(limit->rate), 104 NFTA_LIMIT_PAD) || 105 nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(secs), 106 NFTA_LIMIT_PAD) || 107 nla_put_be32(skb, NFTA_LIMIT_BURST, htonl(limit->burst)) || 108 nla_put_be32(skb, NFTA_LIMIT_TYPE, htonl(type)) || 109 nla_put_be32(skb, NFTA_LIMIT_FLAGS, htonl(flags))) 110 goto nla_put_failure; 111 return 0; 112 113 nla_put_failure: 114 return -1; 115 } 116 117 struct nft_limit_pkts { 118 struct nft_limit limit; 119 u64 cost; 120 }; 121 122 static void nft_limit_pkts_eval(const struct nft_expr *expr, 123 struct nft_regs *regs, 124 const struct nft_pktinfo *pkt) 125 { 126 struct nft_limit_pkts *priv = nft_expr_priv(expr); 127 128 if (nft_limit_eval(&priv->limit, priv->cost)) 129 regs->verdict.code = NFT_BREAK; 130 } 131 132 static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = { 133 [NFTA_LIMIT_RATE] = { .type = NLA_U64 }, 134 [NFTA_LIMIT_UNIT] = { .type = NLA_U64 }, 135 [NFTA_LIMIT_BURST] = { .type = NLA_U32 }, 136 [NFTA_LIMIT_TYPE] = { .type = NLA_U32 }, 137 [NFTA_LIMIT_FLAGS] = { .type = NLA_U32 }, 138 }; 139 140 static int nft_limit_pkts_init(const struct nft_ctx *ctx, 141 const struct nft_expr *expr, 142 const struct nlattr * const tb[]) 143 { 144 struct nft_limit_pkts *priv = nft_expr_priv(expr); 145 int err; 146 147 err = nft_limit_init(&priv->limit, tb); 148 if (err < 0) 149 return err; 150 151 priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate); 152 return 0; 153 } 154 155 static int nft_limit_pkts_dump(struct sk_buff *skb, const struct nft_expr *expr) 156 { 157 const struct nft_limit_pkts *priv = nft_expr_priv(expr); 158 159 return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS); 160 } 161 162 static struct nft_expr_type nft_limit_type; 163 static const struct nft_expr_ops nft_limit_pkts_ops = { 164 .type = &nft_limit_type, 165 .size = NFT_EXPR_SIZE(sizeof(struct nft_limit_pkts)), 166 .eval = nft_limit_pkts_eval, 167 .init = nft_limit_pkts_init, 168 .dump = nft_limit_pkts_dump, 169 }; 170 171 static void nft_limit_bytes_eval(const struct nft_expr *expr, 172 struct nft_regs *regs, 173 const struct nft_pktinfo *pkt) 174 { 175 struct nft_limit *priv = nft_expr_priv(expr); 176 u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate); 177 178 if (nft_limit_eval(priv, cost)) 179 regs->verdict.code = NFT_BREAK; 180 } 181 182 static int nft_limit_bytes_init(const struct nft_ctx *ctx, 183 const struct nft_expr *expr, 184 const struct nlattr * const tb[]) 185 { 186 struct nft_limit *priv = nft_expr_priv(expr); 187 188 return nft_limit_init(priv, tb); 189 } 190 191 static int nft_limit_bytes_dump(struct sk_buff *skb, 192 const struct nft_expr *expr) 193 { 194 const struct nft_limit *priv = nft_expr_priv(expr); 195 196 return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES); 197 } 198 199 static const struct nft_expr_ops nft_limit_bytes_ops = { 200 .type = &nft_limit_type, 201 .size = NFT_EXPR_SIZE(sizeof(struct nft_limit)), 202 .eval = nft_limit_bytes_eval, 203 .init = nft_limit_bytes_init, 204 .dump = nft_limit_bytes_dump, 205 }; 206 207 static const struct nft_expr_ops * 208 nft_limit_select_ops(const struct nft_ctx *ctx, 209 const struct nlattr * const tb[]) 210 { 211 if (tb[NFTA_LIMIT_TYPE] == NULL) 212 return &nft_limit_pkts_ops; 213 214 switch (ntohl(nla_get_be32(tb[NFTA_LIMIT_TYPE]))) { 215 case NFT_LIMIT_PKTS: 216 return &nft_limit_pkts_ops; 217 case NFT_LIMIT_PKT_BYTES: 218 return &nft_limit_bytes_ops; 219 } 220 return ERR_PTR(-EOPNOTSUPP); 221 } 222 223 static struct nft_expr_type nft_limit_type __read_mostly = { 224 .name = "limit", 225 .select_ops = nft_limit_select_ops, 226 .policy = nft_limit_policy, 227 .maxattr = NFTA_LIMIT_MAX, 228 .flags = NFT_EXPR_STATEFUL, 229 .owner = THIS_MODULE, 230 }; 231 232 static void nft_limit_obj_pkts_eval(struct nft_object *obj, 233 struct nft_regs *regs, 234 const struct nft_pktinfo *pkt) 235 { 236 struct nft_limit_pkts *priv = nft_obj_data(obj); 237 238 if (nft_limit_eval(&priv->limit, priv->cost)) 239 regs->verdict.code = NFT_BREAK; 240 } 241 242 static int nft_limit_obj_pkts_init(const struct nft_ctx *ctx, 243 const struct nlattr * const tb[], 244 struct nft_object *obj) 245 { 246 struct nft_limit_pkts *priv = nft_obj_data(obj); 247 int err; 248 249 err = nft_limit_init(&priv->limit, tb); 250 if (err < 0) 251 return err; 252 253 priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate); 254 return 0; 255 } 256 257 static int nft_limit_obj_pkts_dump(struct sk_buff *skb, 258 struct nft_object *obj, 259 bool reset) 260 { 261 const struct nft_limit_pkts *priv = nft_obj_data(obj); 262 263 return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS); 264 } 265 266 static struct nft_object_type nft_limit_obj_type; 267 static const struct nft_object_ops nft_limit_obj_pkts_ops = { 268 .type = &nft_limit_obj_type, 269 .size = NFT_EXPR_SIZE(sizeof(struct nft_limit_pkts)), 270 .init = nft_limit_obj_pkts_init, 271 .eval = nft_limit_obj_pkts_eval, 272 .dump = nft_limit_obj_pkts_dump, 273 }; 274 275 static void nft_limit_obj_bytes_eval(struct nft_object *obj, 276 struct nft_regs *regs, 277 const struct nft_pktinfo *pkt) 278 { 279 struct nft_limit *priv = nft_obj_data(obj); 280 u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate); 281 282 if (nft_limit_eval(priv, cost)) 283 regs->verdict.code = NFT_BREAK; 284 } 285 286 static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx, 287 const struct nlattr * const tb[], 288 struct nft_object *obj) 289 { 290 struct nft_limit *priv = nft_obj_data(obj); 291 292 return nft_limit_init(priv, tb); 293 } 294 295 static int nft_limit_obj_bytes_dump(struct sk_buff *skb, 296 struct nft_object *obj, 297 bool reset) 298 { 299 const struct nft_limit *priv = nft_obj_data(obj); 300 301 return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES); 302 } 303 304 static struct nft_object_type nft_limit_obj_type; 305 static const struct nft_object_ops nft_limit_obj_bytes_ops = { 306 .type = &nft_limit_obj_type, 307 .size = sizeof(struct nft_limit), 308 .init = nft_limit_obj_bytes_init, 309 .eval = nft_limit_obj_bytes_eval, 310 .dump = nft_limit_obj_bytes_dump, 311 }; 312 313 static const struct nft_object_ops * 314 nft_limit_obj_select_ops(const struct nft_ctx *ctx, 315 const struct nlattr * const tb[]) 316 { 317 if (!tb[NFTA_LIMIT_TYPE]) 318 return &nft_limit_obj_pkts_ops; 319 320 switch (ntohl(nla_get_be32(tb[NFTA_LIMIT_TYPE]))) { 321 case NFT_LIMIT_PKTS: 322 return &nft_limit_obj_pkts_ops; 323 case NFT_LIMIT_PKT_BYTES: 324 return &nft_limit_obj_bytes_ops; 325 } 326 return ERR_PTR(-EOPNOTSUPP); 327 } 328 329 static struct nft_object_type nft_limit_obj_type __read_mostly = { 330 .select_ops = nft_limit_obj_select_ops, 331 .type = NFT_OBJECT_LIMIT, 332 .maxattr = NFTA_LIMIT_MAX, 333 .policy = nft_limit_policy, 334 .owner = THIS_MODULE, 335 }; 336 337 static int __init nft_limit_module_init(void) 338 { 339 int err; 340 341 err = nft_register_obj(&nft_limit_obj_type); 342 if (err < 0) 343 return err; 344 345 err = nft_register_expr(&nft_limit_type); 346 if (err < 0) 347 goto err1; 348 349 return 0; 350 err1: 351 nft_unregister_obj(&nft_limit_obj_type); 352 return err; 353 } 354 355 static void __exit nft_limit_module_exit(void) 356 { 357 nft_unregister_expr(&nft_limit_type); 358 nft_unregister_obj(&nft_limit_obj_type); 359 } 360 361 module_init(nft_limit_module_init); 362 module_exit(nft_limit_module_exit); 363 364 MODULE_LICENSE("GPL"); 365 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 366 MODULE_ALIAS_NFT_EXPR("limit"); 367 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_LIMIT); 368