blob: cf1284f054e1d7bc9d51b610c3acbac5bf328473 [file] [log] [blame]
Patrick McHardy25282582008-01-15 17:25:39 +00001#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(
Jan Engelhardtbce1c212008-03-27 05:48:14 +010021"RATEEST target options:\n"
Patrick McHardy25282582008-01-15 17:25:39 +000022" --rateest-name name Rate estimator name\n"
23" --rateest-interval sec Rate measurement interval in seconds\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020024" --rateest-ewmalog value Rate measurement averaging time constant\n");
Patrick McHardy25282582008-01-15 17:25:39 +000025}
26
27enum RATEEST_options {
28 RATEEST_OPT_NAME,
29 RATEEST_OPT_INTERVAL,
30 RATEEST_OPT_EWMALOG,
31};
32
33static const struct option RATEEST_opts[] = {
34 { "rateest-name", 1, NULL, RATEEST_OPT_NAME },
35 { "rateest-interval", 1, NULL, RATEEST_OPT_INTERVAL },
36 { "rateest-ewmalog", 1, NULL, RATEEST_OPT_EWMALOG },
Max Kellermann9ee386a2008-01-29 13:48:05 +000037 { .name = NULL },
Patrick McHardy25282582008-01-15 17:25:39 +000038};
39
40/* Copied from iproute */
41#define TIME_UNITS_PER_SEC 1000000
42
43static int
44RATEEST_get_time(unsigned int *time, const char *str)
45{
46 double t;
47 char *p;
48
49 t = strtod(str, &p);
50 if (p == str)
51 return -1;
52
53 if (*p) {
54 if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
55 strcasecmp(p, "secs")==0)
56 t *= TIME_UNITS_PER_SEC;
57 else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
58 strcasecmp(p, "msecs") == 0)
59 t *= TIME_UNITS_PER_SEC/1000;
60 else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
61 strcasecmp(p, "usecs") == 0)
62 t *= TIME_UNITS_PER_SEC/1000000;
63 else
64 return -1;
65 }
66
67 *time = t;
68 return 0;
69}
70
71static void
72RATEEST_print_time(unsigned int time)
73{
74 double tmp = time;
75
76 if (tmp >= TIME_UNITS_PER_SEC)
77 printf("%.1fs ", tmp/TIME_UNITS_PER_SEC);
78 else if (tmp >= TIME_UNITS_PER_SEC/1000)
79 printf("%.1fms ", tmp/(TIME_UNITS_PER_SEC/1000));
80 else
81 printf("%uus ", time);
82}
83
84static void
85RATEEST_init(struct xt_entry_target *target)
86{
87 interval = 0;
88 ewma_log = 0;
89}
90
91static int
92RATEEST_parse(int c, char **argv, int invert, unsigned int *flags,
93 const void *entry, struct xt_entry_target **target)
94{
95 struct xt_rateest_target_info *info = (void *)(*target)->data;
96
97 RATEEST_info = info;
98
99 switch (c) {
100 case RATEEST_OPT_NAME:
101 if (*flags & (1 << c))
102 exit_error(PARAMETER_PROBLEM,
103 "RATEEST: can't specify --rateest-name twice");
104 *flags |= 1 << c;
105
106 strncpy(info->name, optarg, sizeof(info->name) - 1);
107 break;
108
109 case RATEEST_OPT_INTERVAL:
110 if (*flags & (1 << c))
111 exit_error(PARAMETER_PROBLEM,
112 "RATEEST: can't specify --rateest-interval twice");
113 *flags |= 1 << c;
114
115 if (RATEEST_get_time(&interval, optarg) < 0)
116 exit_error(PARAMETER_PROBLEM,
117 "RATEEST: bad interval value `%s'", optarg);
118
119 break;
120
121 case RATEEST_OPT_EWMALOG:
122 if (*flags & (1 << c))
123 exit_error(PARAMETER_PROBLEM,
124 "RATEEST: can't specify --rateest-ewmalog twice");
125 *flags |= 1 << c;
126
127 if (RATEEST_get_time(&ewma_log, optarg) < 0)
128 exit_error(PARAMETER_PROBLEM,
129 "RATEEST: bad ewmalog value `%s'", optarg);
130
131 break;
132
133 default:
134 return 0;
135 }
136
137 return 1;
138}
139
140static void
141RATEEST_final_check(unsigned int flags)
142{
143 struct xt_rateest_target_info *info = RATEEST_info;
144
145 if (!(flags & (1 << RATEEST_OPT_NAME)))
146 exit_error(PARAMETER_PROBLEM, "RATEEST: no name specified");
147 if (!(flags & (1 << RATEEST_OPT_INTERVAL)))
148 exit_error(PARAMETER_PROBLEM, "RATEEST: no interval specified");
149 if (!(flags & (1 << RATEEST_OPT_EWMALOG)))
150 exit_error(PARAMETER_PROBLEM, "RATEEST: no ewmalog specified");
151
152 for (info->interval = 0; info->interval <= 5; info->interval++) {
153 if (interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4))
154 break;
155 }
156
157 if (info->interval > 5)
158 exit_error(PARAMETER_PROBLEM,
159 "RATEEST: interval value is too large");
160 info->interval -= 2;
161
162 for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) {
163 double w = 1.0 - 1.0 / (1 << info->ewma_log);
164 if (interval / (-log(w)) > ewma_log)
165 break;
166 }
167 info->ewma_log--;
168
169 if (info->ewma_log == 0 || info->ewma_log >= 31)
170 exit_error(PARAMETER_PROBLEM,
171 "RATEEST: ewmalog value is out of range");
172}
173
174static void
175__RATEEST_print(const struct xt_entry_target *target, const char *prefix)
176{
177 struct xt_rateest_target_info *info = (void *)target->data;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100178 unsigned int local_interval;
179 unsigned int local_ewma_log;
Patrick McHardy25282582008-01-15 17:25:39 +0000180
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100181 local_interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4;
182 local_ewma_log = local_interval * (1 << (info->ewma_log));
Patrick McHardy25282582008-01-15 17:25:39 +0000183
184 printf("%sname %s ", prefix, info->name);
185 printf("%sinterval ", prefix);
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100186 RATEEST_print_time(local_interval);
Patrick McHardy25282582008-01-15 17:25:39 +0000187 printf("%sewmalog ", prefix);
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100188 RATEEST_print_time(local_ewma_log);
Patrick McHardy25282582008-01-15 17:25:39 +0000189}
190
191static void
192RATEEST_print(const void *ip, const struct xt_entry_target *target,
193 int numeric)
194{
195 __RATEEST_print(target, "");
196}
197
198static void
199RATEEST_save(const void *ip, const struct xt_entry_target *target)
200{
201 __RATEEST_print(target, "--rateest-");
202}
203
Jan Engelhardt23545c22008-02-14 04:23:04 +0100204static struct xtables_target rateest_tg_reg = {
205 .family = AF_UNSPEC,
Patrick McHardy25282582008-01-15 17:25:39 +0000206 .name = "RATEEST",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200207 .version = XTABLES_VERSION,
Patrick McHardy25282582008-01-15 17:25:39 +0000208 .size = XT_ALIGN(sizeof(struct xt_rateest_target_info)),
209 .userspacesize = XT_ALIGN(sizeof(struct xt_rateest_target_info)),
210 .help = RATEEST_help,
211 .init = RATEEST_init,
212 .parse = RATEEST_parse,
213 .final_check = RATEEST_final_check,
214 .print = RATEEST_print,
215 .save = RATEEST_save,
216 .extra_opts = RATEEST_opts,
217};
218
219void _init(void)
220{
Jan Engelhardt23545c22008-02-14 04:23:04 +0100221 xtables_register_target(&rateest_tg_reg);
Patrick McHardy25282582008-01-15 17:25:39 +0000222}