diff options
| -rw-r--r-- | include/linux/pkt_sched.h | 9 | ||||
| -rw-r--r-- | net/sched/sch_netem.c | 54 |
2 files changed, 50 insertions, 13 deletions
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 73d84c071cb1..1d9da36eb9db 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h | |||
| @@ -427,6 +427,7 @@ enum | |||
| 427 | TCA_NETEM_UNSPEC, | 427 | TCA_NETEM_UNSPEC, |
| 428 | TCA_NETEM_CORR, | 428 | TCA_NETEM_CORR, |
| 429 | TCA_NETEM_DELAY_DIST, | 429 | TCA_NETEM_DELAY_DIST, |
| 430 | TCA_NETEM_REORDER, | ||
| 430 | __TCA_NETEM_MAX, | 431 | __TCA_NETEM_MAX, |
| 431 | }; | 432 | }; |
| 432 | 433 | ||
| @@ -437,7 +438,7 @@ struct tc_netem_qopt | |||
| 437 | __u32 latency; /* added delay (us) */ | 438 | __u32 latency; /* added delay (us) */ |
| 438 | __u32 limit; /* fifo limit (packets) */ | 439 | __u32 limit; /* fifo limit (packets) */ |
| 439 | __u32 loss; /* random packet loss (0=none ~0=100%) */ | 440 | __u32 loss; /* random packet loss (0=none ~0=100%) */ |
| 440 | __u32 gap; /* re-ordering gap (0 for delay all) */ | 441 | __u32 gap; /* re-ordering gap (0 for none) */ |
| 441 | __u32 duplicate; /* random packet dup (0=none ~0=100%) */ | 442 | __u32 duplicate; /* random packet dup (0=none ~0=100%) */ |
| 442 | __u32 jitter; /* random jitter in latency (us) */ | 443 | __u32 jitter; /* random jitter in latency (us) */ |
| 443 | }; | 444 | }; |
| @@ -449,6 +450,12 @@ struct tc_netem_corr | |||
| 449 | __u32 dup_corr; /* duplicate correlation */ | 450 | __u32 dup_corr; /* duplicate correlation */ |
| 450 | }; | 451 | }; |
| 451 | 452 | ||
| 453 | struct tc_netem_reorder | ||
| 454 | { | ||
| 455 | __u32 probability; | ||
| 456 | __u32 correlation; | ||
| 457 | }; | ||
| 458 | |||
| 452 | #define NETEM_DIST_SCALE 8192 | 459 | #define NETEM_DIST_SCALE 8192 |
| 453 | 460 | ||
| 454 | #endif | 461 | #endif |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 48360f7eec5d..bb9bf8d5003c 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
| @@ -62,11 +62,12 @@ struct netem_sched_data { | |||
| 62 | u32 gap; | 62 | u32 gap; |
| 63 | u32 jitter; | 63 | u32 jitter; |
| 64 | u32 duplicate; | 64 | u32 duplicate; |
| 65 | u32 reorder; | ||
| 65 | 66 | ||
| 66 | struct crndstate { | 67 | struct crndstate { |
| 67 | unsigned long last; | 68 | unsigned long last; |
| 68 | unsigned long rho; | 69 | unsigned long rho; |
| 69 | } delay_cor, loss_cor, dup_cor; | 70 | } delay_cor, loss_cor, dup_cor, reorder_cor; |
| 70 | 71 | ||
| 71 | struct disttable { | 72 | struct disttable { |
| 72 | u32 size; | 73 | u32 size; |
| @@ -180,23 +181,23 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 180 | q->duplicate = dupsave; | 181 | q->duplicate = dupsave; |
| 181 | } | 182 | } |
| 182 | 183 | ||
| 183 | /* | 184 | if (q->gap == 0 /* not doing reordering */ |
| 184 | * Do re-ordering by putting one out of N packets at the front | 185 | || q->counter < q->gap /* inside last reordering gap */ |
| 185 | * of the queue. | 186 | || q->reorder < get_crandom(&q->reorder_cor)) { |
| 186 | * gap == 0 is special case for no-reordering. | ||
| 187 | */ | ||
| 188 | if (q->gap == 0 || q->counter != q->gap) { | ||
| 189 | psched_time_t now; | 187 | psched_time_t now; |
| 190 | PSCHED_GET_TIME(now); | 188 | PSCHED_GET_TIME(now); |
| 191 | PSCHED_TADD2(now, | 189 | PSCHED_TADD2(now, tabledist(q->latency, q->jitter, |
| 192 | tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist), | 190 | &q->delay_cor, q->delay_dist), |
| 193 | cb->time_to_send); | 191 | cb->time_to_send); |
| 194 | |||
| 195 | ++q->counter; | 192 | ++q->counter; |
| 196 | ret = q->qdisc->enqueue(skb, q->qdisc); | 193 | ret = q->qdisc->enqueue(skb, q->qdisc); |
| 197 | } else { | 194 | } else { |
| 198 | q->counter = 0; | 195 | /* |
| 196 | * Do re-ordering by putting one out of N packets at the front | ||
| 197 | * of the queue. | ||
| 198 | */ | ||
| 199 | PSCHED_GET_TIME(cb->time_to_send); | 199 | PSCHED_GET_TIME(cb->time_to_send); |
| 200 | q->counter = 0; | ||
| 200 | ret = q->qdisc->ops->requeue(skb, q->qdisc); | 201 | ret = q->qdisc->ops->requeue(skb, q->qdisc); |
| 201 | } | 202 | } |
| 202 | 203 | ||
| @@ -351,6 +352,19 @@ static int get_correlation(struct Qdisc *sch, const struct rtattr *attr) | |||
| 351 | return 0; | 352 | return 0; |
| 352 | } | 353 | } |
| 353 | 354 | ||
| 355 | static int get_reorder(struct Qdisc *sch, const struct rtattr *attr) | ||
| 356 | { | ||
| 357 | struct netem_sched_data *q = qdisc_priv(sch); | ||
| 358 | const struct tc_netem_reorder *r = RTA_DATA(attr); | ||
| 359 | |||
| 360 | if (RTA_PAYLOAD(attr) != sizeof(*r)) | ||
| 361 | return -EINVAL; | ||
| 362 | |||
| 363 | q->reorder = r->probability; | ||
| 364 | init_crandom(&q->reorder_cor, r->correlation); | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 354 | static int netem_change(struct Qdisc *sch, struct rtattr *opt) | 368 | static int netem_change(struct Qdisc *sch, struct rtattr *opt) |
| 355 | { | 369 | { |
| 356 | struct netem_sched_data *q = qdisc_priv(sch); | 370 | struct netem_sched_data *q = qdisc_priv(sch); |
| @@ -371,9 +385,15 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt) | |||
| 371 | q->jitter = qopt->jitter; | 385 | q->jitter = qopt->jitter; |
| 372 | q->limit = qopt->limit; | 386 | q->limit = qopt->limit; |
| 373 | q->gap = qopt->gap; | 387 | q->gap = qopt->gap; |
| 388 | q->counter = 0; | ||
| 374 | q->loss = qopt->loss; | 389 | q->loss = qopt->loss; |
| 375 | q->duplicate = qopt->duplicate; | 390 | q->duplicate = qopt->duplicate; |
| 376 | 391 | ||
| 392 | /* for compatiablity with earlier versions. | ||
| 393 | * if gap is set, need to assume 100% probablity | ||
| 394 | */ | ||
| 395 | q->reorder = ~0; | ||
| 396 | |||
| 377 | /* Handle nested options after initial queue options. | 397 | /* Handle nested options after initial queue options. |
| 378 | * Should have put all options in nested format but too late now. | 398 | * Should have put all options in nested format but too late now. |
| 379 | */ | 399 | */ |
| @@ -395,6 +415,11 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt) | |||
| 395 | if (ret) | 415 | if (ret) |
| 396 | return ret; | 416 | return ret; |
| 397 | } | 417 | } |
| 418 | if (tb[TCA_NETEM_REORDER-1]) { | ||
| 419 | ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]); | ||
| 420 | if (ret) | ||
| 421 | return ret; | ||
| 422 | } | ||
| 398 | } | 423 | } |
| 399 | 424 | ||
| 400 | 425 | ||
| @@ -412,7 +437,6 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt) | |||
| 412 | init_timer(&q->timer); | 437 | init_timer(&q->timer); |
| 413 | q->timer.function = netem_watchdog; | 438 | q->timer.function = netem_watchdog; |
| 414 | q->timer.data = (unsigned long) sch; | 439 | q->timer.data = (unsigned long) sch; |
| 415 | q->counter = 0; | ||
| 416 | 440 | ||
| 417 | q->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); | 441 | q->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); |
| 418 | if (!q->qdisc) { | 442 | if (!q->qdisc) { |
| @@ -444,6 +468,7 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
| 444 | struct rtattr *rta = (struct rtattr *) b; | 468 | struct rtattr *rta = (struct rtattr *) b; |
| 445 | struct tc_netem_qopt qopt; | 469 | struct tc_netem_qopt qopt; |
| 446 | struct tc_netem_corr cor; | 470 | struct tc_netem_corr cor; |
| 471 | struct tc_netem_reorder reorder; | ||
| 447 | 472 | ||
| 448 | qopt.latency = q->latency; | 473 | qopt.latency = q->latency; |
| 449 | qopt.jitter = q->jitter; | 474 | qopt.jitter = q->jitter; |
| @@ -457,6 +482,11 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
| 457 | cor.loss_corr = q->loss_cor.rho; | 482 | cor.loss_corr = q->loss_cor.rho; |
| 458 | cor.dup_corr = q->dup_cor.rho; | 483 | cor.dup_corr = q->dup_cor.rho; |
| 459 | RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor); | 484 | RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor); |
| 485 | |||
| 486 | reorder.probability = q->reorder; | ||
| 487 | reorder.correlation = q->reorder_cor.rho; | ||
| 488 | RTA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder); | ||
| 489 | |||
| 460 | rta->rta_len = skb->tail - b; | 490 | rta->rta_len = skb->tail - b; |
| 461 | 491 | ||
| 462 | return skb->len; | 492 | return skb->len; |
