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; 814a5a5c73SJan Engelhardt int ret = false; 8250c164a8SPatrick McHardy 8350c164a8SPatrick McHardy if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | 8450c164a8SPatrick McHardy XT_RATEEST_MATCH_REL)) != 1) 8550c164a8SPatrick McHardy goto err1; 8650c164a8SPatrick McHardy 8750c164a8SPatrick McHardy if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS))) 8850c164a8SPatrick McHardy goto err1; 8950c164a8SPatrick McHardy 9050c164a8SPatrick McHardy switch (info->mode) { 9150c164a8SPatrick McHardy case XT_RATEEST_MATCH_EQ: 9250c164a8SPatrick McHardy case XT_RATEEST_MATCH_LT: 9350c164a8SPatrick McHardy case XT_RATEEST_MATCH_GT: 9450c164a8SPatrick McHardy break; 9550c164a8SPatrick McHardy default: 9650c164a8SPatrick McHardy goto err1; 9750c164a8SPatrick McHardy } 9850c164a8SPatrick McHardy 994a5a5c73SJan Engelhardt ret = -ENOENT; 10050c164a8SPatrick McHardy est1 = xt_rateest_lookup(info->name1); 10150c164a8SPatrick McHardy if (!est1) 10250c164a8SPatrick McHardy goto err1; 10350c164a8SPatrick McHardy 10450c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_REL) { 10550c164a8SPatrick McHardy est2 = xt_rateest_lookup(info->name2); 10650c164a8SPatrick McHardy if (!est2) 10750c164a8SPatrick McHardy goto err2; 10850c164a8SPatrick McHardy } else 10950c164a8SPatrick McHardy est2 = NULL; 11050c164a8SPatrick McHardy 11150c164a8SPatrick McHardy 11250c164a8SPatrick McHardy info->est1 = est1; 11350c164a8SPatrick McHardy info->est2 = est2; 114bd414ee6SJan Engelhardt return 0; 11550c164a8SPatrick McHardy 11650c164a8SPatrick McHardy err2: 11750c164a8SPatrick McHardy xt_rateest_put(est1); 11850c164a8SPatrick McHardy err1: 119bd414ee6SJan Engelhardt return -EINVAL; 12050c164a8SPatrick McHardy } 12150c164a8SPatrick McHardy 1226be3d859SJan Engelhardt static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par) 12350c164a8SPatrick McHardy { 1246be3d859SJan Engelhardt struct xt_rateest_match_info *info = par->matchinfo; 12550c164a8SPatrick McHardy 12650c164a8SPatrick McHardy xt_rateest_put(info->est1); 12750c164a8SPatrick McHardy if (info->est2) 12850c164a8SPatrick McHardy xt_rateest_put(info->est2); 12950c164a8SPatrick McHardy } 13050c164a8SPatrick McHardy 13155b69e91SJan Engelhardt static struct xt_match xt_rateest_mt_reg __read_mostly = { 13250c164a8SPatrick McHardy .name = "rateest", 13355b69e91SJan Engelhardt .revision = 0, 13455b69e91SJan Engelhardt .family = NFPROTO_UNSPEC, 13550c164a8SPatrick McHardy .match = xt_rateest_mt, 13650c164a8SPatrick McHardy .checkentry = xt_rateest_mt_checkentry, 13750c164a8SPatrick McHardy .destroy = xt_rateest_mt_destroy, 13850c164a8SPatrick McHardy .matchsize = sizeof(struct xt_rateest_match_info), 13950c164a8SPatrick McHardy .me = THIS_MODULE, 14050c164a8SPatrick McHardy }; 14150c164a8SPatrick McHardy 14250c164a8SPatrick McHardy static int __init xt_rateest_mt_init(void) 14350c164a8SPatrick McHardy { 14455b69e91SJan Engelhardt return xt_register_match(&xt_rateest_mt_reg); 14550c164a8SPatrick McHardy } 14650c164a8SPatrick McHardy 14750c164a8SPatrick McHardy static void __exit xt_rateest_mt_fini(void) 14850c164a8SPatrick McHardy { 14955b69e91SJan Engelhardt xt_unregister_match(&xt_rateest_mt_reg); 15050c164a8SPatrick McHardy } 15150c164a8SPatrick McHardy 15250c164a8SPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 15350c164a8SPatrick McHardy MODULE_LICENSE("GPL"); 15450c164a8SPatrick McHardy MODULE_DESCRIPTION("xtables rate estimator match"); 15550c164a8SPatrick McHardy MODULE_ALIAS("ipt_rateest"); 15650c164a8SPatrick McHardy MODULE_ALIAS("ip6t_rateest"); 15750c164a8SPatrick McHardy module_init(xt_rateest_mt_init); 15850c164a8SPatrick McHardy module_exit(xt_rateest_mt_fini); 159