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