libxt_rateest.c revision bbe83862a5e1baf15f7c923352d4afdf59bc70e2
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 */ 11static struct xt_rateest_match_info *rateest_info; 12 13static 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 29enum 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 42static 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 */ 60static 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 85static int 86rateest_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 110static int 111rateest_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 unsigned int val; 116 117 rateest_info = info; 118 119 switch (c) { 120 case OPT_RATEEST1: 121 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 122 if (invert) 123 xtables_error(PARAMETER_PROBLEM, 124 "rateest: rateest can't be inverted"); 125 126 if (*flags & (1 << c)) 127 xtables_error(PARAMETER_PROBLEM, 128 "rateest: can't specify --rateest1 twice"); 129 *flags |= 1 << c; 130 131 strncpy(info->name1, optarg, sizeof(info->name1) - 1); 132 break; 133 134 case OPT_RATEEST2: 135 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 136 if (invert) 137 xtables_error(PARAMETER_PROBLEM, 138 "rateest: rateest can't be inverted"); 139 140 if (*flags & (1 << c)) 141 xtables_error(PARAMETER_PROBLEM, 142 "rateest: can't specify --rateest2 twice"); 143 *flags |= 1 << c; 144 145 strncpy(info->name2, optarg, sizeof(info->name2) - 1); 146 info->flags |= XT_RATEEST_MATCH_REL; 147 break; 148 149 case OPT_RATEEST_BPS1: 150 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 151 if (invert) 152 xtables_error(PARAMETER_PROBLEM, 153 "rateest: rateest-bps can't be inverted"); 154 155 if (*flags & (1 << c)) 156 xtables_error(PARAMETER_PROBLEM, 157 "rateest: can't specify --rateest-bps1 twice"); 158 *flags |= 1 << c; 159 160 info->flags |= XT_RATEEST_MATCH_BPS; 161 162 /* The rate is optional and only required in absolute mode */ 163 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!') 164 break; 165 166 if (rateest_get_rate(&info->bps1, argv[optind]) < 0) 167 xtables_error(PARAMETER_PROBLEM, 168 "rateest: could not parse rate `%s'", 169 argv[optind]); 170 optind++; 171 break; 172 173 case OPT_RATEEST_PPS1: 174 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 175 if (invert) 176 xtables_error(PARAMETER_PROBLEM, 177 "rateest: rateest-pps can't be inverted"); 178 179 if (*flags & (1 << c)) 180 xtables_error(PARAMETER_PROBLEM, 181 "rateest: can't specify --rateest-pps1 twice"); 182 *flags |= 1 << c; 183 184 info->flags |= XT_RATEEST_MATCH_PPS; 185 186 /* The rate is optional and only required in absolute mode */ 187 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!') 188 break; 189 190 if (!xtables_strtoui(argv[optind], NULL, &val, 0, UINT32_MAX)) 191 xtables_error(PARAMETER_PROBLEM, 192 "rateest: could not parse pps `%s'", 193 argv[optind]); 194 info->pps1 = val; 195 optind++; 196 break; 197 198 case OPT_RATEEST_BPS2: 199 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 200 if (invert) 201 xtables_error(PARAMETER_PROBLEM, 202 "rateest: rateest-bps can't be inverted"); 203 204 if (*flags & (1 << c)) 205 xtables_error(PARAMETER_PROBLEM, 206 "rateest: can't specify --rateest-bps2 twice"); 207 *flags |= 1 << c; 208 209 info->flags |= XT_RATEEST_MATCH_BPS; 210 211 /* The rate is optional and only required in absolute mode */ 212 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!') 213 break; 214 215 if (rateest_get_rate(&info->bps2, argv[optind]) < 0) 216 xtables_error(PARAMETER_PROBLEM, 217 "rateest: could not parse rate `%s'", 218 argv[optind]); 219 optind++; 220 break; 221 222 case OPT_RATEEST_PPS2: 223 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 224 if (invert) 225 xtables_error(PARAMETER_PROBLEM, 226 "rateest: rateest-pps can't be inverted"); 227 228 if (*flags & (1 << c)) 229 xtables_error(PARAMETER_PROBLEM, 230 "rateest: can't specify --rateest-pps2 twice"); 231 *flags |= 1 << c; 232 233 info->flags |= XT_RATEEST_MATCH_PPS; 234 235 /* The rate is optional and only required in absolute mode */ 236 if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!') 237 break; 238 239 if (!xtables_strtoui(argv[optind], NULL, &val, 0, UINT32_MAX)) 240 xtables_error(PARAMETER_PROBLEM, 241 "rateest: could not parse pps `%s'", 242 argv[optind]); 243 info->pps2 = val; 244 optind++; 245 break; 246 247 case OPT_RATEEST_DELTA: 248 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 249 if (invert) 250 xtables_error(PARAMETER_PROBLEM, 251 "rateest: rateest-delta can't be inverted"); 252 253 if (*flags & (1 << c)) 254 xtables_error(PARAMETER_PROBLEM, 255 "rateest: can't specify --rateest-delta twice"); 256 *flags |= 1 << c; 257 258 info->flags |= XT_RATEEST_MATCH_DELTA; 259 break; 260 261 case OPT_RATEEST_EQ: 262 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 263 264 if (*flags & (1 << c)) 265 xtables_error(PARAMETER_PROBLEM, 266 "rateest: can't specify lt/gt/eq twice"); 267 *flags |= 1 << c; 268 269 info->mode = XT_RATEEST_MATCH_EQ; 270 if (invert) 271 info->flags |= XT_RATEEST_MATCH_INVERT; 272 break; 273 274 case OPT_RATEEST_LT: 275 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 276 277 if (*flags & (1 << c)) 278 xtables_error(PARAMETER_PROBLEM, 279 "rateest: can't specify lt/gt/eq twice"); 280 *flags |= 1 << c; 281 282 info->mode = XT_RATEEST_MATCH_LT; 283 if (invert) 284 info->flags |= XT_RATEEST_MATCH_INVERT; 285 break; 286 287 case OPT_RATEEST_GT: 288 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 289 290 if (*flags & (1 << c)) 291 xtables_error(PARAMETER_PROBLEM, 292 "rateest: can't specify lt/gt/eq twice"); 293 *flags |= 1 << c; 294 295 info->mode = XT_RATEEST_MATCH_GT; 296 if (invert) 297 info->flags |= XT_RATEEST_MATCH_INVERT; 298 break; 299 300 default: 301 return 0; 302 } 303 304 return 1; 305} 306 307static void 308rateest_final_check(unsigned int flags) 309{ 310 struct xt_rateest_match_info *info = rateest_info; 311 312 if (info == NULL) 313 xtables_error(PARAMETER_PROBLEM, "rateest match: " 314 "you need to specify some flags"); 315 if (!(info->flags & XT_RATEEST_MATCH_REL)) 316 info->flags |= XT_RATEEST_MATCH_ABS; 317} 318 319static void 320rateest_print_rate(u_int32_t rate, int numeric) 321{ 322 double tmp = (double)rate*8; 323 324 if (numeric) 325 printf("%u ", rate); 326 else if (tmp >= 1000.0*1000000.0) 327 printf("%.0fMbit ", tmp/1000000.0); 328 else if (tmp >= 1000.0 * 1000.0) 329 printf("%.0fKbit ", tmp/1000.0); 330 else 331 printf("%.0fbit ", tmp); 332} 333 334static void 335rateest_print_mode(const struct xt_rateest_match_info *info, 336 const char *prefix) 337{ 338 if (info->flags & XT_RATEEST_MATCH_INVERT) 339 printf("! "); 340 341 switch (info->mode) { 342 case XT_RATEEST_MATCH_EQ: 343 printf("%seq ", prefix); 344 break; 345 case XT_RATEEST_MATCH_LT: 346 printf("%slt ", prefix); 347 break; 348 case XT_RATEEST_MATCH_GT: 349 printf("%sgt ", prefix); 350 break; 351 default: 352 exit(1); 353 } 354} 355 356static void 357rateest_print(const void *ip, const struct xt_entry_match *match, int numeric) 358{ 359 const struct xt_rateest_match_info *info = (const void *)match->data; 360 361 printf("rateest match "); 362 363 printf("%s ", info->name1); 364 if (info->flags & XT_RATEEST_MATCH_DELTA) 365 printf("delta "); 366 367 if (info->flags & XT_RATEEST_MATCH_BPS) { 368 printf("bps "); 369 if (info->flags & XT_RATEEST_MATCH_DELTA) 370 rateest_print_rate(info->bps1, numeric); 371 if (info->flags & XT_RATEEST_MATCH_ABS) { 372 rateest_print_mode(info, ""); 373 rateest_print_rate(info->bps2, numeric); 374 } 375 } 376 if (info->flags & XT_RATEEST_MATCH_PPS) { 377 printf("pps "); 378 if (info->flags & XT_RATEEST_MATCH_DELTA) 379 printf("%u ", info->pps1); 380 if (info->flags & XT_RATEEST_MATCH_ABS) { 381 rateest_print_mode(info, ""); 382 printf("%u ", info->pps2); 383 } 384 } 385 386 if (info->flags & XT_RATEEST_MATCH_REL) { 387 rateest_print_mode(info, ""); 388 389 printf("%s ", info->name2); 390 if (info->flags & XT_RATEEST_MATCH_DELTA) 391 printf("delta "); 392 393 if (info->flags & XT_RATEEST_MATCH_BPS) { 394 printf("bps "); 395 if (info->flags & XT_RATEEST_MATCH_DELTA) 396 rateest_print_rate(info->bps2, numeric); 397 } 398 if (info->flags & XT_RATEEST_MATCH_PPS) { 399 printf("pps "); 400 if (info->flags & XT_RATEEST_MATCH_DELTA) 401 printf("%u ", info->pps2); 402 } 403 } 404} 405 406static void 407rateest_save(const void *ip, const struct xt_entry_match *match) 408{ 409 const struct xt_rateest_match_info *info = (const void *)match->data; 410 411 if (info->flags & XT_RATEEST_MATCH_REL) { 412 printf("--rateest1 %s ", info->name1); 413 if (info->flags & XT_RATEEST_MATCH_BPS) 414 printf("--rateest-bps "); 415 if (info->flags & XT_RATEEST_MATCH_PPS) 416 printf("--rateest-pps "); 417 rateest_print_mode(info, "--rateest-"); 418 printf("--rateest2 %s ", info->name2); 419 } else { 420 printf("--rateest %s ", info->name1); 421 if (info->flags & XT_RATEEST_MATCH_BPS) { 422 printf("--rateest-bps "); 423 rateest_print_mode(info, "--rateest-"); 424 rateest_print_rate(info->bps2, 0); 425 } 426 if (info->flags & XT_RATEEST_MATCH_PPS) { 427 printf("--rateest-pps "); 428 rateest_print_mode(info, "--rateest-"); 429 printf("%u ", info->pps2); 430 } 431 } 432} 433 434static struct xtables_match rateest_mt_reg = { 435 .family = NFPROTO_UNSPEC, 436 .name = "rateest", 437 .version = XTABLES_VERSION, 438 .size = XT_ALIGN(sizeof(struct xt_rateest_match_info)), 439 .userspacesize = XT_ALIGN(offsetof(struct xt_rateest_match_info, est1)), 440 .help = rateest_help, 441 .parse = rateest_parse, 442 .final_check = rateest_final_check, 443 .print = rateest_print, 444 .save = rateest_save, 445 .extra_opts = rateest_opts, 446}; 447 448void _init(void) 449{ 450 xtables_register_match(&rateest_mt_reg); 451} 452