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 1750c164a8SPatrick McHardy static bool xt_rateest_mt(const struct sk_buff *skb, 1850c164a8SPatrick McHardy const struct net_device *in, 1950c164a8SPatrick McHardy const struct net_device *out, 2050c164a8SPatrick McHardy const struct xt_match *match, 2150c164a8SPatrick McHardy const void *matchinfo, 2250c164a8SPatrick McHardy int offset, 2350c164a8SPatrick McHardy unsigned int protoff, 2450c164a8SPatrick McHardy bool *hotdrop) 2550c164a8SPatrick McHardy { 2650c164a8SPatrick McHardy const struct xt_rateest_match_info *info = matchinfo; 2750c164a8SPatrick McHardy struct gnet_stats_rate_est *r; 2850c164a8SPatrick McHardy u_int32_t bps1, bps2, pps1, pps2; 2950c164a8SPatrick McHardy bool ret = true; 3050c164a8SPatrick McHardy 3150c164a8SPatrick McHardy spin_lock_bh(&info->est1->lock); 3250c164a8SPatrick McHardy r = &info->est1->rstats; 3350c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_DELTA) { 3450c164a8SPatrick McHardy bps1 = info->bps1 >= r->bps ? info->bps1 - r->bps : 0; 3550c164a8SPatrick McHardy pps1 = info->pps1 >= r->pps ? info->pps1 - r->pps : 0; 3650c164a8SPatrick McHardy } else { 3750c164a8SPatrick McHardy bps1 = r->bps; 3850c164a8SPatrick McHardy pps1 = r->pps; 3950c164a8SPatrick McHardy } 4050c164a8SPatrick McHardy spin_unlock_bh(&info->est1->lock); 4150c164a8SPatrick McHardy 4250c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_ABS) { 4350c164a8SPatrick McHardy bps2 = info->bps2; 4450c164a8SPatrick McHardy pps2 = info->pps2; 4550c164a8SPatrick McHardy } else { 4650c164a8SPatrick McHardy spin_lock_bh(&info->est2->lock); 4750c164a8SPatrick McHardy r = &info->est2->rstats; 4850c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_DELTA) { 4950c164a8SPatrick McHardy bps2 = info->bps2 >= r->bps ? info->bps2 - r->bps : 0; 5050c164a8SPatrick McHardy pps2 = info->pps2 >= r->pps ? info->pps2 - r->pps : 0; 5150c164a8SPatrick McHardy } else { 5250c164a8SPatrick McHardy bps2 = r->bps; 5350c164a8SPatrick McHardy pps2 = r->pps; 5450c164a8SPatrick McHardy } 5550c164a8SPatrick McHardy spin_unlock_bh(&info->est2->lock); 5650c164a8SPatrick McHardy } 5750c164a8SPatrick McHardy 5850c164a8SPatrick McHardy switch (info->mode) { 5950c164a8SPatrick McHardy case XT_RATEEST_MATCH_LT: 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_GT: 6650c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_BPS) 6750c164a8SPatrick McHardy ret &= bps1 > bps2; 6850c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_PPS) 6950c164a8SPatrick McHardy ret &= pps1 > pps2; 7050c164a8SPatrick McHardy break; 7150c164a8SPatrick McHardy case XT_RATEEST_MATCH_EQ: 7250c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_BPS) 7350c164a8SPatrick McHardy ret &= bps1 == bps2; 7450c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_PPS) 7550c164a8SPatrick McHardy ret &= pps2 == pps2; 7650c164a8SPatrick McHardy break; 7750c164a8SPatrick McHardy } 7850c164a8SPatrick McHardy 7950c164a8SPatrick McHardy ret ^= info->flags & XT_RATEEST_MATCH_INVERT ? true : false; 8050c164a8SPatrick McHardy return ret; 8150c164a8SPatrick McHardy } 8250c164a8SPatrick McHardy 8350c164a8SPatrick McHardy static bool xt_rateest_mt_checkentry(const char *tablename, 8450c164a8SPatrick McHardy const void *ip, 8550c164a8SPatrick McHardy const struct xt_match *match, 8650c164a8SPatrick McHardy void *matchinfo, 8750c164a8SPatrick McHardy unsigned int hook_mask) 8850c164a8SPatrick McHardy { 893cf93c96SJan Engelhardt struct xt_rateest_match_info *info = matchinfo; 9050c164a8SPatrick McHardy struct xt_rateest *est1, *est2; 9150c164a8SPatrick McHardy 9250c164a8SPatrick McHardy if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | 9350c164a8SPatrick McHardy XT_RATEEST_MATCH_REL)) != 1) 9450c164a8SPatrick McHardy goto err1; 9550c164a8SPatrick McHardy 9650c164a8SPatrick McHardy if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS))) 9750c164a8SPatrick McHardy goto err1; 9850c164a8SPatrick McHardy 9950c164a8SPatrick McHardy switch (info->mode) { 10050c164a8SPatrick McHardy case XT_RATEEST_MATCH_EQ: 10150c164a8SPatrick McHardy case XT_RATEEST_MATCH_LT: 10250c164a8SPatrick McHardy case XT_RATEEST_MATCH_GT: 10350c164a8SPatrick McHardy break; 10450c164a8SPatrick McHardy default: 10550c164a8SPatrick McHardy goto err1; 10650c164a8SPatrick McHardy } 10750c164a8SPatrick McHardy 10850c164a8SPatrick McHardy est1 = xt_rateest_lookup(info->name1); 10950c164a8SPatrick McHardy if (!est1) 11050c164a8SPatrick McHardy goto err1; 11150c164a8SPatrick McHardy 11250c164a8SPatrick McHardy if (info->flags & XT_RATEEST_MATCH_REL) { 11350c164a8SPatrick McHardy est2 = xt_rateest_lookup(info->name2); 11450c164a8SPatrick McHardy if (!est2) 11550c164a8SPatrick McHardy goto err2; 11650c164a8SPatrick McHardy } else 11750c164a8SPatrick McHardy est2 = NULL; 11850c164a8SPatrick McHardy 11950c164a8SPatrick McHardy 12050c164a8SPatrick McHardy info->est1 = est1; 12150c164a8SPatrick McHardy info->est2 = est2; 12250c164a8SPatrick McHardy return true; 12350c164a8SPatrick McHardy 12450c164a8SPatrick McHardy err2: 12550c164a8SPatrick McHardy xt_rateest_put(est1); 12650c164a8SPatrick McHardy err1: 12750c164a8SPatrick McHardy return false; 12850c164a8SPatrick McHardy } 12950c164a8SPatrick McHardy 13050c164a8SPatrick McHardy static void xt_rateest_mt_destroy(const struct xt_match *match, 13150c164a8SPatrick McHardy void *matchinfo) 13250c164a8SPatrick McHardy { 1333cf93c96SJan Engelhardt struct xt_rateest_match_info *info = matchinfo; 13450c164a8SPatrick McHardy 13550c164a8SPatrick McHardy xt_rateest_put(info->est1); 13650c164a8SPatrick McHardy if (info->est2) 13750c164a8SPatrick McHardy xt_rateest_put(info->est2); 13850c164a8SPatrick McHardy } 13950c164a8SPatrick McHardy 14050c164a8SPatrick McHardy static struct xt_match xt_rateest_match[] __read_mostly = { 14150c164a8SPatrick McHardy { 14250c164a8SPatrick McHardy .family = AF_INET, 14350c164a8SPatrick McHardy .name = "rateest", 14450c164a8SPatrick McHardy .match = xt_rateest_mt, 14550c164a8SPatrick McHardy .checkentry = xt_rateest_mt_checkentry, 14650c164a8SPatrick McHardy .destroy = xt_rateest_mt_destroy, 14750c164a8SPatrick McHardy .matchsize = sizeof(struct xt_rateest_match_info), 14850c164a8SPatrick McHardy .me = THIS_MODULE, 14950c164a8SPatrick McHardy }, 15050c164a8SPatrick McHardy { 15150c164a8SPatrick McHardy .family = AF_INET6, 15250c164a8SPatrick McHardy .name = "rateest", 15350c164a8SPatrick McHardy .match = xt_rateest_mt, 15450c164a8SPatrick McHardy .checkentry = xt_rateest_mt_checkentry, 15550c164a8SPatrick McHardy .destroy = xt_rateest_mt_destroy, 15650c164a8SPatrick McHardy .matchsize = sizeof(struct xt_rateest_match_info), 15750c164a8SPatrick McHardy .me = THIS_MODULE, 15850c164a8SPatrick McHardy }, 15950c164a8SPatrick McHardy }; 16050c164a8SPatrick McHardy 16150c164a8SPatrick McHardy static int __init xt_rateest_mt_init(void) 16250c164a8SPatrick McHardy { 16350c164a8SPatrick McHardy return xt_register_matches(xt_rateest_match, 16450c164a8SPatrick McHardy ARRAY_SIZE(xt_rateest_match)); 16550c164a8SPatrick McHardy } 16650c164a8SPatrick McHardy 16750c164a8SPatrick McHardy static void __exit xt_rateest_mt_fini(void) 16850c164a8SPatrick McHardy { 16950c164a8SPatrick McHardy xt_unregister_matches(xt_rateest_match, ARRAY_SIZE(xt_rateest_match)); 17050c164a8SPatrick McHardy } 17150c164a8SPatrick McHardy 17250c164a8SPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 17350c164a8SPatrick McHardy MODULE_LICENSE("GPL"); 17450c164a8SPatrick McHardy MODULE_DESCRIPTION("xtables rate estimator match"); 17550c164a8SPatrick McHardy MODULE_ALIAS("ipt_rateest"); 17650c164a8SPatrick McHardy MODULE_ALIAS("ip6t_rateest"); 17750c164a8SPatrick McHardy module_init(xt_rateest_mt_init); 17850c164a8SPatrick McHardy module_exit(xt_rateest_mt_fini); 179