libxt_RATEEST.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdbool.h>
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stddef.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <getopt.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <math.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <xtables.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/netfilter/x_tables.h>
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <linux/netfilter/xt_RATEEST.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* hack to pass raw values to final_check */
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct xt_rateest_target_info *RATEEST_info;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned int interval;
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstatic unsigned int ewma_log;
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstatic void
19effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochRATEEST_help(void)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	printf(
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch"RATEEST target options:\n"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"  --rateest-name name		Rate estimator name\n"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"  --rateest-interval sec	Rate measurement interval in seconds\n"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"  --rateest-ewmalog value	Rate measurement averaging time constant\n");
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum RATEEST_options {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	RATEEST_OPT_NAME,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	RATEEST_OPT_INTERVAL,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	RATEEST_OPT_EWMALOG,
32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const struct option RATEEST_opts[] = {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{.name = "rateest-name",     .has_arg = true, .val = RATEEST_OPT_NAME},
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{.name = "rateest-interval", .has_arg = true, .val = RATEEST_OPT_INTERVAL},
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{.name = "rateest-ewmalog",  .has_arg = true, .val = RATEEST_OPT_EWMALOG},
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	XT_GETOPT_TABLEEND,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copied from iproute */
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TIME_UNITS_PER_SEC	1000000
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RATEEST_get_time(unsigned int *time, const char *str)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	double t;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *p;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	t = strtod(str, &p);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (p == str)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return -1;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (*p) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    strcasecmp(p, "secs")==0)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			t *= TIME_UNITS_PER_SEC;
58		else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
59			 strcasecmp(p, "msecs") == 0)
60			t *= TIME_UNITS_PER_SEC/1000;
61		else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
62			 strcasecmp(p, "usecs") == 0)
63			t *= TIME_UNITS_PER_SEC/1000000;
64		else
65			return -1;
66	}
67
68	*time = t;
69	return 0;
70}
71
72static void
73RATEEST_print_time(unsigned int time)
74{
75	double tmp = time;
76
77	if (tmp >= TIME_UNITS_PER_SEC)
78		printf(" %.1fs", tmp / TIME_UNITS_PER_SEC);
79	else if (tmp >= TIME_UNITS_PER_SEC/1000)
80		printf(" %.1fms", tmp / (TIME_UNITS_PER_SEC / 1000));
81	else
82		printf(" %uus", time);
83}
84
85static void
86RATEEST_init(struct xt_entry_target *target)
87{
88	interval = 0;
89	ewma_log = 0;
90}
91
92static int
93RATEEST_parse(int c, char **argv, int invert, unsigned int *flags,
94	      const void *entry, struct xt_entry_target **target)
95{
96	struct xt_rateest_target_info *info = (void *)(*target)->data;
97
98	RATEEST_info = info;
99
100	switch (c) {
101	case RATEEST_OPT_NAME:
102		if (*flags & (1 << c))
103			xtables_error(PARAMETER_PROBLEM,
104				   "RATEEST: can't specify --rateest-name twice");
105		*flags |= 1 << c;
106
107		strncpy(info->name, optarg, sizeof(info->name) - 1);
108		break;
109
110	case RATEEST_OPT_INTERVAL:
111		if (*flags & (1 << c))
112			xtables_error(PARAMETER_PROBLEM,
113				   "RATEEST: can't specify --rateest-interval twice");
114		*flags |= 1 << c;
115
116		if (RATEEST_get_time(&interval, optarg) < 0)
117			xtables_error(PARAMETER_PROBLEM,
118				   "RATEEST: bad interval value `%s'", optarg);
119
120		break;
121
122	case RATEEST_OPT_EWMALOG:
123		if (*flags & (1 << c))
124			xtables_error(PARAMETER_PROBLEM,
125				   "RATEEST: can't specify --rateest-ewmalog twice");
126		*flags |= 1 << c;
127
128		if (RATEEST_get_time(&ewma_log, optarg) < 0)
129			xtables_error(PARAMETER_PROBLEM,
130				   "RATEEST: bad ewmalog value `%s'", optarg);
131
132		break;
133	}
134
135	return 1;
136}
137
138static void
139RATEEST_final_check(unsigned int flags)
140{
141	struct xt_rateest_target_info *info = RATEEST_info;
142
143	if (!(flags & (1 << RATEEST_OPT_NAME)))
144		xtables_error(PARAMETER_PROBLEM, "RATEEST: no name specified");
145	if (!(flags & (1 << RATEEST_OPT_INTERVAL)))
146		xtables_error(PARAMETER_PROBLEM, "RATEEST: no interval specified");
147	if (!(flags & (1 << RATEEST_OPT_EWMALOG)))
148		xtables_error(PARAMETER_PROBLEM, "RATEEST: no ewmalog specified");
149
150	for (info->interval = 0; info->interval <= 5; info->interval++) {
151		if (interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4))
152			break;
153	}
154
155	if (info->interval > 5)
156		xtables_error(PARAMETER_PROBLEM,
157			   "RATEEST: interval value is too large");
158	info->interval -= 2;
159
160	for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) {
161		double w = 1.0 - 1.0 / (1 << info->ewma_log);
162		if (interval / (-log(w)) > ewma_log)
163			break;
164	}
165	info->ewma_log--;
166
167	if (info->ewma_log == 0 || info->ewma_log >= 31)
168		xtables_error(PARAMETER_PROBLEM,
169			   "RATEEST: ewmalog value is out of range");
170}
171
172static void
173__RATEEST_print(const struct xt_entry_target *target, const char *prefix)
174{
175	const struct xt_rateest_target_info *info = (const void *)target->data;
176	unsigned int local_interval;
177	unsigned int local_ewma_log;
178
179	local_interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4;
180	local_ewma_log = local_interval * (1 << (info->ewma_log));
181
182	printf(" %sname %s", prefix, info->name);
183	printf(" %sinterval", prefix);
184	RATEEST_print_time(local_interval);
185	printf(" %sewmalog", prefix);
186	RATEEST_print_time(local_ewma_log);
187}
188
189static void
190RATEEST_print(const void *ip, const struct xt_entry_target *target,
191	      int numeric)
192{
193	__RATEEST_print(target, "");
194}
195
196static void
197RATEEST_save(const void *ip, const struct xt_entry_target *target)
198{
199	__RATEEST_print(target, "--rateest-");
200}
201
202static struct xtables_target rateest_tg_reg = {
203	.family		= NFPROTO_UNSPEC,
204	.name		= "RATEEST",
205	.version	= XTABLES_VERSION,
206	.size		= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
207	.userspacesize	= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
208	.help		= RATEEST_help,
209	.init		= RATEEST_init,
210	.parse		= RATEEST_parse,
211	.final_check	= RATEEST_final_check,
212	.print		= RATEEST_print,
213	.save		= RATEEST_save,
214	.extra_opts	= RATEEST_opts,
215};
216
217void _init(void)
218{
219	xtables_register_target(&rateest_tg_reg);
220}
221