libxt_RATEEST.c revision 9ee386a1b6d7704b259460152c959ab0e79e02aa
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stddef.h>
5#include <getopt.h>
6#include <math.h>
7
8#include <xtables.h>
9#include <linux/netfilter/x_tables.h>
10#include <linux/netfilter/xt_RATEEST.h>
11
12/* hack to pass raw values to final_check */
13static struct xt_rateest_target_info *RATEEST_info;
14static unsigned int interval;
15static unsigned int ewma_log;
16
17static void
18RATEEST_help(void)
19{
20	printf(
21"RATEST target v%s options:\n"
22"  --rateest-name name		Rate estimator name\n"
23"  --rateest-interval sec	Rate measurement interval in seconds\n"
24"  --rateest-ewmalog value	Rate measurement averaging time constant\n"
25"\n",
26	       IPTABLES_VERSION);
27}
28
29enum RATEEST_options {
30	RATEEST_OPT_NAME,
31	RATEEST_OPT_INTERVAL,
32	RATEEST_OPT_EWMALOG,
33};
34
35static const struct option RATEEST_opts[] = {
36	{ "rateest-name",	1, NULL, RATEEST_OPT_NAME },
37	{ "rateest-interval",	1, NULL, RATEEST_OPT_INTERVAL },
38	{ "rateest-ewmalog",	1, NULL, RATEEST_OPT_EWMALOG },
39	{ .name = NULL },
40};
41
42/* Copied from iproute */
43#define TIME_UNITS_PER_SEC	1000000
44
45static int
46RATEEST_get_time(unsigned int *time, const char *str)
47{
48	double t;
49	char *p;
50
51	t = strtod(str, &p);
52	if (p == str)
53		return -1;
54
55	if (*p) {
56		if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
57		    strcasecmp(p, "secs")==0)
58			t *= TIME_UNITS_PER_SEC;
59		else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
60			 strcasecmp(p, "msecs") == 0)
61			t *= TIME_UNITS_PER_SEC/1000;
62		else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
63			 strcasecmp(p, "usecs") == 0)
64			t *= TIME_UNITS_PER_SEC/1000000;
65		else
66			return -1;
67	}
68
69	*time = t;
70	return 0;
71}
72
73static void
74RATEEST_print_time(unsigned int time)
75{
76	double tmp = time;
77
78	if (tmp >= TIME_UNITS_PER_SEC)
79		printf("%.1fs ", tmp/TIME_UNITS_PER_SEC);
80	else if (tmp >= TIME_UNITS_PER_SEC/1000)
81		printf("%.1fms ", tmp/(TIME_UNITS_PER_SEC/1000));
82	else
83		printf("%uus ", time);
84}
85
86static void
87RATEEST_init(struct xt_entry_target *target)
88{
89	interval = 0;
90	ewma_log = 0;
91}
92
93static int
94RATEEST_parse(int c, char **argv, int invert, unsigned int *flags,
95	      const void *entry, struct xt_entry_target **target)
96{
97	struct xt_rateest_target_info *info = (void *)(*target)->data;
98
99	RATEEST_info = info;
100
101	switch (c) {
102	case RATEEST_OPT_NAME:
103		if (*flags & (1 << c))
104			exit_error(PARAMETER_PROBLEM,
105				   "RATEEST: can't specify --rateest-name twice");
106		*flags |= 1 << c;
107
108		strncpy(info->name, optarg, sizeof(info->name) - 1);
109		break;
110
111	case RATEEST_OPT_INTERVAL:
112		if (*flags & (1 << c))
113			exit_error(PARAMETER_PROBLEM,
114				   "RATEEST: can't specify --rateest-interval twice");
115		*flags |= 1 << c;
116
117		if (RATEEST_get_time(&interval, optarg) < 0)
118			exit_error(PARAMETER_PROBLEM,
119				   "RATEEST: bad interval value `%s'", optarg);
120
121		break;
122
123	case RATEEST_OPT_EWMALOG:
124		if (*flags & (1 << c))
125			exit_error(PARAMETER_PROBLEM,
126				   "RATEEST: can't specify --rateest-ewmalog twice");
127		*flags |= 1 << c;
128
129		if (RATEEST_get_time(&ewma_log, optarg) < 0)
130			exit_error(PARAMETER_PROBLEM,
131				   "RATEEST: bad ewmalog value `%s'", optarg);
132
133		break;
134
135	default:
136		return 0;
137	}
138
139	return 1;
140}
141
142static void
143RATEEST_final_check(unsigned int flags)
144{
145	struct xt_rateest_target_info *info = RATEEST_info;
146
147	if (!(flags & (1 << RATEEST_OPT_NAME)))
148		exit_error(PARAMETER_PROBLEM, "RATEEST: no name specified");
149	if (!(flags & (1 << RATEEST_OPT_INTERVAL)))
150		exit_error(PARAMETER_PROBLEM, "RATEEST: no interval specified");
151	if (!(flags & (1 << RATEEST_OPT_EWMALOG)))
152		exit_error(PARAMETER_PROBLEM, "RATEEST: no ewmalog specified");
153
154	for (info->interval = 0; info->interval <= 5; info->interval++) {
155		if (interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4))
156			break;
157	}
158
159	if (info->interval > 5)
160		exit_error(PARAMETER_PROBLEM,
161			   "RATEEST: interval value is too large");
162	info->interval -= 2;
163
164	for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) {
165		double w = 1.0 - 1.0 / (1 << info->ewma_log);
166		if (interval / (-log(w)) > ewma_log)
167			break;
168	}
169	info->ewma_log--;
170
171	if (info->ewma_log == 0 || info->ewma_log >= 31)
172		exit_error(PARAMETER_PROBLEM,
173			   "RATEEST: ewmalog value is out of range");
174}
175
176static void
177__RATEEST_print(const struct xt_entry_target *target, const char *prefix)
178{
179	struct xt_rateest_target_info *info = (void *)target->data;
180	unsigned int interval;
181	unsigned int ewma_log;
182
183	interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4;
184	ewma_log = interval * (1 << (info->ewma_log));
185
186	printf("%sname %s ", prefix, info->name);
187	printf("%sinterval ", prefix);
188	RATEEST_print_time(interval);
189	printf("%sewmalog ", prefix);
190	RATEEST_print_time(ewma_log);
191}
192
193static void
194RATEEST_print(const void *ip, const struct xt_entry_target *target,
195	      int numeric)
196{
197	__RATEEST_print(target, "");
198}
199
200static void
201RATEEST_save(const void *ip, const struct xt_entry_target *target)
202{
203	__RATEEST_print(target, "--rateest-");
204}
205
206static struct xtables_target rateest_target4 = {
207	.family		= AF_INET,
208	.name		= "RATEEST",
209	.version	= IPTABLES_VERSION,
210	.size		= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
211	.userspacesize	= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
212	.help		= RATEEST_help,
213	.init		= RATEEST_init,
214	.parse		= RATEEST_parse,
215	.final_check	= RATEEST_final_check,
216	.print		= RATEEST_print,
217	.save		= RATEEST_save,
218	.extra_opts	= RATEEST_opts,
219};
220
221static struct xtables_target rateest_target6 = {
222	.family		= AF_INET6,
223	.name		= "RATEEST",
224	.version	= IPTABLES_VERSION,
225	.size		= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
226	.userspacesize	= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
227	.help		= RATEEST_help,
228	.init		= RATEEST_init,
229	.parse		= RATEEST_parse,
230	.final_check	= RATEEST_final_check,
231	.print		= RATEEST_print,
232	.save		= RATEEST_save,
233	.extra_opts	= RATEEST_opts,
234};
235
236void _init(void)
237{
238	xtables_register_target(&rateest_target4);
239	xtables_register_target(&rateest_target6);
240}
241