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 18f7108a20SJan Engelhardt xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par) 1950c164a8SPatrick McHardy { 20f7108a20SJan Engelhardt const struct xt_rateest_match_info *info = par->matchinfo; 2150c164a8SPatrick McHardy struct gnet_stats_rate_est *r; 2250c164a8SPatrick McHardy u_int32_t bps1, bps2, pps1, pps2; 2350c164a8SPatrick McHardy bool ret = true; 2450c164a8SPatrick McHardy 2550c164a8SPatrick McHardy spin_lock_bh(&info->est1->lock); 2650c164a8SPatrick McHardy r = &info->est1->rstats; 2750c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_DELTA) { 2850c164a8SPatrick McHardy bps1 = info->bps1 >= r->bps ? info->bps1 - r->bps : 0; 2950c164a8SPatrick McHardy pps1 = info->pps1 >= r->pps ? info->pps1 - r->pps : 0; 3050c164a8SPatrick McHardy } else { 3150c164a8SPatrick McHardy bps1 = r->bps; 3250c164a8SPatrick McHardy pps1 = r->pps; 3350c164a8SPatrick McHardy } 3450c164a8SPatrick McHardy spin_unlock_bh(&info->est1->lock); 3550c164a8SPatrick McHardy 3650c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_ABS) { 3750c164a8SPatrick McHardy bps2 = info->bps2; 3850c164a8SPatrick McHardy pps2 = info->pps2; 3950c164a8SPatrick McHardy } else { 4050c164a8SPatrick McHardy spin_lock_bh(&info->est2->lock); 4150c164a8SPatrick McHardy r = &info->est2->rstats; 4250c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_DELTA) { 4350c164a8SPatrick McHardy bps2 = info->bps2 >= r->bps ? info->bps2 - r->bps : 0; 4450c164a8SPatrick McHardy pps2 = info->pps2 >= r->pps ? info->pps2 - r->pps : 0; 4550c164a8SPatrick McHardy } else { 4650c164a8SPatrick McHardy bps2 = r->bps; 4750c164a8SPatrick McHardy pps2 = r->pps; 4850c164a8SPatrick McHardy } 4950c164a8SPatrick McHardy spin_unlock_bh(&info->est2->lock); 5050c164a8SPatrick McHardy } 5150c164a8SPatrick McHardy 5250c164a8SPatrick McHardy switch (info->mode) { 5350c164a8SPatrick McHardy case XT_RATEEST_MATCH_LT: 5450c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_BPS) 5550c164a8SPatrick McHardy ret &= bps1 < bps2; 5650c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_PPS) 5750c164a8SPatrick McHardy ret &= pps1 < pps2; 5850c164a8SPatrick McHardy break; 5950c164a8SPatrick McHardy case XT_RATEEST_MATCH_GT: 6050c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_BPS) 6150c164a8SPatrick McHardy ret &= bps1 > bps2; 6250c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_PPS) 6350c164a8SPatrick McHardy ret &= pps1 > pps2; 6450c164a8SPatrick McHardy break; 6550c164a8SPatrick McHardy case XT_RATEEST_MATCH_EQ: 6650c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_BPS) 6750c164a8SPatrick McHardy ret &= bps1 == bps2; 6850c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_PPS) 694d900f9dSPatrick McHardy ret &= pps1 == pps2; 7050c164a8SPatrick McHardy break; 7150c164a8SPatrick McHardy } 7250c164a8SPatrick McHardy 7350c164a8SPatrick McHardy ret ^= info->flags & XT_RATEEST_MATCH_INVERT ? true : false; 7450c164a8SPatrick McHardy return ret; 7550c164a8SPatrick McHardy } 7650c164a8SPatrick McHardy 77b0f38452SJan Engelhardt static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) 7850c164a8SPatrick McHardy { 799b4fce7aSJan Engelhardt struct xt_rateest_match_info *info = par->matchinfo; 8050c164a8SPatrick McHardy struct xt_rateest *est1, *est2; 8150c164a8SPatrick McHardy 8250c164a8SPatrick McHardy if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | 8350c164a8SPatrick McHardy XT_RATEEST_MATCH_REL)) != 1) 8450c164a8SPatrick McHardy goto err1; 8550c164a8SPatrick McHardy 8650c164a8SPatrick McHardy if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS))) 8750c164a8SPatrick McHardy goto err1; 8850c164a8SPatrick McHardy 8950c164a8SPatrick McHardy switch (info->mode) { 9050c164a8SPatrick McHardy case XT_RATEEST_MATCH_EQ: 9150c164a8SPatrick McHardy case XT_RATEEST_MATCH_LT: 9250c164a8SPatrick McHardy case XT_RATEEST_MATCH_GT: 9350c164a8SPatrick McHardy break; 9450c164a8SPatrick McHardy default: 9550c164a8SPatrick McHardy goto err1; 9650c164a8SPatrick McHardy } 9750c164a8SPatrick McHardy 9850c164a8SPatrick McHardy est1 = xt_rateest_lookup(info->name1); 9950c164a8SPatrick McHardy if (!est1) 10050c164a8SPatrick McHardy goto err1; 10150c164a8SPatrick McHardy 10250c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_REL) { 10350c164a8SPatrick McHardy est2 = xt_rateest_lookup(info->name2); 10450c164a8SPatrick McHardy if (!est2) 10550c164a8SPatrick McHardy goto err2; 10650c164a8SPatrick McHardy } else 10750c164a8SPatrick McHardy est2 = NULL; 10850c164a8SPatrick McHardy 10950c164a8SPatrick McHardy 11050c164a8SPatrick McHardy info->est1 = est1; 11150c164a8SPatrick McHardy info->est2 = est2; 11250c164a8SPatrick McHardy return true; 11350c164a8SPatrick McHardy 11450c164a8SPatrick McHardy err2: 11550c164a8SPatrick McHardy xt_rateest_put(est1); 11650c164a8SPatrick McHardy err1: 11750c164a8SPatrick McHardy return false; 11850c164a8SPatrick McHardy } 11950c164a8SPatrick McHardy 1206be3d859SJan Engelhardt static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par) 12150c164a8SPatrick McHardy { 1226be3d859SJan Engelhardt struct xt_rateest_match_info *info = par->matchinfo; 12350c164a8SPatrick McHardy 12450c164a8SPatrick McHardy xt_rateest_put(info->est1); 12550c164a8SPatrick McHardy if (info->est2) 12650c164a8SPatrick McHardy xt_rateest_put(info->est2); 12750c164a8SPatrick McHardy } 12850c164a8SPatrick McHardy 12955b69e91SJan Engelhardt static struct xt_match xt_rateest_mt_reg __read_mostly = { 13050c164a8SPatrick McHardy .name = "rateest", 13155b69e91SJan Engelhardt .revision = 0, 13255b69e91SJan Engelhardt .family = NFPROTO_UNSPEC, 13350c164a8SPatrick McHardy .match = xt_rateest_mt, 13450c164a8SPatrick McHardy .checkentry = xt_rateest_mt_checkentry, 13550c164a8SPatrick McHardy .destroy = xt_rateest_mt_destroy, 13650c164a8SPatrick McHardy .matchsize = sizeof(struct xt_rateest_match_info), 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