Blame view

net/netfilter/xt_RATEEST.c 4.59 KB
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * (C) 2007 Patrick McHardy <kaber@trash.net>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/gen_stats.h>
  #include <linux/jhash.h>
  #include <linux/rtnetlink.h>
  #include <linux/random.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
15
  #include <net/gen_stats.h>
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
16
  #include <net/netlink.h>
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
17
18
19
20
21
22
23
24
25
26
  
  #include <linux/netfilter/x_tables.h>
  #include <linux/netfilter/xt_RATEEST.h>
  #include <net/netfilter/xt_rateest.h>
  
  static DEFINE_MUTEX(xt_rateest_mutex);
  
  #define RATEEST_HSIZE	16
  static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly;
  static unsigned int jhash_rnd __read_mostly;
5191d5019   Jan Engelhardt   netfilter: xtable...
27
  static bool rnd_inited __read_mostly;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  
  static unsigned int xt_rateest_hash(const char *name)
  {
  	return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) &
  	       (RATEEST_HSIZE - 1);
  }
  
  static void xt_rateest_hash_insert(struct xt_rateest *est)
  {
  	unsigned int h;
  
  	h = xt_rateest_hash(est->name);
  	hlist_add_head(&est->list, &rateest_hash[h]);
  }
  
  struct xt_rateest *xt_rateest_lookup(const char *name)
  {
  	struct xt_rateest *est;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
46
47
48
49
  	unsigned int h;
  
  	h = xt_rateest_hash(name);
  	mutex_lock(&xt_rateest_mutex);
b67bfe0d4   Sasha Levin   hlist: drop the n...
50
  	hlist_for_each_entry(est, &rateest_hash[h], list) {
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  		if (strcmp(est->name, name) == 0) {
  			est->refcnt++;
  			mutex_unlock(&xt_rateest_mutex);
  			return est;
  		}
  	}
  	mutex_unlock(&xt_rateest_mutex);
  	return NULL;
  }
  EXPORT_SYMBOL_GPL(xt_rateest_lookup);
  
  void xt_rateest_put(struct xt_rateest *est)
  {
  	mutex_lock(&xt_rateest_mutex);
  	if (--est->refcnt == 0) {
  		hlist_del(&est->list);
  		gen_kill_estimator(&est->bstats, &est->rstats);
c7de2cf05   Eric Dumazet   pkt_sched: gen_ki...
68
69
70
71
  		/*
  		 * gen_estimator est_timer() might access est->lock or bstats,
  		 * wait a RCU grace period before freeing 'est'
  		 */
cefcb6020   Paul E. McKenney   net,rcu: Convert ...
72
  		kfree_rcu(est, rcu);
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
73
74
75
76
77
78
  	}
  	mutex_unlock(&xt_rateest_mutex);
  }
  EXPORT_SYMBOL_GPL(xt_rateest_put);
  
  static unsigned int
4b560b447   Jan Engelhardt   netfilter: xtable...
79
  xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par)
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
80
  {
7eb355865   Jan Engelhardt   netfilter: xtable...
81
  	const struct xt_rateest_target_info *info = par->targinfo;
c1a8f1f1c   Eric Dumazet   net: restore gnet...
82
  	struct gnet_stats_basic_packed *stats = &info->est->bstats;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
83
84
85
86
87
88
89
90
  
  	spin_lock_bh(&info->est->lock);
  	stats->bytes += skb->len;
  	stats->packets++;
  	spin_unlock_bh(&info->est->lock);
  
  	return XT_CONTINUE;
  }
135367b8f   Jan Engelhardt   netfilter: xtable...
91
  static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
92
  {
af5d6dc20   Jan Engelhardt   netfilter: xtable...
93
  	struct xt_rateest_target_info *info = par->targinfo;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
94
95
  	struct xt_rateest *est;
  	struct {
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
96
  		struct nlattr		opt;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
97
98
  		struct gnet_estimator	est;
  	} cfg;
4a5a5c73b   Jan Engelhardt   netfilter: xtable...
99
  	int ret;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
100

5191d5019   Jan Engelhardt   netfilter: xtable...
101
102
103
104
  	if (unlikely(!rnd_inited)) {
  		get_random_bytes(&jhash_rnd, sizeof(jhash_rnd));
  		rnd_inited = true;
  	}
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
105
106
107
108
109
110
111
112
113
114
  	est = xt_rateest_lookup(info->name);
  	if (est) {
  		/*
  		 * If estimator parameters are specified, they must match the
  		 * existing estimator.
  		 */
  		if ((!info->interval && !info->ewma_log) ||
  		    (info->interval != est->params.interval ||
  		     info->ewma_log != est->params.ewma_log)) {
  			xt_rateest_put(est);
d6b00a534   Jan Engelhardt   netfilter: xtable...
115
  			return -EINVAL;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
116
117
  		}
  		info->est = est;
d6b00a534   Jan Engelhardt   netfilter: xtable...
118
  		return 0;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
119
  	}
4a5a5c73b   Jan Engelhardt   netfilter: xtable...
120
  	ret = -ENOMEM;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
121
122
123
124
125
126
127
128
129
  	est = kzalloc(sizeof(*est), GFP_KERNEL);
  	if (!est)
  		goto err1;
  
  	strlcpy(est->name, info->name, sizeof(est->name));
  	spin_lock_init(&est->lock);
  	est->refcnt		= 1;
  	est->params.interval	= info->interval;
  	est->params.ewma_log	= info->ewma_log;
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
130
131
  	cfg.opt.nla_len		= nla_attr_size(sizeof(cfg.est));
  	cfg.opt.nla_type	= TCA_STATS_RATE_EST;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
132
133
  	cfg.est.interval	= info->interval;
  	cfg.est.ewma_log	= info->ewma_log;
22e0f8b93   John Fastabend   net: sched: make ...
134
  	ret = gen_new_estimator(&est->bstats, NULL, &est->rstats,
4a5a5c73b   Jan Engelhardt   netfilter: xtable...
135
136
  				&est->lock, &cfg.opt);
  	if (ret < 0)
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
137
138
139
140
  		goto err2;
  
  	info->est = est;
  	xt_rateest_hash_insert(est);
d6b00a534   Jan Engelhardt   netfilter: xtable...
141
  	return 0;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
142
143
144
145
  
  err2:
  	kfree(est);
  err1:
4a5a5c73b   Jan Engelhardt   netfilter: xtable...
146
  	return ret;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
147
  }
a2df1648b   Jan Engelhardt   netfilter: xtable...
148
  static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
149
  {
a2df1648b   Jan Engelhardt   netfilter: xtable...
150
  	struct xt_rateest_target_info *info = par->targinfo;
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
151
152
153
  
  	xt_rateest_put(info->est);
  }
55b69e910   Jan Engelhardt   netfilter: implem...
154
155
156
157
158
159
160
161
162
  static struct xt_target xt_rateest_tg_reg __read_mostly = {
  	.name       = "RATEEST",
  	.revision   = 0,
  	.family     = NFPROTO_UNSPEC,
  	.target     = xt_rateest_tg,
  	.checkentry = xt_rateest_tg_checkentry,
  	.destroy    = xt_rateest_tg_destroy,
  	.targetsize = sizeof(struct xt_rateest_target_info),
  	.me         = THIS_MODULE,
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
163
164
165
166
167
168
169
170
  };
  
  static int __init xt_rateest_tg_init(void)
  {
  	unsigned int i;
  
  	for (i = 0; i < ARRAY_SIZE(rateest_hash); i++)
  		INIT_HLIST_HEAD(&rateest_hash[i]);
55b69e910   Jan Engelhardt   netfilter: implem...
171
  	return xt_register_target(&xt_rateest_tg_reg);
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
172
173
174
175
  }
  
  static void __exit xt_rateest_tg_fini(void)
  {
55b69e910   Jan Engelhardt   netfilter: implem...
176
  	xt_unregister_target(&xt_rateest_tg_reg);
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
177
178
179
180
181
  }
  
  
  MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
  MODULE_LICENSE("GPL");
2ae15b64e   Jan Engelhardt   [NETFILTER]: Upda...
182
  MODULE_DESCRIPTION("Xtables: packet rate estimator");
5859034d7   Patrick McHardy   [NETFILTER]: x_ta...
183
184
185
186
  MODULE_ALIAS("ipt_RATEEST");
  MODULE_ALIAS("ip6t_RATEEST");
  module_init(xt_rateest_tg_init);
  module_exit(xt_rateest_tg_fini);