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