aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/sch_netem.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index eb3b9a86c6ed..9b7af9f1272f 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -79,6 +79,7 @@ struct netem_sched_data {
79 u32 duplicate; 79 u32 duplicate;
80 u32 reorder; 80 u32 reorder;
81 u32 corrupt; 81 u32 corrupt;
82 u32 rate;
82 83
83 struct crndstate { 84 struct crndstate {
84 u32 last; 85 u32 last;
@@ -298,6 +299,11 @@ static psched_tdiff_t tabledist(psched_tdiff_t mu, psched_tdiff_t sigma,
298 return x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu; 299 return x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
299} 300}
300 301
302static psched_time_t packet_len_2_sched_time(unsigned int len, u32 rate)
303{
304 return PSCHED_NS2TICKS((u64)len * NSEC_PER_SEC / rate);
305}
306
301/* 307/*
302 * Insert one skb into qdisc. 308 * Insert one skb into qdisc.
303 * Note: parent depends on return value to account for queue length. 309 * Note: parent depends on return value to account for queue length.
@@ -371,6 +377,24 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
371 &q->delay_cor, q->delay_dist); 377 &q->delay_cor, q->delay_dist);
372 378
373 now = psched_get_time(); 379 now = psched_get_time();
380
381 if (q->rate) {
382 struct sk_buff_head *list = &q->qdisc->q;
383
384 delay += packet_len_2_sched_time(skb->len, q->rate);
385
386 if (!skb_queue_empty(list)) {
387 /*
388 * Last packet in queue is reference point (now).
389 * First packet in queue is already in flight,
390 * calculate this time bonus and substract
391 * from delay.
392 */
393 delay -= now - netem_skb_cb(skb_peek(list))->time_to_send;
394 now = netem_skb_cb(skb_peek_tail(list))->time_to_send;
395 }
396 }
397
374 cb->time_to_send = now + delay; 398 cb->time_to_send = now + delay;
375 ++q->counter; 399 ++q->counter;
376 ret = qdisc_enqueue(skb, q->qdisc); 400 ret = qdisc_enqueue(skb, q->qdisc);
@@ -535,6 +559,14 @@ static void get_corrupt(struct Qdisc *sch, const struct nlattr *attr)
535 init_crandom(&q->corrupt_cor, r->correlation); 559 init_crandom(&q->corrupt_cor, r->correlation);
536} 560}
537 561
562static void get_rate(struct Qdisc *sch, const struct nlattr *attr)
563{
564 struct netem_sched_data *q = qdisc_priv(sch);
565 const struct tc_netem_rate *r = nla_data(attr);
566
567 q->rate = r->rate;
568}
569
538static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr) 570static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)
539{ 571{
540 struct netem_sched_data *q = qdisc_priv(sch); 572 struct netem_sched_data *q = qdisc_priv(sch);
@@ -594,6 +626,7 @@ static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
594 [TCA_NETEM_CORR] = { .len = sizeof(struct tc_netem_corr) }, 626 [TCA_NETEM_CORR] = { .len = sizeof(struct tc_netem_corr) },
595 [TCA_NETEM_REORDER] = { .len = sizeof(struct tc_netem_reorder) }, 627 [TCA_NETEM_REORDER] = { .len = sizeof(struct tc_netem_reorder) },
596 [TCA_NETEM_CORRUPT] = { .len = sizeof(struct tc_netem_corrupt) }, 628 [TCA_NETEM_CORRUPT] = { .len = sizeof(struct tc_netem_corrupt) },
629 [TCA_NETEM_RATE] = { .len = sizeof(struct tc_netem_rate) },
597 [TCA_NETEM_LOSS] = { .type = NLA_NESTED }, 630 [TCA_NETEM_LOSS] = { .type = NLA_NESTED },
598}; 631};
599 632
@@ -666,6 +699,9 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
666 if (tb[TCA_NETEM_CORRUPT]) 699 if (tb[TCA_NETEM_CORRUPT])
667 get_corrupt(sch, tb[TCA_NETEM_CORRUPT]); 700 get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
668 701
702 if (tb[TCA_NETEM_RATE])
703 get_rate(sch, tb[TCA_NETEM_RATE]);
704
669 q->loss_model = CLG_RANDOM; 705 q->loss_model = CLG_RANDOM;
670 if (tb[TCA_NETEM_LOSS]) 706 if (tb[TCA_NETEM_LOSS])
671 ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]); 707 ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]);
@@ -846,6 +882,7 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
846 struct tc_netem_corr cor; 882 struct tc_netem_corr cor;
847 struct tc_netem_reorder reorder; 883 struct tc_netem_reorder reorder;
848 struct tc_netem_corrupt corrupt; 884 struct tc_netem_corrupt corrupt;
885 struct tc_netem_rate rate;
849 886
850 qopt.latency = q->latency; 887 qopt.latency = q->latency;
851 qopt.jitter = q->jitter; 888 qopt.jitter = q->jitter;
@@ -868,6 +905,9 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
868 corrupt.correlation = q->corrupt_cor.rho; 905 corrupt.correlation = q->corrupt_cor.rho;
869 NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); 906 NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
870 907
908 rate.rate = q->rate;
909 NLA_PUT(skb, TCA_NETEM_RATE, sizeof(rate), &rate);
910
871 if (dump_loss_model(q, skb) != 0) 911 if (dump_loss_model(q, skb) != 0)
872 goto nla_put_failure; 912 goto nla_put_failure;
873 913