sch_netem.c (20fea08b5fb639c4c175b5c74a2bb346c5c5bc2e) | sch_netem.c (1e90474c377e92db7262a8968a45c1dd980ca9e5) |
---|---|
1/* 2 * net/sched/sch_netem.c Network emulator 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. 8 * --- 299 unchanged lines hidden (view full) --- 308 qdisc_reset(q->qdisc); 309 sch->q.qlen = 0; 310 qdisc_watchdog_cancel(&q->watchdog); 311} 312 313/* Pass size change message down to embedded FIFO */ 314static int set_fifo_limit(struct Qdisc *q, int limit) 315{ | 1/* 2 * net/sched/sch_netem.c Network emulator 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. 8 * --- 299 unchanged lines hidden (view full) --- 308 qdisc_reset(q->qdisc); 309 sch->q.qlen = 0; 310 qdisc_watchdog_cancel(&q->watchdog); 311} 312 313/* Pass size change message down to embedded FIFO */ 314static int set_fifo_limit(struct Qdisc *q, int limit) 315{ |
316 struct rtattr *rta; | 316 struct nlattr *nla; |
317 int ret = -ENOMEM; 318 319 /* Hack to avoid sending change message to non-FIFO */ 320 if (strncmp(q->ops->id + 1, "fifo", 4) != 0) 321 return 0; 322 | 317 int ret = -ENOMEM; 318 319 /* Hack to avoid sending change message to non-FIFO */ 320 if (strncmp(q->ops->id + 1, "fifo", 4) != 0) 321 return 0; 322 |
323 rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); 324 if (rta) { 325 rta->rta_type = RTM_NEWQDISC; 326 rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); 327 ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; | 323 nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); 324 if (nla) { 325 nla->nla_type = RTM_NEWQDISC; 326 nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); 327 ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; |
328 | 328 |
329 ret = q->ops->change(q, rta); 330 kfree(rta); | 329 ret = q->ops->change(q, nla); 330 kfree(nla); |
331 } 332 return ret; 333} 334 335/* 336 * Distribution data is a variable size payload containing 337 * signed 16 bit values. 338 */ | 331 } 332 return ret; 333} 334 335/* 336 * Distribution data is a variable size payload containing 337 * signed 16 bit values. 338 */ |
339static int get_dist_table(struct Qdisc *sch, const struct rtattr *attr) | 339static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) |
340{ 341 struct netem_sched_data *q = qdisc_priv(sch); | 340{ 341 struct netem_sched_data *q = qdisc_priv(sch); |
342 unsigned long n = RTA_PAYLOAD(attr)/sizeof(__s16); 343 const __s16 *data = RTA_DATA(attr); | 342 unsigned long n = nla_len(attr)/sizeof(__s16); 343 const __s16 *data = nla_data(attr); |
344 struct disttable *d; 345 int i; 346 347 if (n > 65536) 348 return -EINVAL; 349 350 d = kmalloc(sizeof(*d) + n*sizeof(d->table[0]), GFP_KERNEL); 351 if (!d) --- 6 unchanged lines hidden (view full) --- 358 spin_lock_bh(&sch->dev->queue_lock); 359 d = xchg(&q->delay_dist, d); 360 spin_unlock_bh(&sch->dev->queue_lock); 361 362 kfree(d); 363 return 0; 364} 365 | 344 struct disttable *d; 345 int i; 346 347 if (n > 65536) 348 return -EINVAL; 349 350 d = kmalloc(sizeof(*d) + n*sizeof(d->table[0]), GFP_KERNEL); 351 if (!d) --- 6 unchanged lines hidden (view full) --- 358 spin_lock_bh(&sch->dev->queue_lock); 359 d = xchg(&q->delay_dist, d); 360 spin_unlock_bh(&sch->dev->queue_lock); 361 362 kfree(d); 363 return 0; 364} 365 |
366static int get_correlation(struct Qdisc *sch, const struct rtattr *attr) | 366static int get_correlation(struct Qdisc *sch, const struct nlattr *attr) |
367{ 368 struct netem_sched_data *q = qdisc_priv(sch); | 367{ 368 struct netem_sched_data *q = qdisc_priv(sch); |
369 const struct tc_netem_corr *c = RTA_DATA(attr); | 369 const struct tc_netem_corr *c = nla_data(attr); |
370 | 370 |
371 if (RTA_PAYLOAD(attr) != sizeof(*c)) | 371 if (nla_len(attr) != sizeof(*c)) |
372 return -EINVAL; 373 374 init_crandom(&q->delay_cor, c->delay_corr); 375 init_crandom(&q->loss_cor, c->loss_corr); 376 init_crandom(&q->dup_cor, c->dup_corr); 377 return 0; 378} 379 | 372 return -EINVAL; 373 374 init_crandom(&q->delay_cor, c->delay_corr); 375 init_crandom(&q->loss_cor, c->loss_corr); 376 init_crandom(&q->dup_cor, c->dup_corr); 377 return 0; 378} 379 |
380static int get_reorder(struct Qdisc *sch, const struct rtattr *attr) | 380static int get_reorder(struct Qdisc *sch, const struct nlattr *attr) |
381{ 382 struct netem_sched_data *q = qdisc_priv(sch); | 381{ 382 struct netem_sched_data *q = qdisc_priv(sch); |
383 const struct tc_netem_reorder *r = RTA_DATA(attr); | 383 const struct tc_netem_reorder *r = nla_data(attr); |
384 | 384 |
385 if (RTA_PAYLOAD(attr) != sizeof(*r)) | 385 if (nla_len(attr) != sizeof(*r)) |
386 return -EINVAL; 387 388 q->reorder = r->probability; 389 init_crandom(&q->reorder_cor, r->correlation); 390 return 0; 391} 392 | 386 return -EINVAL; 387 388 q->reorder = r->probability; 389 init_crandom(&q->reorder_cor, r->correlation); 390 return 0; 391} 392 |
393static int get_corrupt(struct Qdisc *sch, const struct rtattr *attr) | 393static int get_corrupt(struct Qdisc *sch, const struct nlattr *attr) |
394{ 395 struct netem_sched_data *q = qdisc_priv(sch); | 394{ 395 struct netem_sched_data *q = qdisc_priv(sch); |
396 const struct tc_netem_corrupt *r = RTA_DATA(attr); | 396 const struct tc_netem_corrupt *r = nla_data(attr); |
397 | 397 |
398 if (RTA_PAYLOAD(attr) != sizeof(*r)) | 398 if (nla_len(attr) != sizeof(*r)) |
399 return -EINVAL; 400 401 q->corrupt = r->probability; 402 init_crandom(&q->corrupt_cor, r->correlation); 403 return 0; 404} 405 406/* Parse netlink message to set options */ | 399 return -EINVAL; 400 401 q->corrupt = r->probability; 402 init_crandom(&q->corrupt_cor, r->correlation); 403 return 0; 404} 405 406/* Parse netlink message to set options */ |
407static int netem_change(struct Qdisc *sch, struct rtattr *opt) | 407static int netem_change(struct Qdisc *sch, struct nlattr *opt) |
408{ 409 struct netem_sched_data *q = qdisc_priv(sch); 410 struct tc_netem_qopt *qopt; 411 int ret; 412 | 408{ 409 struct netem_sched_data *q = qdisc_priv(sch); 410 struct tc_netem_qopt *qopt; 411 int ret; 412 |
413 if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) | 413 if (opt == NULL || nla_len(opt) < sizeof(*qopt)) |
414 return -EINVAL; 415 | 414 return -EINVAL; 415 |
416 qopt = RTA_DATA(opt); | 416 qopt = nla_data(opt); |
417 ret = set_fifo_limit(q->qdisc, qopt->limit); 418 if (ret) { 419 pr_debug("netem: can't set fifo limit\n"); 420 return ret; 421 } 422 423 q->latency = qopt->latency; 424 q->jitter = qopt->jitter; --- 7 unchanged lines hidden (view full) --- 432 * if gap is set, need to assume 100% probability 433 */ 434 if (q->gap) 435 q->reorder = ~0; 436 437 /* Handle nested options after initial queue options. 438 * Should have put all options in nested format but too late now. 439 */ | 417 ret = set_fifo_limit(q->qdisc, qopt->limit); 418 if (ret) { 419 pr_debug("netem: can't set fifo limit\n"); 420 return ret; 421 } 422 423 q->latency = qopt->latency; 424 q->jitter = qopt->jitter; --- 7 unchanged lines hidden (view full) --- 432 * if gap is set, need to assume 100% probability 433 */ 434 if (q->gap) 435 q->reorder = ~0; 436 437 /* Handle nested options after initial queue options. 438 * Should have put all options in nested format but too late now. 439 */ |
440 if (RTA_PAYLOAD(opt) > sizeof(*qopt)) { 441 struct rtattr *tb[TCA_NETEM_MAX]; 442 if (rtattr_parse(tb, TCA_NETEM_MAX, 443 RTA_DATA(opt) + sizeof(*qopt), 444 RTA_PAYLOAD(opt) - sizeof(*qopt))) | 440 if (nla_len(opt) > sizeof(*qopt)) { 441 struct nlattr *tb[TCA_NETEM_MAX + 1]; 442 if (nla_parse(tb, TCA_NETEM_MAX, 443 nla_data(opt) + sizeof(*qopt), 444 nla_len(opt) - sizeof(*qopt), NULL)) |
445 return -EINVAL; 446 | 445 return -EINVAL; 446 |
447 if (tb[TCA_NETEM_CORR-1]) { 448 ret = get_correlation(sch, tb[TCA_NETEM_CORR-1]); | 447 if (tb[TCA_NETEM_CORR]) { 448 ret = get_correlation(sch, tb[TCA_NETEM_CORR]); |
449 if (ret) 450 return ret; 451 } 452 | 449 if (ret) 450 return ret; 451 } 452 |
453 if (tb[TCA_NETEM_DELAY_DIST-1]) { 454 ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST-1]); | 453 if (tb[TCA_NETEM_DELAY_DIST]) { 454 ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]); |
455 if (ret) 456 return ret; 457 } 458 | 455 if (ret) 456 return ret; 457 } 458 |
459 if (tb[TCA_NETEM_REORDER-1]) { 460 ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]); | 459 if (tb[TCA_NETEM_REORDER]) { 460 ret = get_reorder(sch, tb[TCA_NETEM_REORDER]); |
461 if (ret) 462 return ret; 463 } 464 | 461 if (ret) 462 return ret; 463 } 464 |
465 if (tb[TCA_NETEM_CORRUPT-1]) { 466 ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT-1]); | 465 if (tb[TCA_NETEM_CORRUPT]) { 466 ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT]); |
467 if (ret) 468 return ret; 469 } 470 } 471 472 return 0; 473} 474 --- 35 unchanged lines hidden (view full) --- 510 sch->bstats.packets++; 511 512 return NET_XMIT_SUCCESS; 513 } 514 515 return qdisc_reshape_fail(nskb, sch); 516} 517 | 467 if (ret) 468 return ret; 469 } 470 } 471 472 return 0; 473} 474 --- 35 unchanged lines hidden (view full) --- 510 sch->bstats.packets++; 511 512 return NET_XMIT_SUCCESS; 513 } 514 515 return qdisc_reshape_fail(nskb, sch); 516} 517 |
518static int tfifo_init(struct Qdisc *sch, struct rtattr *opt) | 518static int tfifo_init(struct Qdisc *sch, struct nlattr *opt) |
519{ 520 struct fifo_sched_data *q = qdisc_priv(sch); 521 522 if (opt) { | 519{ 520 struct fifo_sched_data *q = qdisc_priv(sch); 521 522 if (opt) { |
523 struct tc_fifo_qopt *ctl = RTA_DATA(opt); 524 if (RTA_PAYLOAD(opt) < sizeof(*ctl)) | 523 struct tc_fifo_qopt *ctl = nla_data(opt); 524 if (nla_len(opt) < sizeof(*ctl)) |
525 return -EINVAL; 526 527 q->limit = ctl->limit; 528 } else 529 q->limit = max_t(u32, sch->dev->tx_queue_len, 1); 530 531 q->oldest = PSCHED_PASTPERFECT; 532 return 0; 533} 534 535static int tfifo_dump(struct Qdisc *sch, struct sk_buff *skb) 536{ 537 struct fifo_sched_data *q = qdisc_priv(sch); 538 struct tc_fifo_qopt opt = { .limit = q->limit }; 539 | 525 return -EINVAL; 526 527 q->limit = ctl->limit; 528 } else 529 q->limit = max_t(u32, sch->dev->tx_queue_len, 1); 530 531 q->oldest = PSCHED_PASTPERFECT; 532 return 0; 533} 534 535static int tfifo_dump(struct Qdisc *sch, struct sk_buff *skb) 536{ 537 struct fifo_sched_data *q = qdisc_priv(sch); 538 struct tc_fifo_qopt opt = { .limit = q->limit }; 539 |
540 RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); | 540 NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); |
541 return skb->len; 542 | 541 return skb->len; 542 |
543rtattr_failure: | 543nla_put_failure: |
544 return -1; 545} 546 547static struct Qdisc_ops tfifo_qdisc_ops __read_mostly = { 548 .id = "tfifo", 549 .priv_size = sizeof(struct fifo_sched_data), 550 .enqueue = tfifo_enqueue, 551 .dequeue = qdisc_dequeue_head, 552 .requeue = qdisc_requeue, 553 .drop = qdisc_queue_drop, 554 .init = tfifo_init, 555 .reset = qdisc_reset_queue, 556 .change = tfifo_init, 557 .dump = tfifo_dump, 558}; 559 | 544 return -1; 545} 546 547static struct Qdisc_ops tfifo_qdisc_ops __read_mostly = { 548 .id = "tfifo", 549 .priv_size = sizeof(struct fifo_sched_data), 550 .enqueue = tfifo_enqueue, 551 .dequeue = qdisc_dequeue_head, 552 .requeue = qdisc_requeue, 553 .drop = qdisc_queue_drop, 554 .init = tfifo_init, 555 .reset = qdisc_reset_queue, 556 .change = tfifo_init, 557 .dump = tfifo_dump, 558}; 559 |
560static int netem_init(struct Qdisc *sch, struct rtattr *opt) | 560static int netem_init(struct Qdisc *sch, struct nlattr *opt) |
561{ 562 struct netem_sched_data *q = qdisc_priv(sch); 563 int ret; 564 565 if (!opt) 566 return -EINVAL; 567 568 qdisc_watchdog_init(&q->watchdog, sch); --- 21 unchanged lines hidden (view full) --- 590 qdisc_destroy(q->qdisc); 591 kfree(q->delay_dist); 592} 593 594static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) 595{ 596 const struct netem_sched_data *q = qdisc_priv(sch); 597 unsigned char *b = skb_tail_pointer(skb); | 561{ 562 struct netem_sched_data *q = qdisc_priv(sch); 563 int ret; 564 565 if (!opt) 566 return -EINVAL; 567 568 qdisc_watchdog_init(&q->watchdog, sch); --- 21 unchanged lines hidden (view full) --- 590 qdisc_destroy(q->qdisc); 591 kfree(q->delay_dist); 592} 593 594static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) 595{ 596 const struct netem_sched_data *q = qdisc_priv(sch); 597 unsigned char *b = skb_tail_pointer(skb); |
598 struct rtattr *rta = (struct rtattr *) b; | 598 struct nlattr *nla = (struct nlattr *) b; |
599 struct tc_netem_qopt qopt; 600 struct tc_netem_corr cor; 601 struct tc_netem_reorder reorder; 602 struct tc_netem_corrupt corrupt; 603 604 qopt.latency = q->latency; 605 qopt.jitter = q->jitter; 606 qopt.limit = q->limit; 607 qopt.loss = q->loss; 608 qopt.gap = q->gap; 609 qopt.duplicate = q->duplicate; | 599 struct tc_netem_qopt qopt; 600 struct tc_netem_corr cor; 601 struct tc_netem_reorder reorder; 602 struct tc_netem_corrupt corrupt; 603 604 qopt.latency = q->latency; 605 qopt.jitter = q->jitter; 606 qopt.limit = q->limit; 607 qopt.loss = q->loss; 608 qopt.gap = q->gap; 609 qopt.duplicate = q->duplicate; |
610 RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); | 610 NLA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); |
611 612 cor.delay_corr = q->delay_cor.rho; 613 cor.loss_corr = q->loss_cor.rho; 614 cor.dup_corr = q->dup_cor.rho; | 611 612 cor.delay_corr = q->delay_cor.rho; 613 cor.loss_corr = q->loss_cor.rho; 614 cor.dup_corr = q->dup_cor.rho; |
615 RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor); | 615 NLA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor); |
616 617 reorder.probability = q->reorder; 618 reorder.correlation = q->reorder_cor.rho; | 616 617 reorder.probability = q->reorder; 618 reorder.correlation = q->reorder_cor.rho; |
619 RTA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder); | 619 NLA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder); |
620 621 corrupt.probability = q->corrupt; 622 corrupt.correlation = q->corrupt_cor.rho; | 620 621 corrupt.probability = q->corrupt; 622 corrupt.correlation = q->corrupt_cor.rho; |
623 RTA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); | 623 NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); |
624 | 624 |
625 rta->rta_len = skb_tail_pointer(skb) - b; | 625 nla->nla_len = skb_tail_pointer(skb) - b; |
626 627 return skb->len; 628 | 626 627 return skb->len; 628 |
629rtattr_failure: | 629nla_put_failure: |
630 nlmsg_trim(skb, b); 631 return -1; 632} 633 634static int netem_dump_class(struct Qdisc *sch, unsigned long cl, 635 struct sk_buff *skb, struct tcmsg *tcm) 636{ 637 struct netem_sched_data *q = qdisc_priv(sch); --- 35 unchanged lines hidden (view full) --- 673 return 1; 674} 675 676static void netem_put(struct Qdisc *sch, unsigned long arg) 677{ 678} 679 680static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | 630 nlmsg_trim(skb, b); 631 return -1; 632} 633 634static int netem_dump_class(struct Qdisc *sch, unsigned long cl, 635 struct sk_buff *skb, struct tcmsg *tcm) 636{ 637 struct netem_sched_data *q = qdisc_priv(sch); --- 35 unchanged lines hidden (view full) --- 673 return 1; 674} 675 676static void netem_put(struct Qdisc *sch, unsigned long arg) 677{ 678} 679 680static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid, |
681 struct rtattr **tca, unsigned long *arg) | 681 struct nlattr **tca, unsigned long *arg) |
682{ 683 return -ENOSYS; 684} 685 686static int netem_delete(struct Qdisc *sch, unsigned long arg) 687{ 688 return -ENOSYS; 689} --- 59 unchanged lines hidden --- | 682{ 683 return -ENOSYS; 684} 685 686static int netem_delete(struct Qdisc *sch, unsigned long arg) 687{ 688 return -ENOSYS; 689} --- 59 unchanged lines hidden --- |