diff options
author | Patrick McHardy <kaber@trash.net> | 2007-12-05 02:40:05 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:56:02 -0500 |
commit | 5859034d7eb8793d3d78d3af515c4175e7b9d03a (patch) | |
tree | fbd0efe0424d9ef9dbe2a57b905bcd413c4cb0bc | |
parent | cb76c6a597350534d211ba79d92da1f9771f8226 (diff) |
[NETFILTER]: x_tables: add RATEEST target
Add new rate estimator target (using gen_estimator). In combination with
the rateest match (next patch) this can be used for load-based multipath
routing.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netfilter/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/netfilter/xt_RATEEST.h | 11 | ||||
-rw-r--r-- | include/net/netfilter/xt_rateest.h | 17 | ||||
-rw-r--r-- | net/netfilter/Kconfig | 10 | ||||
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/xt_RATEEST.c | 204 |
6 files changed, 244 insertions, 0 deletions
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index 1e6900278318..707a15854430 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild | |||
@@ -10,6 +10,7 @@ header-y += xt_DSCP.h | |||
10 | header-y += xt_MARK.h | 10 | header-y += xt_MARK.h |
11 | header-y += xt_NFLOG.h | 11 | header-y += xt_NFLOG.h |
12 | header-y += xt_NFQUEUE.h | 12 | header-y += xt_NFQUEUE.h |
13 | header-y += xt_RATEEST.h | ||
13 | header-y += xt_SECMARK.h | 14 | header-y += xt_SECMARK.h |
14 | header-y += xt_TCPMSS.h | 15 | header-y += xt_TCPMSS.h |
15 | header-y += xt_comment.h | 16 | header-y += xt_comment.h |
diff --git a/include/linux/netfilter/xt_RATEEST.h b/include/linux/netfilter/xt_RATEEST.h new file mode 100644 index 000000000000..670f2e49d4fb --- /dev/null +++ b/include/linux/netfilter/xt_RATEEST.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef _XT_RATEEST_TARGET_H | ||
2 | #define _XT_RATEEST_TARGET_H | ||
3 | |||
4 | struct xt_rateest_target_info { | ||
5 | char name[IFNAMSIZ]; | ||
6 | int8_t interval; | ||
7 | u_int8_t ewma_log; | ||
8 | struct xt_rateest *est __attribute__((aligned(8))); | ||
9 | }; | ||
10 | |||
11 | #endif /* _XT_RATEEST_TARGET_H */ | ||
diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h new file mode 100644 index 000000000000..65d594dffbff --- /dev/null +++ b/include/net/netfilter/xt_rateest.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef _XT_RATEEST_H | ||
2 | #define _XT_RATEEST_H | ||
3 | |||
4 | struct xt_rateest { | ||
5 | struct hlist_node list; | ||
6 | char name[IFNAMSIZ]; | ||
7 | unsigned int refcnt; | ||
8 | spinlock_t lock; | ||
9 | struct gnet_estimator params; | ||
10 | struct gnet_stats_rate_est rstats; | ||
11 | struct gnet_stats_basic bstats; | ||
12 | }; | ||
13 | |||
14 | extern struct xt_rateest *xt_rateest_lookup(const char *name); | ||
15 | extern void xt_rateest_put(struct xt_rateest *est); | ||
16 | |||
17 | #endif /* _XT_RATEEST_H */ | ||
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 7bde6315999a..22d1f10e88b0 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -357,6 +357,16 @@ config NETFILTER_XT_TARGET_NOTRACK | |||
357 | If you want to compile it as a module, say M here and read | 357 | If you want to compile it as a module, say M here and read |
358 | <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. | 358 | <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. |
359 | 359 | ||
360 | config NETFILTER_XT_TARGET_RATEEST | ||
361 | tristate '"RATEEST" target support' | ||
362 | depends on NETFILTER_XTABLES | ||
363 | help | ||
364 | This option adds a `RATEEST' target, which allows to measure | ||
365 | rates similar to TC estimators. The `rateest' match can be | ||
366 | used to match on the measured rates. | ||
367 | |||
368 | To compile it as a module, choose M here. If unsure, say N. | ||
369 | |||
360 | config NETFILTER_XT_TARGET_TRACE | 370 | config NETFILTER_XT_TARGET_TRACE |
361 | tristate '"TRACE" target support' | 371 | tristate '"TRACE" target support' |
362 | depends on NETFILTER_XTABLES | 372 | depends on NETFILTER_XTABLES |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 28f59a35aeef..413afaad361f 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -46,6 +46,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o | |||
46 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o | 46 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o |
47 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o | 47 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o |
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o | 48 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o |
49 | obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o | ||
49 | obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o | 50 | obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o |
50 | obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o | 51 | obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o |
51 | obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o | 52 | obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o |
diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c new file mode 100644 index 000000000000..c0088839fde2 --- /dev/null +++ b/net/netfilter/xt_RATEEST.c | |||
@@ -0,0 +1,204 @@ | |||
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 <net/gen_stats.h> | ||
15 | |||
16 | #include <linux/netfilter/x_tables.h> | ||
17 | #include <linux/netfilter/xt_RATEEST.h> | ||
18 | #include <net/netfilter/xt_rateest.h> | ||
19 | |||
20 | static DEFINE_MUTEX(xt_rateest_mutex); | ||
21 | |||
22 | #define RATEEST_HSIZE 16 | ||
23 | static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly; | ||
24 | static unsigned int jhash_rnd __read_mostly; | ||
25 | |||
26 | static unsigned int xt_rateest_hash(const char *name) | ||
27 | { | ||
28 | return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) & | ||
29 | (RATEEST_HSIZE - 1); | ||
30 | } | ||
31 | |||
32 | static void xt_rateest_hash_insert(struct xt_rateest *est) | ||
33 | { | ||
34 | unsigned int h; | ||
35 | |||
36 | h = xt_rateest_hash(est->name); | ||
37 | hlist_add_head(&est->list, &rateest_hash[h]); | ||
38 | } | ||
39 | |||
40 | struct xt_rateest *xt_rateest_lookup(const char *name) | ||
41 | { | ||
42 | struct xt_rateest *est; | ||
43 | struct hlist_node *n; | ||
44 | unsigned int h; | ||
45 | |||
46 | h = xt_rateest_hash(name); | ||
47 | mutex_lock(&xt_rateest_mutex); | ||
48 | hlist_for_each_entry(est, n, &rateest_hash[h], list) { | ||
49 | if (strcmp(est->name, name) == 0) { | ||
50 | est->refcnt++; | ||
51 | mutex_unlock(&xt_rateest_mutex); | ||
52 | return est; | ||
53 | } | ||
54 | } | ||
55 | mutex_unlock(&xt_rateest_mutex); | ||
56 | return NULL; | ||
57 | } | ||
58 | EXPORT_SYMBOL_GPL(xt_rateest_lookup); | ||
59 | |||
60 | void xt_rateest_put(struct xt_rateest *est) | ||
61 | { | ||
62 | mutex_lock(&xt_rateest_mutex); | ||
63 | if (--est->refcnt == 0) { | ||
64 | hlist_del(&est->list); | ||
65 | gen_kill_estimator(&est->bstats, &est->rstats); | ||
66 | kfree(est); | ||
67 | } | ||
68 | mutex_unlock(&xt_rateest_mutex); | ||
69 | } | ||
70 | EXPORT_SYMBOL_GPL(xt_rateest_put); | ||
71 | |||
72 | static unsigned int | ||
73 | xt_rateest_tg(struct sk_buff *skb, | ||
74 | const struct net_device *in, | ||
75 | const struct net_device *out, | ||
76 | unsigned int hooknum, | ||
77 | const struct xt_target *target, | ||
78 | const void *targinfo) | ||
79 | { | ||
80 | const struct xt_rateest_target_info *info = targinfo; | ||
81 | struct gnet_stats_basic *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 | |||
91 | static bool | ||
92 | xt_rateest_tg_checkentry(const char *tablename, | ||
93 | const void *entry, | ||
94 | const struct xt_target *target, | ||
95 | void *targinfo, | ||
96 | unsigned int hook_mask) | ||
97 | { | ||
98 | struct xt_rateest_target_info *info = (void *)targinfo; | ||
99 | struct xt_rateest *est; | ||
100 | struct { | ||
101 | struct rtattr opt; | ||
102 | struct gnet_estimator est; | ||
103 | } cfg; | ||
104 | |||
105 | est = xt_rateest_lookup(info->name); | ||
106 | if (est) { | ||
107 | /* | ||
108 | * If estimator parameters are specified, they must match the | ||
109 | * existing estimator. | ||
110 | */ | ||
111 | if ((!info->interval && !info->ewma_log) || | ||
112 | (info->interval != est->params.interval || | ||
113 | info->ewma_log != est->params.ewma_log)) { | ||
114 | xt_rateest_put(est); | ||
115 | return false; | ||
116 | } | ||
117 | info->est = est; | ||
118 | return true; | ||
119 | } | ||
120 | |||
121 | est = kzalloc(sizeof(*est), GFP_KERNEL); | ||
122 | if (!est) | ||
123 | goto err1; | ||
124 | |||
125 | strlcpy(est->name, info->name, sizeof(est->name)); | ||
126 | spin_lock_init(&est->lock); | ||
127 | est->refcnt = 1; | ||
128 | est->params.interval = info->interval; | ||
129 | est->params.ewma_log = info->ewma_log; | ||
130 | |||
131 | cfg.opt.rta_len = RTA_LENGTH(sizeof(cfg.est)); | ||
132 | cfg.opt.rta_type = TCA_STATS_RATE_EST; | ||
133 | cfg.est.interval = info->interval; | ||
134 | cfg.est.ewma_log = info->ewma_log; | ||
135 | |||
136 | if (gen_new_estimator(&est->bstats, &est->rstats, &est->lock, | ||
137 | &cfg.opt) < 0) | ||
138 | goto err2; | ||
139 | |||
140 | info->est = est; | ||
141 | xt_rateest_hash_insert(est); | ||
142 | |||
143 | return true; | ||
144 | |||
145 | err2: | ||
146 | kfree(est); | ||
147 | err1: | ||
148 | return false; | ||
149 | } | ||
150 | |||
151 | static void xt_rateest_tg_destroy(const struct xt_target *target, | ||
152 | void *targinfo) | ||
153 | { | ||
154 | struct xt_rateest_target_info *info = targinfo; | ||
155 | |||
156 | xt_rateest_put(info->est); | ||
157 | } | ||
158 | |||
159 | static struct xt_target xt_rateest_target[] __read_mostly = { | ||
160 | { | ||
161 | .family = AF_INET, | ||
162 | .name = "RATEEST", | ||
163 | .target = xt_rateest_tg, | ||
164 | .checkentry = xt_rateest_tg_checkentry, | ||
165 | .destroy = xt_rateest_tg_destroy, | ||
166 | .targetsize = sizeof(struct xt_rateest_target_info), | ||
167 | .me = THIS_MODULE, | ||
168 | }, | ||
169 | { | ||
170 | .family = AF_INET6, | ||
171 | .name = "RATEEST", | ||
172 | .target = xt_rateest_tg, | ||
173 | .checkentry = xt_rateest_tg_checkentry, | ||
174 | .destroy = xt_rateest_tg_destroy, | ||
175 | .targetsize = sizeof(struct xt_rateest_target_info), | ||
176 | .me = THIS_MODULE, | ||
177 | }, | ||
178 | }; | ||
179 | |||
180 | static int __init xt_rateest_tg_init(void) | ||
181 | { | ||
182 | unsigned int i; | ||
183 | |||
184 | for (i = 0; i < ARRAY_SIZE(rateest_hash); i++) | ||
185 | INIT_HLIST_HEAD(&rateest_hash[i]); | ||
186 | |||
187 | get_random_bytes(&jhash_rnd, sizeof(jhash_rnd)); | ||
188 | return xt_register_targets(xt_rateest_target, | ||
189 | ARRAY_SIZE(xt_rateest_target)); | ||
190 | } | ||
191 | |||
192 | static void __exit xt_rateest_tg_fini(void) | ||
193 | { | ||
194 | xt_unregister_targets(xt_rateest_target, ARRAY_SIZE(xt_rateest_target)); | ||
195 | } | ||
196 | |||
197 | |||
198 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
199 | MODULE_LICENSE("GPL"); | ||
200 | MODULE_DESCRIPTION("xtables rate estimator"); | ||
201 | MODULE_ALIAS("ipt_RATEEST"); | ||
202 | MODULE_ALIAS("ip6t_RATEEST"); | ||
203 | module_init(xt_rateest_tg_init); | ||
204 | module_exit(xt_rateest_tg_fini); | ||