1 /* 2 * (C) 2007 Patrick McHardy <[email protected]> 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 #include <linux/module.h> 9 #include <linux/skbuff.h> 10 #include <linux/gen_stats.h> 11 #include <linux/jhash.h> 12 #include <linux/rtnetlink.h> 13 #include <linux/random.h> 14 #include <net/gen_stats.h> 15 #include <net/netlink.h> 16 17 #include <linux/netfilter/x_tables.h> 18 #include <linux/netfilter/xt_RATEEST.h> 19 #include <net/netfilter/xt_rateest.h> 20 21 static DEFINE_MUTEX(xt_rateest_mutex); 22 23 #define RATEEST_HSIZE 16 24 static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly; 25 static unsigned int jhash_rnd __read_mostly; 26 static bool rnd_inited __read_mostly; 27 28 static unsigned int xt_rateest_hash(const char *name) 29 { 30 return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) & 31 (RATEEST_HSIZE - 1); 32 } 33 34 static void xt_rateest_hash_insert(struct xt_rateest *est) 35 { 36 unsigned int h; 37 38 h = xt_rateest_hash(est->name); 39 hlist_add_head(&est->list, &rateest_hash[h]); 40 } 41 42 struct xt_rateest *xt_rateest_lookup(const char *name) 43 { 44 struct xt_rateest *est; 45 struct hlist_node *n; 46 unsigned int h; 47 48 h = xt_rateest_hash(name); 49 mutex_lock(&xt_rateest_mutex); 50 hlist_for_each_entry(est, n, &rateest_hash[h], list) { 51 if (strcmp(est->name, name) == 0) { 52 est->refcnt++; 53 mutex_unlock(&xt_rateest_mutex); 54 return est; 55 } 56 } 57 mutex_unlock(&xt_rateest_mutex); 58 return NULL; 59 } 60 EXPORT_SYMBOL_GPL(xt_rateest_lookup); 61 62 void xt_rateest_put(struct xt_rateest *est) 63 { 64 mutex_lock(&xt_rateest_mutex); 65 if (--est->refcnt == 0) { 66 hlist_del(&est->list); 67 gen_kill_estimator(&est->bstats, &est->rstats); 68 kfree(est); 69 } 70 mutex_unlock(&xt_rateest_mutex); 71 } 72 EXPORT_SYMBOL_GPL(xt_rateest_put); 73 74 static unsigned int 75 xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par) 76 { 77 const struct xt_rateest_target_info *info = par->targinfo; 78 struct gnet_stats_basic_packed *stats = &info->est->bstats; 79 80 spin_lock_bh(&info->est->lock); 81 stats->bytes += skb->len; 82 stats->packets++; 83 spin_unlock_bh(&info->est->lock); 84 85 return XT_CONTINUE; 86 } 87 88 static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) 89 { 90 struct xt_rateest_target_info *info = par->targinfo; 91 struct xt_rateest *est; 92 struct { 93 struct nlattr opt; 94 struct gnet_estimator est; 95 } cfg; 96 97 if (unlikely(!rnd_inited)) { 98 get_random_bytes(&jhash_rnd, sizeof(jhash_rnd)); 99 rnd_inited = true; 100 } 101 102 est = xt_rateest_lookup(info->name); 103 if (est) { 104 /* 105 * If estimator parameters are specified, they must match the 106 * existing estimator. 107 */ 108 if ((!info->interval && !info->ewma_log) || 109 (info->interval != est->params.interval || 110 info->ewma_log != est->params.ewma_log)) { 111 xt_rateest_put(est); 112 return -EINVAL; 113 } 114 info->est = est; 115 return 0; 116 } 117 118 est = kzalloc(sizeof(*est), GFP_KERNEL); 119 if (!est) 120 goto err1; 121 122 strlcpy(est->name, info->name, sizeof(est->name)); 123 spin_lock_init(&est->lock); 124 est->refcnt = 1; 125 est->params.interval = info->interval; 126 est->params.ewma_log = info->ewma_log; 127 128 cfg.opt.nla_len = nla_attr_size(sizeof(cfg.est)); 129 cfg.opt.nla_type = TCA_STATS_RATE_EST; 130 cfg.est.interval = info->interval; 131 cfg.est.ewma_log = info->ewma_log; 132 133 if (gen_new_estimator(&est->bstats, &est->rstats, &est->lock, 134 &cfg.opt) < 0) 135 goto err2; 136 137 info->est = est; 138 xt_rateest_hash_insert(est); 139 return 0; 140 141 err2: 142 kfree(est); 143 err1: 144 return -EINVAL; 145 } 146 147 static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par) 148 { 149 struct xt_rateest_target_info *info = par->targinfo; 150 151 xt_rateest_put(info->est); 152 } 153 154 static struct xt_target xt_rateest_tg_reg __read_mostly = { 155 .name = "RATEEST", 156 .revision = 0, 157 .family = NFPROTO_UNSPEC, 158 .target = xt_rateest_tg, 159 .checkentry = xt_rateest_tg_checkentry, 160 .destroy = xt_rateest_tg_destroy, 161 .targetsize = sizeof(struct xt_rateest_target_info), 162 .me = THIS_MODULE, 163 }; 164 165 static int __init xt_rateest_tg_init(void) 166 { 167 unsigned int i; 168 169 for (i = 0; i < ARRAY_SIZE(rateest_hash); i++) 170 INIT_HLIST_HEAD(&rateest_hash[i]); 171 172 return xt_register_target(&xt_rateest_tg_reg); 173 } 174 175 static void __exit xt_rateest_tg_fini(void) 176 { 177 xt_unregister_target(&xt_rateest_tg_reg); 178 } 179 180 181 MODULE_AUTHOR("Patrick McHardy <[email protected]>"); 182 MODULE_LICENSE("GPL"); 183 MODULE_DESCRIPTION("Xtables: packet rate estimator"); 184 MODULE_ALIAS("ipt_RATEEST"); 185 MODULE_ALIAS("ip6t_RATEEST"); 186 module_init(xt_rateest_tg_init); 187 module_exit(xt_rateest_tg_fini); 188