Skip to content

Commit 5859034

Browse files
kaberdavem330
authored andcommitted
[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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cb76c6a commit 5859034

6 files changed

Lines changed: 244 additions & 0 deletions

File tree

include/linux/netfilter/Kbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ header-y += xt_DSCP.h
1010
header-y += xt_MARK.h
1111
header-y += xt_NFLOG.h
1212
header-y += xt_NFQUEUE.h
13+
header-y += xt_RATEEST.h
1314
header-y += xt_SECMARK.h
1415
header-y += xt_TCPMSS.h
1516
header-y += xt_comment.h
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */

include/net/netfilter/xt_rateest.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */

net/netfilter/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,16 @@ config NETFILTER_XT_TARGET_NOTRACK
357357
If you want to compile it as a module, say M here and read
358358
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
359359

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+
360370
config NETFILTER_XT_TARGET_TRACE
361371
tristate '"TRACE" target support'
362372
depends on NETFILTER_XTABLES

net/netfilter/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
4646
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
4747
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
4848
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
49+
obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o
4950
obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
5051
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
5152
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o

net/netfilter/xt_RATEEST.c

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
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+
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 <[email protected]>");
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);

0 commit comments

Comments
 (0)