changing trunk/trunk to trunk
[iptables.git] / extensions / libxt_RATEEST.c
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 */
13 static struct xt_rateest_target_info *RATEEST_info;
14 static unsigned int interval;
15 static unsigned int ewma_log;
16
17 static void
18 RATEEST_help(void)
19 {
20         printf(
21 "RATEEST target 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 }
26
27 enum RATEEST_options {
28         RATEEST_OPT_NAME,
29         RATEEST_OPT_INTERVAL,
30         RATEEST_OPT_EWMALOG,
31 };
32
33 static 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 },
37         { .name = NULL },
38 };
39
40 /* Copied from iproute */
41 #define TIME_UNITS_PER_SEC      1000000
42
43 static int
44 RATEEST_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
71 static void
72 RATEEST_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
84 static void
85 RATEEST_init(struct xt_entry_target *target)
86 {
87         interval = 0;
88         ewma_log = 0;
89 }
90
91 static int
92 RATEEST_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
140 static void
141 RATEEST_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
174 static void
175 __RATEEST_print(const struct xt_entry_target *target, const char *prefix)
176 {
177         struct xt_rateest_target_info *info = (void *)target->data;
178         unsigned int local_interval;
179         unsigned int local_ewma_log;
180
181         local_interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4;
182         local_ewma_log = local_interval * (1 << (info->ewma_log));
183
184         printf("%sname %s ", prefix, info->name);
185         printf("%sinterval ", prefix);
186         RATEEST_print_time(local_interval);
187         printf("%sewmalog ", prefix);
188         RATEEST_print_time(local_ewma_log);
189 }
190
191 static void
192 RATEEST_print(const void *ip, const struct xt_entry_target *target,
193               int numeric)
194 {
195         __RATEEST_print(target, "");
196 }
197
198 static void
199 RATEEST_save(const void *ip, const struct xt_entry_target *target)
200 {
201         __RATEEST_print(target, "--rateest-");
202 }
203
204 static struct xtables_target rateest_tg_reg = {
205         .family         = AF_UNSPEC,
206         .name           = "RATEEST",
207         .version        = XTABLES_VERSION,
208         .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
219 void _init(void)
220 {
221         xtables_register_target(&rateest_tg_reg);
222 }