libxt_rateest.c revision 0f16c725aadaac7e670d632ecbaea3661ff00827
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); 122 if (invert) 123 exit_error(PARAMETER_PROBLEM, 124 "rateest: rateest can't be inverted"); 125 126 if (*flags & (1 << c)) 127 exit_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); 136 if (invert) 137 exit_error(PARAMETER_PROBLEM, 138 "rateest: rateest can't be inverted"); 139 140 if (*flags & (1 << c)) 141 exit_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); 151 if (invert) 152 exit_error(PARAMETER_PROBLEM, 153 "rateest: rateest-bps can't be inverted"); 154 155 if (*flags & (1 << c)) 156 exit_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 exit_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); 175 if (invert) 176 exit_error(PARAMETER_PROBLEM, 177 "rateest: rateest-pps can't be inverted"); 178 179 if (*flags & (1 << c)) 180 exit_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 exit_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); 200 if (invert) 201 exit_error(PARAMETER_PROBLEM, 202 "rateest: rateest-bps can't be inverted"); 203 204 if (*flags & (1 << c)) 205 exit_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 exit_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); 224 if (invert) 225 exit_error(PARAMETER_PROBLEM, 226 "rateest: rateest-pps can't be inverted"); 227 228 if (*flags & (1 << c)) 229 exit_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 exit_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); 249 if (invert) 250 exit_error(PARAMETER_PROBLEM, 251 "rateest: rateest-delta can't be inverted"); 252 253 if (*flags & (1 << c)) 254 exit_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(argv[optind-1], &invert, &optind, 0); 263 264 if (*flags & (1 << c)) 265 exit_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(argv[optind-1], &invert, &optind, 0); 276 277 if (*flags & (1 << c)) 278 exit_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(argv[optind-1], &invert, &optind, 0); 289 290 if (*flags & (1 << c)) 291 exit_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 exit_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(struct xt_rateest_match_info *info, const char *prefix) 336{ 337 if (info->flags & XT_RATEEST_MATCH_INVERT) 338 printf("! "); 339 340 switch (info->mode) { 341 case XT_RATEEST_MATCH_EQ: 342 printf("%seq ", prefix); 343 break; 344 case XT_RATEEST_MATCH_LT: 345 printf("%slt ", prefix); 346 break; 347 case XT_RATEEST_MATCH_GT: 348 printf("%sgt ", prefix); 349 break; 350 default: 351 exit(1); 352 } 353} 354 355static void 356rateest_print(const void *ip, const struct xt_entry_match *match, int numeric) 357{ 358 struct xt_rateest_match_info *info = (void *)match->data; 359 360 printf("rateest match "); 361 362 printf("%s ", info->name1); 363 if (info->flags & XT_RATEEST_MATCH_DELTA) 364 printf("delta "); 365 366 if (info->flags & XT_RATEEST_MATCH_BPS) { 367 printf("bps "); 368 if (info->flags & XT_RATEEST_MATCH_DELTA) 369 rateest_print_rate(info->bps1, numeric); 370 if (info->flags & XT_RATEEST_MATCH_ABS) { 371 rateest_print_mode(info, ""); 372 rateest_print_rate(info->bps2, numeric); 373 } 374 } 375 if (info->flags & XT_RATEEST_MATCH_PPS) { 376 printf("pps "); 377 if (info->flags & XT_RATEEST_MATCH_DELTA) 378 printf("%u ", info->pps1); 379 if (info->flags & XT_RATEEST_MATCH_ABS) { 380 rateest_print_mode(info, ""); 381 printf("%u ", info->pps2); 382 } 383 } 384 385 if (info->flags & XT_RATEEST_MATCH_REL) { 386 rateest_print_mode(info, ""); 387 388 printf("%s ", info->name2); 389 if (info->flags & XT_RATEEST_MATCH_DELTA) 390 printf("delta "); 391 392 if (info->flags & XT_RATEEST_MATCH_BPS) { 393 printf("bps "); 394 if (info->flags & XT_RATEEST_MATCH_DELTA) 395 rateest_print_rate(info->bps2, numeric); 396 } 397 if (info->flags & XT_RATEEST_MATCH_PPS) { 398 printf("pps "); 399 if (info->flags & XT_RATEEST_MATCH_DELTA) 400 printf("%u ", info->pps2); 401 } 402 } 403} 404 405static void 406rateest_save(const void *ip, const struct xt_entry_match *match) 407{ 408 struct xt_rateest_match_info *info = (void *)match->data; 409 410 if (info->flags & XT_RATEEST_MATCH_REL) { 411 printf("--rateest1 %s ", info->name1); 412 if (info->flags & XT_RATEEST_MATCH_BPS) 413 printf("--rateest-bps "); 414 if (info->flags & XT_RATEEST_MATCH_PPS) 415 printf("--rateest-pps "); 416 rateest_print_mode(info, "--rateest-"); 417 printf("--rateest2 %s ", info->name2); 418 } else { 419 printf("--rateest %s ", info->name1); 420 if (info->flags & XT_RATEEST_MATCH_BPS) { 421 printf("--rateest-bps "); 422 rateest_print_mode(info, "--rateest-"); 423 rateest_print_rate(info->bps2, 0); 424 } 425 if (info->flags & XT_RATEEST_MATCH_PPS) { 426 printf("--rateest-pps "); 427 rateest_print_mode(info, "--rateest-"); 428 printf("%u ", info->pps2); 429 } 430 } 431} 432 433static struct xtables_match rateest_mt_reg = { 434 .family = AF_UNSPEC, 435 .name = "rateest", 436 .version = XTABLES_VERSION, 437 .size = XT_ALIGN(sizeof(struct xt_rateest_match_info)), 438 .userspacesize = XT_ALIGN(offsetof(struct xt_rateest_match_info, est1)), 439 .help = rateest_help, 440 .parse = rateest_parse, 441 .final_check = rateest_final_check, 442 .print = rateest_print, 443 .save = rateest_save, 444 .extra_opts = rateest_opts, 445}; 446 447void _init(void) 448{ 449 xtables_register_match(&rateest_mt_reg); 450} 451