1 /* 2 * q_netem.c NETEM. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Stephen Hemminger <shemminger (at) linux-foundation.org> 10 * 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <math.h> 16 #include <ctype.h> 17 #include <unistd.h> 18 #include <syslog.h> 19 #include <fcntl.h> 20 #include <sys/socket.h> 21 #include <netinet/in.h> 22 #include <arpa/inet.h> 23 #include <string.h> 24 #include <errno.h> 25 26 #include "utils.h" 27 #include "tc_util.h" 28 #include "tc_common.h" 29 30 static void explain(void) 31 { 32 fprintf(stderr, 33 "Usage: ... netem [ limit PACKETS ] \n" \ 34 " [ delay TIME [ JITTER [CORRELATION]]]\n" \ 35 " [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ 36 " [ corrupt PERCENT [CORRELATION]] \n" \ 37 " [ duplicate PERCENT [CORRELATION]]\n" \ 38 " [ loss random PERCENT [CORRELATION]]\n" \ 39 " [ loss state P13 [P31 [P32 [P23 P14]]]\n" \ 40 " [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \ 41 " [ ecn ]\n" \ 42 " [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \ 43 " [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n"); 44 } 45 46 static void explain1(const char *arg) 47 { 48 fprintf(stderr, "Illegal \"%s\"\n", arg); 49 } 50 51 /* Upper bound on size of distribution 52 * really (TCA_BUF_MAX - other headers) / sizeof (__s16) 53 */ 54 #define MAX_DIST (16*1024) 55 56 static const double max_percent_value = 0xffffffff; 57 58 /* scaled value used to percent of maximum. */ 59 static void set_percent(__u32 *percent, double per) 60 { 61 *percent = (unsigned) rint(per * max_percent_value); 62 } 63 64 65 /* Parse either a fraction '.3' or percent '30% 66 * return: 0 = ok, -1 = error, 1 = out of range 67 */ 68 static int parse_percent(double *val, const char *str) 69 { 70 char *p; 71 72 *val = strtod(str, &p) / 100.; 73 if (*p && strcmp(p, "%") ) 74 return -1; 75 76 return 0; 77 } 78 79 static int get_percent(__u32 *percent, const char *str) 80 { 81 double per; 82 83 if (parse_percent(&per, str)) 84 return -1; 85 86 set_percent(percent, per); 87 return 0; 88 } 89 90 static void print_percent(char *buf, int len, __u32 per) 91 { 92 snprintf(buf, len, "%g%%", 100. * (double) per / max_percent_value); 93 } 94 95 static char * sprint_percent(__u32 per, char *buf) 96 { 97 print_percent(buf, SPRINT_BSIZE-1, per); 98 return buf; 99 } 100 101 /* 102 * Simplistic file parser for distrbution data. 103 * Format is: 104 * # comment line(s) 105 * data0 data1 ... 106 */ 107 static int get_distribution(const char *type, __s16 *data, int maxdata) 108 { 109 FILE *f; 110 int n; 111 long x; 112 size_t len; 113 char *line = NULL; 114 char name[128]; 115 116 snprintf(name, sizeof(name), "%s/%s.dist", get_tc_lib(), type); 117 if ((f = fopen(name, "r")) == NULL) { 118 fprintf(stderr, "No distribution data for %s (%s: %s)\n", 119 type, name, strerror(errno)); 120 return -1; 121 } 122 123 n = 0; 124 while (getline(&line, &len, f) != -1) { 125 char *p, *endp; 126 if (*line == '\n' || *line == '#') 127 continue; 128 129 for (p = line; ; p = endp) { 130 x = strtol(p, &endp, 0); 131 if (endp == p) 132 break; 133 134 if (n >= maxdata) { 135 fprintf(stderr, "%s: too much data\n", 136 name); 137 n = -1; 138 goto error; 139 } 140 data[n++] = x; 141 } 142 } 143 error: 144 free(line); 145 fclose(f); 146 return n; 147 } 148 149 #define NEXT_IS_NUMBER() (NEXT_ARG_OK() && isdigit(argv[1][0])) 150 #define NEXT_IS_SIGNED_NUMBER() \ 151 (NEXT_ARG_OK() && (isdigit(argv[1][0]) || argv[1][0] == '-')) 152 153 /* Adjust for the fact that psched_ticks aren't always usecs 154 (based on kernel PSCHED_CLOCK configuration */ 155 static int get_ticks(__u32 *ticks, const char *str) 156 { 157 unsigned t; 158 159 if(get_time(&t, str)) 160 return -1; 161 162 if (tc_core_time2big(t)) { 163 fprintf(stderr, "Illegal %u time (too large)\n", t); 164 return -1; 165 } 166 167 *ticks = tc_core_time2tick(t); 168 return 0; 169 } 170 171 static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, 172 struct nlmsghdr *n) 173 { 174 int dist_size = 0; 175 struct rtattr *tail; 176 struct tc_netem_qopt opt = { .limit = 1000 }; 177 struct tc_netem_corr cor; 178 struct tc_netem_reorder reorder; 179 struct tc_netem_corrupt corrupt; 180 struct tc_netem_gimodel gimodel; 181 struct tc_netem_gemodel gemodel; 182 struct tc_netem_rate rate; 183 __s16 *dist_data = NULL; 184 __u16 loss_type = NETEM_LOSS_UNSPEC; 185 int present[__TCA_NETEM_MAX]; 186 __u64 rate64 = 0; 187 188 memset(&cor, 0, sizeof(cor)); 189 memset(&reorder, 0, sizeof(reorder)); 190 memset(&corrupt, 0, sizeof(corrupt)); 191 memset(&rate, 0, sizeof(rate)); 192 memset(present, 0, sizeof(present)); 193 194 for( ; argc > 0; --argc, ++argv) { 195 if (matches(*argv, "limit") == 0) { 196 NEXT_ARG(); 197 if (get_size(&opt.limit, *argv)) { 198 explain1("limit"); 199 return -1; 200 } 201 } else if (matches(*argv, "latency") == 0 || 202 matches(*argv, "delay") == 0) { 203 NEXT_ARG(); 204 if (get_ticks(&opt.latency, *argv)) { 205 explain1("latency"); 206 return -1; 207 } 208 209 if (NEXT_IS_NUMBER()) { 210 NEXT_ARG(); 211 if (get_ticks(&opt.jitter, *argv)) { 212 explain1("latency"); 213 return -1; 214 } 215 216 if (NEXT_IS_NUMBER()) { 217 NEXT_ARG(); 218 ++present[TCA_NETEM_CORR]; 219 if (get_percent(&cor.delay_corr, *argv)) { 220 explain1("latency"); 221 return -1; 222 } 223 } 224 } 225 } else if (matches(*argv, "loss") == 0 || 226 matches(*argv, "drop") == 0) { 227 if (opt.loss > 0 || loss_type != NETEM_LOSS_UNSPEC) { 228 explain1("duplicate loss argument\n"); 229 return -1; 230 } 231 232 NEXT_ARG(); 233 /* Old (deprecated) random loss model syntax */ 234 if (isdigit(argv[0][0])) 235 goto random_loss_model; 236 237 if (!strcmp(*argv, "random")) { 238 NEXT_ARG(); 239 random_loss_model: 240 if (get_percent(&opt.loss, *argv)) { 241 explain1("loss percent"); 242 return -1; 243 } 244 if (NEXT_IS_NUMBER()) { 245 NEXT_ARG(); 246 ++present[TCA_NETEM_CORR]; 247 if (get_percent(&cor.loss_corr, *argv)) { 248 explain1("loss correllation"); 249 return -1; 250 } 251 } 252 } else if (!strcmp(*argv, "state")) { 253 double p13; 254 255 NEXT_ARG(); 256 if (parse_percent(&p13, *argv)) { 257 explain1("loss p13"); 258 return -1; 259 } 260 261 /* set defaults */ 262 set_percent(&gimodel.p13, p13); 263 set_percent(&gimodel.p31, 1. - p13); 264 set_percent(&gimodel.p32, 0); 265 set_percent(&gimodel.p23, 1.); 266 set_percent(&gimodel.p14, 0); 267 loss_type = NETEM_LOSS_GI; 268 269 if (!NEXT_IS_NUMBER()) 270 continue; 271 NEXT_ARG(); 272 if (get_percent(&gimodel.p31, *argv)) { 273 explain1("loss p31"); 274 return -1; 275 } 276 277 if (!NEXT_IS_NUMBER()) 278 continue; 279 NEXT_ARG(); 280 if (get_percent(&gimodel.p32, *argv)) { 281 explain1("loss p32"); 282 return -1; 283 } 284 285 if (!NEXT_IS_NUMBER()) 286 continue; 287 NEXT_ARG(); 288 if (get_percent(&gimodel.p23, *argv)) { 289 explain1("loss p23"); 290 return -1; 291 } 292 if (!NEXT_IS_NUMBER()) 293 continue; 294 NEXT_ARG(); 295 if (get_percent(&gimodel.p14, *argv)) { 296 explain1("loss p14"); 297 return -1; 298 } 299 300 } else if (!strcmp(*argv, "gemodel")) { 301 NEXT_ARG(); 302 if (get_percent(&gemodel.p, *argv)) { 303 explain1("loss gemodel p"); 304 return -1; 305 } 306 307 /* set defaults */ 308 set_percent(&gemodel.r, 1.); 309 set_percent(&gemodel.h, 0); 310 set_percent(&gemodel.k1, 0); 311 loss_type = NETEM_LOSS_GE; 312 313 if (!NEXT_IS_NUMBER()) 314 continue; 315 NEXT_ARG(); 316 if (get_percent(&gemodel.r, *argv)) { 317 explain1("loss gemodel r"); 318 return -1; 319 } 320 321 if (!NEXT_IS_NUMBER()) 322 continue; 323 NEXT_ARG(); 324 if (get_percent(&gemodel.h, *argv)) { 325 explain1("loss gemodel h"); 326 return -1; 327 } 328 /* netem option is "1-h" but kernel 329 * expects "h". 330 */ 331 gemodel.h = max_percent_value - gemodel.h; 332 333 if (!NEXT_IS_NUMBER()) 334 continue; 335 NEXT_ARG(); 336 if (get_percent(&gemodel.k1, *argv)) { 337 explain1("loss gemodel k"); 338 return -1; 339 } 340 } else { 341 fprintf(stderr, "Unknown loss parameter: %s\n", 342 *argv); 343 return -1; 344 } 345 } else if (matches(*argv, "ecn") == 0) { 346 present[TCA_NETEM_ECN] = 1; 347 } else if (matches(*argv, "reorder") == 0) { 348 NEXT_ARG(); 349 present[TCA_NETEM_REORDER] = 1; 350 if (get_percent(&reorder.probability, *argv)) { 351 explain1("reorder"); 352 return -1; 353 } 354 if (NEXT_IS_NUMBER()) { 355 NEXT_ARG(); 356 ++present[TCA_NETEM_CORR]; 357 if (get_percent(&reorder.correlation, *argv)) { 358 explain1("reorder"); 359 return -1; 360 } 361 } 362 } else if (matches(*argv, "corrupt") == 0) { 363 NEXT_ARG(); 364 present[TCA_NETEM_CORRUPT] = 1; 365 if (get_percent(&corrupt.probability, *argv)) { 366 explain1("corrupt"); 367 return -1; 368 } 369 if (NEXT_IS_NUMBER()) { 370 NEXT_ARG(); 371 ++present[TCA_NETEM_CORR]; 372 if (get_percent(&corrupt.correlation, *argv)) { 373 explain1("corrupt"); 374 return -1; 375 } 376 } 377 } else if (matches(*argv, "gap") == 0) { 378 NEXT_ARG(); 379 if (get_u32(&opt.gap, *argv, 0)) { 380 explain1("gap"); 381 return -1; 382 } 383 } else if (matches(*argv, "duplicate") == 0) { 384 NEXT_ARG(); 385 if (get_percent(&opt.duplicate, *argv)) { 386 explain1("duplicate"); 387 return -1; 388 } 389 if (NEXT_IS_NUMBER()) { 390 NEXT_ARG(); 391 if (get_percent(&cor.dup_corr, *argv)) { 392 explain1("duplicate"); 393 return -1; 394 } 395 } 396 } else if (matches(*argv, "distribution") == 0) { 397 NEXT_ARG(); 398 dist_data = calloc(sizeof(dist_data[0]), MAX_DIST); 399 dist_size = get_distribution(*argv, dist_data, MAX_DIST); 400 if (dist_size <= 0) { 401 free(dist_data); 402 return -1; 403 } 404 } else if (matches(*argv, "rate") == 0) { 405 ++present[TCA_NETEM_RATE]; 406 NEXT_ARG(); 407 if (get_rate64(&rate64, *argv)) { 408 explain1("rate"); 409 return -1; 410 } 411 if (NEXT_IS_SIGNED_NUMBER()) { 412 NEXT_ARG(); 413 if (get_s32(&rate.packet_overhead, *argv, 0)) { 414 explain1("rate"); 415 return -1; 416 } 417 } 418 if (NEXT_IS_NUMBER()) { 419 NEXT_ARG(); 420 if (get_u32(&rate.cell_size, *argv, 0)) { 421 explain1("rate"); 422 return -1; 423 } 424 } 425 if (NEXT_IS_SIGNED_NUMBER()) { 426 NEXT_ARG(); 427 if (get_s32(&rate.cell_overhead, *argv, 0)) { 428 explain1("rate"); 429 return -1; 430 } 431 } 432 } else if (strcmp(*argv, "help") == 0) { 433 explain(); 434 return -1; 435 } else { 436 fprintf(stderr, "What is \"%s\"?\n", *argv); 437 explain(); 438 return -1; 439 } 440 } 441 442 tail = NLMSG_TAIL(n); 443 444 if (reorder.probability) { 445 if (opt.latency == 0) { 446 fprintf(stderr, "reordering not possible without specifying some delay\n"); 447 explain(); 448 return -1; 449 } 450 if (opt.gap == 0) 451 opt.gap = 1; 452 } else if (opt.gap > 0) { 453 fprintf(stderr, "gap specified without reorder probability\n"); 454 explain(); 455 return -1; 456 } 457 458 if (present[TCA_NETEM_ECN]) { 459 if (opt.loss <= 0 && loss_type == NETEM_LOSS_UNSPEC) { 460 fprintf(stderr, "ecn requested without loss model\n"); 461 explain(); 462 return -1; 463 } 464 } 465 466 if (dist_data && (opt.latency == 0 || opt.jitter == 0)) { 467 fprintf(stderr, "distribution specified but no latency and jitter values\n"); 468 explain(); 469 return -1; 470 } 471 472 if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0) 473 return -1; 474 475 if (present[TCA_NETEM_CORR] && 476 addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0) 477 return -1; 478 479 if (present[TCA_NETEM_REORDER] && 480 addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0) 481 return -1; 482 483 if (present[TCA_NETEM_ECN] && 484 addattr_l(n, 1024, TCA_NETEM_ECN, &present[TCA_NETEM_ECN], 485 sizeof(present[TCA_NETEM_ECN])) < 0) 486 return -1; 487 488 if (present[TCA_NETEM_CORRUPT] && 489 addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0) 490 return -1; 491 492 if (loss_type != NETEM_LOSS_UNSPEC) { 493 struct rtattr *start; 494 495 start = addattr_nest(n, 1024, TCA_NETEM_LOSS | NLA_F_NESTED); 496 if (loss_type == NETEM_LOSS_GI) { 497 if (addattr_l(n, 1024, NETEM_LOSS_GI, 498 &gimodel, sizeof(gimodel)) < 0) 499 return -1; 500 } else if (loss_type == NETEM_LOSS_GE) { 501 if (addattr_l(n, 1024, NETEM_LOSS_GE, 502 &gemodel, sizeof(gemodel)) < 0) 503 return -1; 504 } else { 505 fprintf(stderr, "loss in the weeds!\n"); 506 return -1; 507 } 508 509 addattr_nest_end(n, start); 510 } 511 512 if (present[TCA_NETEM_RATE]) { 513 if (rate64 >= (1ULL << 32)) { 514 if (addattr_l(n, 1024, 515 TCA_NETEM_RATE64, &rate64, sizeof(rate64)) < 0) 516 return -1; 517 rate.rate = ~0U; 518 } else { 519 rate.rate = rate64; 520 } 521 if (addattr_l(n, 1024, TCA_NETEM_RATE, &rate, sizeof(rate)) < 0) 522 return -1; 523 } 524 525 if (dist_data) { 526 if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]), 527 TCA_NETEM_DELAY_DIST, 528 dist_data, dist_size * sizeof(dist_data[0])) < 0) 529 return -1; 530 free(dist_data); 531 } 532 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 533 return 0; 534 } 535 536 static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 537 { 538 const struct tc_netem_corr *cor = NULL; 539 const struct tc_netem_reorder *reorder = NULL; 540 const struct tc_netem_corrupt *corrupt = NULL; 541 const struct tc_netem_gimodel *gimodel = NULL; 542 const struct tc_netem_gemodel *gemodel = NULL; 543 int *ecn = NULL; 544 struct tc_netem_qopt qopt; 545 const struct tc_netem_rate *rate = NULL; 546 int len = RTA_PAYLOAD(opt) - sizeof(qopt); 547 __u64 rate64 = 0; 548 SPRINT_BUF(b1); 549 550 if (opt == NULL) 551 return 0; 552 553 if (len < 0) { 554 fprintf(stderr, "options size error\n"); 555 return -1; 556 } 557 memcpy(&qopt, RTA_DATA(opt), sizeof(qopt)); 558 559 if (len > 0) { 560 struct rtattr *tb[TCA_NETEM_MAX+1]; 561 parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt), 562 len); 563 564 if (tb[TCA_NETEM_CORR]) { 565 if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor)) 566 return -1; 567 cor = RTA_DATA(tb[TCA_NETEM_CORR]); 568 } 569 if (tb[TCA_NETEM_REORDER]) { 570 if (RTA_PAYLOAD(tb[TCA_NETEM_REORDER]) < sizeof(*reorder)) 571 return -1; 572 reorder = RTA_DATA(tb[TCA_NETEM_REORDER]); 573 } 574 if (tb[TCA_NETEM_CORRUPT]) { 575 if (RTA_PAYLOAD(tb[TCA_NETEM_CORRUPT]) < sizeof(*corrupt)) 576 return -1; 577 corrupt = RTA_DATA(tb[TCA_NETEM_CORRUPT]); 578 } 579 if (tb[TCA_NETEM_LOSS]) { 580 struct rtattr *lb[NETEM_LOSS_MAX + 1]; 581 582 parse_rtattr_nested(lb, NETEM_LOSS_MAX, tb[TCA_NETEM_LOSS]); 583 if (lb[NETEM_LOSS_GI]) 584 gimodel = RTA_DATA(lb[NETEM_LOSS_GI]); 585 if (lb[NETEM_LOSS_GE]) 586 gemodel = RTA_DATA(lb[NETEM_LOSS_GE]); 587 } 588 if (tb[TCA_NETEM_RATE]) { 589 if (RTA_PAYLOAD(tb[TCA_NETEM_RATE]) < sizeof(*rate)) 590 return -1; 591 rate = RTA_DATA(tb[TCA_NETEM_RATE]); 592 } 593 if (tb[TCA_NETEM_ECN]) { 594 if (RTA_PAYLOAD(tb[TCA_NETEM_ECN]) < sizeof(*ecn)) 595 return -1; 596 ecn = RTA_DATA(tb[TCA_NETEM_ECN]); 597 } 598 if (tb[TCA_NETEM_RATE64]) { 599 if (RTA_PAYLOAD(tb[TCA_NETEM_RATE64]) < sizeof(rate64)) 600 return -1; 601 rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]); 602 } 603 } 604 605 fprintf(f, "limit %d", qopt.limit); 606 607 if (qopt.latency) { 608 fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1)); 609 610 if (qopt.jitter) { 611 fprintf(f, " %s", sprint_ticks(qopt.jitter, b1)); 612 if (cor && cor->delay_corr) 613 fprintf(f, " %s", sprint_percent(cor->delay_corr, b1)); 614 } 615 } 616 617 if (qopt.loss) { 618 fprintf(f, " loss %s", sprint_percent(qopt.loss, b1)); 619 if (cor && cor->loss_corr) 620 fprintf(f, " %s", sprint_percent(cor->loss_corr, b1)); 621 } 622 623 if (gimodel) { 624 fprintf(f, " loss state p13 %s", sprint_percent(gimodel->p13, b1)); 625 fprintf(f, " p31 %s", sprint_percent(gimodel->p31, b1)); 626 fprintf(f, " p32 %s", sprint_percent(gimodel->p32, b1)); 627 fprintf(f, " p23 %s", sprint_percent(gimodel->p23, b1)); 628 fprintf(f, " p14 %s", sprint_percent(gimodel->p14, b1)); 629 } 630 631 if (gemodel) { 632 fprintf(f, " loss gemodel p %s", 633 sprint_percent(gemodel->p, b1)); 634 fprintf(f, " r %s", sprint_percent(gemodel->r, b1)); 635 fprintf(f, " 1-h %s", sprint_percent(max_percent_value - 636 gemodel->h, b1)); 637 fprintf(f, " 1-k %s", sprint_percent(gemodel->k1, b1)); 638 } 639 640 if (qopt.duplicate) { 641 fprintf(f, " duplicate %s", 642 sprint_percent(qopt.duplicate, b1)); 643 if (cor && cor->dup_corr) 644 fprintf(f, " %s", sprint_percent(cor->dup_corr, b1)); 645 } 646 647 if (reorder && reorder->probability) { 648 fprintf(f, " reorder %s", 649 sprint_percent(reorder->probability, b1)); 650 if (reorder->correlation) 651 fprintf(f, " %s", 652 sprint_percent(reorder->correlation, b1)); 653 } 654 655 if (corrupt && corrupt->probability) { 656 fprintf(f, " corrupt %s", 657 sprint_percent(corrupt->probability, b1)); 658 if (corrupt->correlation) 659 fprintf(f, " %s", 660 sprint_percent(corrupt->correlation, b1)); 661 } 662 663 if (rate && rate->rate) { 664 if (rate64) 665 fprintf(f, " rate %s", sprint_rate(rate64, b1)); 666 else 667 fprintf(f, " rate %s", sprint_rate(rate->rate, b1)); 668 if (rate->packet_overhead) 669 fprintf(f, " packetoverhead %d", rate->packet_overhead); 670 if (rate->cell_size) 671 fprintf(f, " cellsize %u", rate->cell_size); 672 if (rate->cell_overhead) 673 fprintf(f, " celloverhead %d", rate->cell_overhead); 674 } 675 676 if (ecn) 677 fprintf(f, " ecn "); 678 679 if (qopt.gap) 680 fprintf(f, " gap %lu", (unsigned long)qopt.gap); 681 682 683 return 0; 684 } 685 686 struct qdisc_util netem_qdisc_util = { 687 .id = "netem", 688 .parse_qopt = netem_parse_opt, 689 .print_qopt = netem_print_opt, 690 }; 691