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