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
7 #include <xtables.h>
8 #include <linux/netfilter/xt_rateest.h>
9
10 /* Ugly hack to pass info to final_check function. We should fix the API */
11 static struct xt_rateest_match_info *rateest_info;
12
13 static void rateest_help(void)
14 {
15         printf(
16 "rateest match options:\n"
17 " --rateest1 name               Rate estimator name\n"
18 " --rateest2 name               Rate estimator name\n"
19 " --rateest-delta               Compare difference(s) to given rate(s)\n"
20 " --rateest-bps1 [bps]          Compare bps\n"
21 " --rateest-pps1 [pps]          Compare pps\n"
22 " --rateest-bps2 [bps]          Compare bps\n"
23 " --rateest-pps2 [pps]          Compare pps\n"
24 " [!] --rateest-lt              Match if rate is less than given rate/estimator\n"
25 " [!] --rateest-gt              Match if rate is greater than given rate/estimator\n"
26 " [!] --rateest-eq              Match if rate is equal to given rate/estimator\n");
27 }
28
29 enum rateest_options {
30         OPT_RATEEST1,
31         OPT_RATEEST2,
32         OPT_RATEEST_BPS1,
33         OPT_RATEEST_PPS1,
34         OPT_RATEEST_BPS2,
35         OPT_RATEEST_PPS2,
36         OPT_RATEEST_DELTA,
37         OPT_RATEEST_LT,
38         OPT_RATEEST_GT,
39         OPT_RATEEST_EQ,
40 };
41
42 static const struct option rateest_opts[] = {
43         { "rateest1",           1, NULL, OPT_RATEEST1 },
44         { "rateest",            1, NULL, OPT_RATEEST1 }, /* alias for absolute mode */
45         { "rateest2",           1, NULL, OPT_RATEEST2 },
46         { "rateest-bps1",       0, NULL, OPT_RATEEST_BPS1 },
47         { "rateest-pps1",       0, NULL, OPT_RATEEST_PPS1 },
48         { "rateest-bps2",       0, NULL, OPT_RATEEST_BPS2 },
49         { "rateest-pps2",       0, NULL, OPT_RATEEST_PPS2 },
50         { "rateest-bps",        0, NULL, OPT_RATEEST_BPS2 }, /* alias for absolute mode */
51         { "rateest-pps",        0, NULL, OPT_RATEEST_PPS2 }, /* alias for absolute mode */
52         { "rateest-delta",      0, NULL, OPT_RATEEST_DELTA },
53         { "rateest-lt",         0, NULL, OPT_RATEEST_LT },
54         { "rateest-gt",         0, NULL, OPT_RATEEST_GT },
55         { "rateest-eq",         0, NULL, OPT_RATEEST_EQ },
56         { .name = NULL }
57 };
58
59 /* Copied from iproute. See http://physics.nist.gov/cuu/Units/binary.html */
60 static const struct rate_suffix {
61         const char *name;
62         double scale;
63 } suffixes[] = {
64         { "bit",        1. },
65         { "Kibit",      1024. },
66         { "kbit",       1000. },
67         { "mibit",      1024.*1024. },
68         { "mbit",       1000000. },
69         { "gibit",      1024.*1024.*1024. },
70         { "gbit",       1000000000. },
71         { "tibit",      1024.*1024.*1024.*1024. },
72         { "tbit",       1000000000000. },
73         { "Bps",        8. },
74         { "KiBps",      8.*1024. },
75         { "KBps",       8000. },
76         { "MiBps",      8.*1024*1024. },
77         { "MBps",       8000000. },
78         { "GiBps",      8.*1024.*1024.*1024. },
79         { "GBps",       8000000000. },
80         { "TiBps",      8.*1024.*1024.*1024.*1024. },
81         { "TBps",       8000000000000. },
82         { .name = NULL }
83 };
84
85 static int
86 rateest_get_rate(u_int32_t *rate, const char *str)
87 {
88         char *p;
89         double bps = strtod(str, &p);
90         const struct rate_suffix *s;
91
92         if (p == str)
93                 return -1;
94
95         if (*p == '\0') {
96                 *rate = bps / 8.;       /* assume bytes/sec */
97                 return 0;
98         }
99
100         for (s = suffixes; s->name; ++s) {
101                 if (strcasecmp(s->name, p) == 0) {
102                         *rate = (bps * s->scale) / 8.;
103                         return 0;
104                 }
105         }
106
107         return -1;
108 }
109
110 static int
111 rateest_parse(int c, char **argv, int invert, unsigned int *flags,
112               const void *entry, struct xt_entry_match **match)
113 {
114         struct xt_rateest_match_info *info = (void *)(*match)->data;
115
116         rateest_info = info;
117
118         switch (c) {
119         case OPT_RATEEST1:
120                 check_inverse(optarg, &invert, &optind, 0);
121                 if (invert)
122                         exit_error(PARAMETER_PROBLEM,
123                                    "rateest: rateest can't be inverted");
124
125                 if (*flags & (1 << c))
126                         exit_error(PARAMETER_PROBLEM,
127                                    "rateest: can't specify --rateest1 twice");
128                 *flags |= 1 << c;
129
130                 strncpy(info->name1, optarg, sizeof(info->name1) - 1);
131                 break;
132
133         case OPT_RATEEST2:
134                 check_inverse(optarg, &invert, &optind, 0);
135                 if (invert)
136                         exit_error(PARAMETER_PROBLEM,
137                                    "rateest: rateest can't be inverted");
138
139                 if (*flags & (1 << c))
140                         exit_error(PARAMETER_PROBLEM,
141                                    "rateest: can't specify --rateest2 twice");
142                 *flags |= 1 << c;
143
144                 strncpy(info->name2, optarg, sizeof(info->name2) - 1);
145                 info->flags |= XT_RATEEST_MATCH_REL;
146                 break;
147
148         case OPT_RATEEST_BPS1:
149                 check_inverse(optarg, &invert, &optind, 0);
150                 if (invert)
151                         exit_error(PARAMETER_PROBLEM,
152                                    "rateest: rateest-bps can't be inverted");
153
154                 if (*flags & (1 << c))
155                         exit_error(PARAMETER_PROBLEM,
156                                    "rateest: can't specify --rateest-bps1 twice");
157                 *flags |= 1 << c;
158
159                 info->flags |= XT_RATEEST_MATCH_BPS;
160
161                 /* The rate is optional and only required in absolute mode */
162                 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!')
163                         break;
164
165                 if (rateest_get_rate(&info->bps1, argv[optind]) < 0)
166                         exit_error(PARAMETER_PROBLEM,
167                                    "rateest: could not parse rate `%s'",
168                                    argv[optind]);
169                 optind++;
170                 break;
171
172         case OPT_RATEEST_PPS1:
173                 check_inverse(optarg, &invert, &optind, 0);
174                 if (invert)
175                         exit_error(PARAMETER_PROBLEM,
176                                    "rateest: rateest-pps can't be inverted");
177
178                 if (*flags & (1 << c))
179                         exit_error(PARAMETER_PROBLEM,
180                                    "rateest: can't specify --rateest-pps1 twice");
181                 *flags |= 1 << c;
182
183                 info->flags |= XT_RATEEST_MATCH_PPS;
184
185                 /* The rate is optional and only required in absolute mode */
186                 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!')
187                         break;
188
189                 if (string_to_number(argv[optind], 0, 0, &info->pps1) < 0)
190                         exit_error(PARAMETER_PROBLEM,
191                                    "rateest: could not parse pps `%s'",
192                                    argv[optind]);
193                 optind++;
194                 break;
195
196         case OPT_RATEEST_BPS2:
197                 check_inverse(optarg, &invert, &optind, 0);
198                 if (invert)
199                         exit_error(PARAMETER_PROBLEM,
200                                    "rateest: rateest-bps can't be inverted");
201
202                 if (*flags & (1 << c))
203                         exit_error(PARAMETER_PROBLEM,
204                                    "rateest: can't specify --rateest-bps2 twice");
205                 *flags |= 1 << c;
206
207                 info->flags |= XT_RATEEST_MATCH_BPS;
208
209                 /* The rate is optional and only required in absolute mode */
210                 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!')
211                         break;
212
213                 if (rateest_get_rate(&info->bps2, argv[optind]) < 0)
214                         exit_error(PARAMETER_PROBLEM,
215                                    "rateest: could not parse rate `%s'",
216                                    argv[optind]);
217                 optind++;
218                 break;
219
220         case OPT_RATEEST_PPS2:
221                 check_inverse(optarg, &invert, &optind, 0);
222                 if (invert)
223                         exit_error(PARAMETER_PROBLEM,
224                                    "rateest: rateest-pps can't be inverted");
225
226                 if (*flags & (1 << c))
227                         exit_error(PARAMETER_PROBLEM,
228                                    "rateest: can't specify --rateest-pps2 twice");
229                 *flags |= 1 << c;
230
231                 info->flags |= XT_RATEEST_MATCH_PPS;
232
233                 /* The rate is optional and only required in absolute mode */
234                 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!')
235                         break;
236
237                 if (string_to_number(argv[optind], 0, 0, &info->pps2) < 0)
238                         exit_error(PARAMETER_PROBLEM,
239                                    "rateest: could not parse pps `%s'",
240                                    argv[optind]);
241                 optind++;
242                 break;
243
244         case OPT_RATEEST_DELTA:
245                 check_inverse(optarg, &invert, &optind, 0);
246                 if (invert)
247                         exit_error(PARAMETER_PROBLEM,
248                                    "rateest: rateest-delta can't be inverted");
249
250                 if (*flags & (1 << c))
251                         exit_error(PARAMETER_PROBLEM,
252                                    "rateest: can't specify --rateest-delta twice");
253                 *flags |= 1 << c;
254
255                 info->flags |= XT_RATEEST_MATCH_DELTA;
256                 break;
257
258         case OPT_RATEEST_EQ:
259                 check_inverse(argv[optind-1], &invert, &optind, 0);
260
261                 if (*flags & (1 << c))
262                         exit_error(PARAMETER_PROBLEM,
263                                    "rateest: can't specify lt/gt/eq twice");
264                 *flags |= 1 << c;
265
266                 info->mode = XT_RATEEST_MATCH_EQ;
267                 if (invert)
268                         info->flags |= XT_RATEEST_MATCH_INVERT;
269                 break;
270
271         case OPT_RATEEST_LT:
272                 check_inverse(argv[optind-1], &invert, &optind, 0);
273
274                 if (*flags & (1 << c))
275                         exit_error(PARAMETER_PROBLEM,
276                                    "rateest: can't specify lt/gt/eq twice");
277                 *flags |= 1 << c;
278
279                 info->mode = XT_RATEEST_MATCH_LT;
280                 if (invert)
281                         info->flags |= XT_RATEEST_MATCH_INVERT;
282                 break;
283
284         case OPT_RATEEST_GT:
285                 check_inverse(argv[optind-1], &invert, &optind, 0);
286
287                 if (*flags & (1 << c))
288                         exit_error(PARAMETER_PROBLEM,
289                                    "rateest: can't specify lt/gt/eq twice");
290                 *flags |= 1 << c;
291
292                 info->mode = XT_RATEEST_MATCH_GT;
293                 if (invert)
294                         info->flags |= XT_RATEEST_MATCH_INVERT;
295                 break;
296
297         default:
298                 return 0;
299         }
300
301         return 1;
302 }
303
304 static void
305 rateest_final_check(unsigned int flags)
306 {
307         struct xt_rateest_match_info *info = rateest_info;
308
309         if (!(info->flags & XT_RATEEST_MATCH_REL))
310                 info->flags |= XT_RATEEST_MATCH_ABS;
311 }
312
313 static void
314 rateest_print_rate(u_int32_t rate, int numeric)
315 {
316         double tmp = (double)rate*8;
317
318         if (numeric)
319                 printf("%u ", rate);
320         else if (tmp >= 1000.0*1000000.0)
321                 printf("%.0fMbit ", tmp/1000000.0);
322         else if (tmp >= 1000.0 * 1000.0)
323                 printf("%.0fKbit ", tmp/1000.0);
324         else
325                 printf("%.0fbit ", tmp);
326 }
327
328 static void
329 rateest_print_mode(struct xt_rateest_match_info *info, const char *prefix)
330 {
331         if (info->flags & XT_RATEEST_MATCH_INVERT)
332                 printf("! ");
333
334         switch (info->mode) {
335         case XT_RATEEST_MATCH_EQ:
336                 printf("%seq ", prefix);
337                 break;
338         case XT_RATEEST_MATCH_LT:
339                 printf("%slt ", prefix);
340                 break;
341         case XT_RATEEST_MATCH_GT:
342                 printf("%sgt ", prefix);
343                 break;
344         default:
345                 exit(1);
346         }
347 }
348
349 static void
350 rateest_print(const void *ip, const struct xt_entry_match *match, int numeric)
351 {
352         struct xt_rateest_match_info *info = (void *)match->data;
353
354         printf("rateest match ");
355
356         printf("%s ", info->name1);
357         if (info->flags & XT_RATEEST_MATCH_DELTA)
358                 printf("delta ");
359
360         if (info->flags & XT_RATEEST_MATCH_BPS) {
361                 printf("bps ");
362                 if (info->flags & XT_RATEEST_MATCH_DELTA)
363                         rateest_print_rate(info->bps1, numeric);
364                 if (info->flags & XT_RATEEST_MATCH_ABS) {
365                         rateest_print_mode(info, "");
366                         rateest_print_rate(info->bps2, numeric);
367                 }
368         }
369         if (info->flags & XT_RATEEST_MATCH_PPS) {
370                 printf("pps ");
371                 if (info->flags & XT_RATEEST_MATCH_DELTA)
372                         printf("%u ", info->pps1);
373                 if (info->flags & XT_RATEEST_MATCH_ABS) {
374                         rateest_print_mode(info, "");
375                         printf("%u ", info->pps2);
376                 }
377         }
378
379         if (info->flags & XT_RATEEST_MATCH_REL) {
380                 rateest_print_mode(info, "");
381
382                 printf("%s ", info->name2);
383                 if (info->flags & XT_RATEEST_MATCH_DELTA)
384                         printf("delta ");
385
386                 if (info->flags & XT_RATEEST_MATCH_BPS) {
387                         printf("bps ");
388                         if (info->flags & XT_RATEEST_MATCH_DELTA)
389                                 rateest_print_rate(info->bps2, numeric);
390                 }
391                 if (info->flags & XT_RATEEST_MATCH_PPS) {
392                         printf("pps ");
393                         if (info->flags & XT_RATEEST_MATCH_DELTA)
394                                 printf("%u ", info->pps2);
395                 }
396         }
397 }
398
399 static void
400 rateest_save(const void *ip, const struct xt_entry_match *match)
401 {
402         struct xt_rateest_match_info *info = (void *)match->data;
403
404         if (info->flags & XT_RATEEST_MATCH_REL) {
405                 printf("--rateest1 %s ", info->name1);
406                 if (info->flags & XT_RATEEST_MATCH_BPS)
407                         printf("--rateest-bps ");
408                 if (info->flags & XT_RATEEST_MATCH_PPS)
409                         printf("--rateest-pps ");
410                 rateest_print_mode(info, "--rateest-");
411                 printf("--rateest2 %s ", info->name2);
412         } else {
413                 printf("--rateest %s ", info->name1);
414                 if (info->flags & XT_RATEEST_MATCH_BPS) {
415                         printf("--rateest-bps ");
416                         rateest_print_mode(info, "--rateest-");
417                         rateest_print_rate(info->bps2, 0);
418                 }
419                 if (info->flags & XT_RATEEST_MATCH_PPS) {
420                         printf("--rateest-pps ");
421                         rateest_print_mode(info, "--rateest-");
422                         printf("%u ", info->pps2);
423                 }
424         }
425 }
426
427 static struct xtables_match rateest_mt_reg = {
428         .family         = AF_UNSPEC,
429         .name           = "rateest",
430         .version        = XTABLES_VERSION,
431         .size           = XT_ALIGN(sizeof(struct xt_rateest_match_info)),
432         .userspacesize  = XT_ALIGN(offsetof(struct xt_rateest_match_info, est1)),
433         .help           = rateest_help,
434         .parse          = rateest_parse,
435         .final_check    = rateest_final_check,
436         .print          = rateest_print,
437         .save           = rateest_save,
438         .extra_opts     = rateest_opts,
439 };
440
441 void _init(void)
442 {
443         xtables_register_match(&rateest_mt_reg);
444 }