150c164a8SPatrick McHardy /* 250c164a8SPatrick McHardy * (C) 2007 Patrick McHardy <kaber@trash.net> 350c164a8SPatrick McHardy * 450c164a8SPatrick McHardy * This program is free software; you can redistribute it and/or modify 550c164a8SPatrick McHardy * it under the terms of the GNU General Public License version 2 as 650c164a8SPatrick McHardy * published by the Free Software Foundation. 750c164a8SPatrick McHardy */ 850c164a8SPatrick McHardy #include <linux/module.h> 950c164a8SPatrick McHardy #include <linux/skbuff.h> 1050c164a8SPatrick McHardy #include <linux/gen_stats.h> 1150c164a8SPatrick McHardy 1250c164a8SPatrick McHardy #include <linux/netfilter/x_tables.h> 1350c164a8SPatrick McHardy #include <linux/netfilter/xt_rateest.h> 1450c164a8SPatrick McHardy #include <net/netfilter/xt_rateest.h> 1550c164a8SPatrick McHardy 1650c164a8SPatrick McHardy 17f7108a20SJan Engelhardt static bool 1862fc8051SJan Engelhardt xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) 1950c164a8SPatrick McHardy { 20f7108a20SJan Engelhardt const struct xt_rateest_match_info *info = par->matchinfo; 211c0d32fdSEric Dumazet struct gnet_stats_rate_est64 sample = {0}; 2250c164a8SPatrick McHardy u_int32_t bps1, bps2, pps1, pps2; 2350c164a8SPatrick McHardy bool ret = true; 2450c164a8SPatrick McHardy 251c0d32fdSEric Dumazet gen_estimator_read(&info->est1->rate_est, &sample); 261c0d32fdSEric Dumazet 2750c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_DELTA) { 281c0d32fdSEric Dumazet bps1 = info->bps1 >= sample.bps ? info->bps1 - sample.bps : 0; 291c0d32fdSEric Dumazet pps1 = info->pps1 >= sample.pps ? info->pps1 - sample.pps : 0; 3050c164a8SPatrick McHardy } else { 311c0d32fdSEric Dumazet bps1 = sample.bps; 321c0d32fdSEric Dumazet pps1 = sample.pps; 3350c164a8SPatrick McHardy } 3450c164a8SPatrick McHardy 3550c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_ABS) { 3650c164a8SPatrick McHardy bps2 = info->bps2; 3750c164a8SPatrick McHardy pps2 = info->pps2; 3850c164a8SPatrick McHardy } else { 391c0d32fdSEric Dumazet gen_estimator_read(&info->est2->rate_est, &sample); 401c0d32fdSEric Dumazet 4150c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_DELTA) { 421c0d32fdSEric Dumazet bps2 = info->bps2 >= sample.bps ? info->bps2 - sample.bps : 0; 431c0d32fdSEric Dumazet pps2 = info->pps2 >= sample.pps ? info->pps2 - sample.pps : 0; 4450c164a8SPatrick McHardy } else { 451c0d32fdSEric Dumazet bps2 = sample.bps; 461c0d32fdSEric Dumazet pps2 = sample.pps; 4750c164a8SPatrick McHardy } 4850c164a8SPatrick McHardy } 4950c164a8SPatrick McHardy 5050c164a8SPatrick McHardy switch (info->mode) { 5150c164a8SPatrick McHardy case XT_RATEEST_MATCH_LT: 5250c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_BPS) 5350c164a8SPatrick McHardy ret &= bps1 < bps2; 5450c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_PPS) 5550c164a8SPatrick McHardy ret &= pps1 < pps2; 5650c164a8SPatrick McHardy break; 5750c164a8SPatrick McHardy case XT_RATEEST_MATCH_GT: 5850c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_BPS) 5950c164a8SPatrick McHardy ret &= bps1 > bps2; 6050c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_PPS) 6150c164a8SPatrick McHardy ret &= pps1 > pps2; 6250c164a8SPatrick McHardy break; 6350c164a8SPatrick McHardy case XT_RATEEST_MATCH_EQ: 6450c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_BPS) 6550c164a8SPatrick McHardy ret &= bps1 == bps2; 6650c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_PPS) 674d900f9dSPatrick McHardy ret &= pps1 == pps2; 6850c164a8SPatrick McHardy break; 6950c164a8SPatrick McHardy } 7050c164a8SPatrick McHardy 7150c164a8SPatrick McHardy ret ^= info->flags & XT_RATEEST_MATCH_INVERT ? true : false; 7250c164a8SPatrick McHardy return ret; 7350c164a8SPatrick McHardy } 7450c164a8SPatrick McHardy 75b0f38452SJan Engelhardt static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) 7650c164a8SPatrick McHardy { 779b4fce7aSJan Engelhardt struct xt_rateest_match_info *info = par->matchinfo; 7850c164a8SPatrick McHardy struct xt_rateest *est1, *est2; 7900fe1ae9SEric Dumazet int ret = -EINVAL; 8050c164a8SPatrick McHardy 8150c164a8SPatrick McHardy if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | 8250c164a8SPatrick McHardy XT_RATEEST_MATCH_REL)) != 1) 8350c164a8SPatrick McHardy goto err1; 8450c164a8SPatrick McHardy 8550c164a8SPatrick McHardy if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS))) 8650c164a8SPatrick McHardy goto err1; 8750c164a8SPatrick McHardy 8850c164a8SPatrick McHardy switch (info->mode) { 8950c164a8SPatrick McHardy case XT_RATEEST_MATCH_EQ: 9050c164a8SPatrick McHardy case XT_RATEEST_MATCH_LT: 9150c164a8SPatrick McHardy case XT_RATEEST_MATCH_GT: 9250c164a8SPatrick McHardy break; 9350c164a8SPatrick McHardy default: 9450c164a8SPatrick McHardy goto err1; 9550c164a8SPatrick McHardy } 9650c164a8SPatrick McHardy 974a5a5c73SJan Engelhardt ret = -ENOENT; 9850c164a8SPatrick McHardy est1 = xt_rateest_lookup(info->name1); 9950c164a8SPatrick McHardy if (!est1) 10050c164a8SPatrick McHardy goto err1; 10150c164a8SPatrick McHardy 10200fe1ae9SEric Dumazet est2 = NULL; 10350c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_REL) { 10450c164a8SPatrick McHardy est2 = xt_rateest_lookup(info->name2); 10550c164a8SPatrick McHardy if (!est2) 10650c164a8SPatrick McHardy goto err2; 10700fe1ae9SEric Dumazet } 10850c164a8SPatrick McHardy 10950c164a8SPatrick McHardy info->est1 = est1; 11050c164a8SPatrick McHardy info->est2 = est2; 111bd414ee6SJan Engelhardt return 0; 11250c164a8SPatrick McHardy 11350c164a8SPatrick McHardy err2: 11450c164a8SPatrick McHardy xt_rateest_put(est1); 11550c164a8SPatrick McHardy err1: 11600fe1ae9SEric Dumazet return ret; 11750c164a8SPatrick McHardy } 11850c164a8SPatrick McHardy 1196be3d859SJan Engelhardt static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par) 12050c164a8SPatrick McHardy { 1216be3d859SJan Engelhardt struct xt_rateest_match_info *info = par->matchinfo; 12250c164a8SPatrick McHardy 12350c164a8SPatrick McHardy xt_rateest_put(info->est1); 12450c164a8SPatrick McHardy if (info->est2) 12550c164a8SPatrick McHardy xt_rateest_put(info->est2); 12650c164a8SPatrick McHardy } 12750c164a8SPatrick McHardy 12855b69e91SJan Engelhardt static struct xt_match xt_rateest_mt_reg __read_mostly = { 12950c164a8SPatrick McHardy .name = "rateest", 13055b69e91SJan Engelhardt .revision = 0, 13155b69e91SJan Engelhardt .family = NFPROTO_UNSPEC, 13250c164a8SPatrick McHardy .match = xt_rateest_mt, 13350c164a8SPatrick McHardy .checkentry = xt_rateest_mt_checkentry, 13450c164a8SPatrick McHardy .destroy = xt_rateest_mt_destroy, 13550c164a8SPatrick McHardy .matchsize = sizeof(struct xt_rateest_match_info), 136ec231890SWillem de Bruijn .usersize = offsetof(struct xt_rateest_match_info, est1), 13750c164a8SPatrick McHardy .me = THIS_MODULE, 13850c164a8SPatrick McHardy }; 13950c164a8SPatrick McHardy 14050c164a8SPatrick McHardy static int __init xt_rateest_mt_init(void) 14150c164a8SPatrick McHardy { 14255b69e91SJan Engelhardt return xt_register_match(&xt_rateest_mt_reg); 14350c164a8SPatrick McHardy } 14450c164a8SPatrick McHardy 14550c164a8SPatrick McHardy static void __exit xt_rateest_mt_fini(void) 14650c164a8SPatrick McHardy { 14755b69e91SJan Engelhardt xt_unregister_match(&xt_rateest_mt_reg); 14850c164a8SPatrick McHardy } 14950c164a8SPatrick McHardy 15050c164a8SPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 15150c164a8SPatrick McHardy MODULE_LICENSE("GPL"); 15250c164a8SPatrick McHardy MODULE_DESCRIPTION("xtables rate estimator match"); 15350c164a8SPatrick McHardy MODULE_ALIAS("ipt_rateest"); 15450c164a8SPatrick McHardy MODULE_ALIAS("ip6t_rateest"); 15550c164a8SPatrick McHardy module_init(xt_rateest_mt_init); 15650c164a8SPatrick McHardy module_exit(xt_rateest_mt_fini); 157