diff options
Diffstat (limited to 'net/sched/sch_netem.c')
-rw-r--r-- | net/sched/sch_netem.c | 54 |
1 files changed, 42 insertions, 12 deletions
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; |