aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_netem.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_netem.c')
-rw-r--r--net/sched/sch_netem.c160
1 files changed, 23 insertions, 137 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 98402f0efa47..d876b8734848 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -230,7 +230,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
230 */ 230 */
231 cb->time_to_send = psched_get_time(); 231 cb->time_to_send = psched_get_time();
232 q->counter = 0; 232 q->counter = 0;
233 ret = q->qdisc->ops->requeue(skb, q->qdisc); 233
234 __skb_queue_head(&q->qdisc->q, skb);
235 q->qdisc->qstats.backlog += qdisc_pkt_len(skb);
236 q->qdisc->qstats.requeues++;
237 ret = NET_XMIT_SUCCESS;
234 } 238 }
235 239
236 if (likely(ret == NET_XMIT_SUCCESS)) { 240 if (likely(ret == NET_XMIT_SUCCESS)) {
@@ -245,20 +249,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
245 return ret; 249 return ret;
246} 250}
247 251
248/* Requeue packets but don't change time stamp */
249static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
250{
251 struct netem_sched_data *q = qdisc_priv(sch);
252 int ret;
253
254 if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
255 sch->q.qlen++;
256 sch->qstats.requeues++;
257 }
258
259 return ret;
260}
261
262static unsigned int netem_drop(struct Qdisc* sch) 252static unsigned int netem_drop(struct Qdisc* sch)
263{ 253{
264 struct netem_sched_data *q = qdisc_priv(sch); 254 struct netem_sched_data *q = qdisc_priv(sch);
@@ -276,29 +266,25 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
276 struct netem_sched_data *q = qdisc_priv(sch); 266 struct netem_sched_data *q = qdisc_priv(sch);
277 struct sk_buff *skb; 267 struct sk_buff *skb;
278 268
279 smp_mb();
280 if (sch->flags & TCQ_F_THROTTLED) 269 if (sch->flags & TCQ_F_THROTTLED)
281 return NULL; 270 return NULL;
282 271
283 skb = q->qdisc->dequeue(q->qdisc); 272 skb = q->qdisc->ops->peek(q->qdisc);
284 if (skb) { 273 if (skb) {
285 const struct netem_skb_cb *cb = netem_skb_cb(skb); 274 const struct netem_skb_cb *cb = netem_skb_cb(skb);
286 psched_time_t now = psched_get_time(); 275 psched_time_t now = psched_get_time();
287 276
288 /* if more time remaining? */ 277 /* if more time remaining? */
289 if (cb->time_to_send <= now) { 278 if (cb->time_to_send <= now) {
279 skb = qdisc_dequeue_peeked(q->qdisc);
280 if (unlikely(!skb))
281 return NULL;
282
290 pr_debug("netem_dequeue: return skb=%p\n", skb); 283 pr_debug("netem_dequeue: return skb=%p\n", skb);
291 sch->q.qlen--; 284 sch->q.qlen--;
292 return skb; 285 return skb;
293 } 286 }
294 287
295 if (unlikely(q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) {
296 qdisc_tree_decrease_qlen(q->qdisc, 1);
297 sch->qstats.drops++;
298 printk(KERN_ERR "netem: %s could not requeue\n",
299 q->qdisc->ops->id);
300 }
301
302 qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send); 288 qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send);
303 } 289 }
304 290
@@ -341,14 +327,13 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
341 root_lock = qdisc_root_sleeping_lock(sch); 327 root_lock = qdisc_root_sleeping_lock(sch);
342 328
343 spin_lock_bh(root_lock); 329 spin_lock_bh(root_lock);
344 d = xchg(&q->delay_dist, d); 330 kfree(q->delay_dist);
331 q->delay_dist = d;
345 spin_unlock_bh(root_lock); 332 spin_unlock_bh(root_lock);
346
347 kfree(d);
348 return 0; 333 return 0;
349} 334}
350 335
351static int get_correlation(struct Qdisc *sch, const struct nlattr *attr) 336static void get_correlation(struct Qdisc *sch, const struct nlattr *attr)
352{ 337{
353 struct netem_sched_data *q = qdisc_priv(sch); 338 struct netem_sched_data *q = qdisc_priv(sch);
354 const struct tc_netem_corr *c = nla_data(attr); 339 const struct tc_netem_corr *c = nla_data(attr);
@@ -356,27 +341,24 @@ static int get_correlation(struct Qdisc *sch, const struct nlattr *attr)
356 init_crandom(&q->delay_cor, c->delay_corr); 341 init_crandom(&q->delay_cor, c->delay_corr);
357 init_crandom(&q->loss_cor, c->loss_corr); 342 init_crandom(&q->loss_cor, c->loss_corr);
358 init_crandom(&q->dup_cor, c->dup_corr); 343 init_crandom(&q->dup_cor, c->dup_corr);
359 return 0;
360} 344}
361 345
362static int get_reorder(struct Qdisc *sch, const struct nlattr *attr) 346static void get_reorder(struct Qdisc *sch, const struct nlattr *attr)
363{ 347{
364 struct netem_sched_data *q = qdisc_priv(sch); 348 struct netem_sched_data *q = qdisc_priv(sch);
365 const struct tc_netem_reorder *r = nla_data(attr); 349 const struct tc_netem_reorder *r = nla_data(attr);
366 350
367 q->reorder = r->probability; 351 q->reorder = r->probability;
368 init_crandom(&q->reorder_cor, r->correlation); 352 init_crandom(&q->reorder_cor, r->correlation);
369 return 0;
370} 353}
371 354
372static int get_corrupt(struct Qdisc *sch, const struct nlattr *attr) 355static void get_corrupt(struct Qdisc *sch, const struct nlattr *attr)
373{ 356{
374 struct netem_sched_data *q = qdisc_priv(sch); 357 struct netem_sched_data *q = qdisc_priv(sch);
375 const struct tc_netem_corrupt *r = nla_data(attr); 358 const struct tc_netem_corrupt *r = nla_data(attr);
376 359
377 q->corrupt = r->probability; 360 q->corrupt = r->probability;
378 init_crandom(&q->corrupt_cor, r->correlation); 361 init_crandom(&q->corrupt_cor, r->correlation);
379 return 0;
380} 362}
381 363
382static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = { 364static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
@@ -435,11 +417,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
435 if (q->gap) 417 if (q->gap)
436 q->reorder = ~0; 418 q->reorder = ~0;
437 419
438 if (tb[TCA_NETEM_CORR]) { 420 if (tb[TCA_NETEM_CORR])
439 ret = get_correlation(sch, tb[TCA_NETEM_CORR]); 421 get_correlation(sch, tb[TCA_NETEM_CORR]);
440 if (ret)
441 return ret;
442 }
443 422
444 if (tb[TCA_NETEM_DELAY_DIST]) { 423 if (tb[TCA_NETEM_DELAY_DIST]) {
445 ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]); 424 ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
@@ -447,17 +426,11 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
447 return ret; 426 return ret;
448 } 427 }
449 428
450 if (tb[TCA_NETEM_REORDER]) { 429 if (tb[TCA_NETEM_REORDER])
451 ret = get_reorder(sch, tb[TCA_NETEM_REORDER]); 430 get_reorder(sch, tb[TCA_NETEM_REORDER]);
452 if (ret)
453 return ret;
454 }
455 431
456 if (tb[TCA_NETEM_CORRUPT]) { 432 if (tb[TCA_NETEM_CORRUPT])
457 ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT]); 433 get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
458 if (ret)
459 return ret;
460 }
461 434
462 return 0; 435 return 0;
463} 436}
@@ -538,7 +511,7 @@ static struct Qdisc_ops tfifo_qdisc_ops __read_mostly = {
538 .priv_size = sizeof(struct fifo_sched_data), 511 .priv_size = sizeof(struct fifo_sched_data),
539 .enqueue = tfifo_enqueue, 512 .enqueue = tfifo_enqueue,
540 .dequeue = qdisc_dequeue_head, 513 .dequeue = qdisc_dequeue_head,
541 .requeue = qdisc_requeue, 514 .peek = qdisc_peek_head,
542 .drop = qdisc_queue_drop, 515 .drop = qdisc_queue_drop,
543 .init = tfifo_init, 516 .init = tfifo_init,
544 .reset = qdisc_reset_queue, 517 .reset = qdisc_reset_queue,
@@ -621,99 +594,12 @@ nla_put_failure:
621 return -1; 594 return -1;
622} 595}
623 596
624static int netem_dump_class(struct Qdisc *sch, unsigned long cl,
625 struct sk_buff *skb, struct tcmsg *tcm)
626{
627 struct netem_sched_data *q = qdisc_priv(sch);
628
629 if (cl != 1) /* only one class */
630 return -ENOENT;
631
632 tcm->tcm_handle |= TC_H_MIN(1);
633 tcm->tcm_info = q->qdisc->handle;
634
635 return 0;
636}
637
638static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
639 struct Qdisc **old)
640{
641 struct netem_sched_data *q = qdisc_priv(sch);
642
643 if (new == NULL)
644 new = &noop_qdisc;
645
646 sch_tree_lock(sch);
647 *old = xchg(&q->qdisc, new);
648 qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
649 qdisc_reset(*old);
650 sch_tree_unlock(sch);
651
652 return 0;
653}
654
655static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
656{
657 struct netem_sched_data *q = qdisc_priv(sch);
658 return q->qdisc;
659}
660
661static unsigned long netem_get(struct Qdisc *sch, u32 classid)
662{
663 return 1;
664}
665
666static void netem_put(struct Qdisc *sch, unsigned long arg)
667{
668}
669
670static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
671 struct nlattr **tca, unsigned long *arg)
672{
673 return -ENOSYS;
674}
675
676static int netem_delete(struct Qdisc *sch, unsigned long arg)
677{
678 return -ENOSYS;
679}
680
681static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
682{
683 if (!walker->stop) {
684 if (walker->count >= walker->skip)
685 if (walker->fn(sch, 1, walker) < 0) {
686 walker->stop = 1;
687 return;
688 }
689 walker->count++;
690 }
691}
692
693static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl)
694{
695 return NULL;
696}
697
698static const struct Qdisc_class_ops netem_class_ops = {
699 .graft = netem_graft,
700 .leaf = netem_leaf,
701 .get = netem_get,
702 .put = netem_put,
703 .change = netem_change_class,
704 .delete = netem_delete,
705 .walk = netem_walk,
706 .tcf_chain = netem_find_tcf,
707 .dump = netem_dump_class,
708};
709
710static struct Qdisc_ops netem_qdisc_ops __read_mostly = { 597static struct Qdisc_ops netem_qdisc_ops __read_mostly = {
711 .id = "netem", 598 .id = "netem",
712 .cl_ops = &netem_class_ops,
713 .priv_size = sizeof(struct netem_sched_data), 599 .priv_size = sizeof(struct netem_sched_data),
714 .enqueue = netem_enqueue, 600 .enqueue = netem_enqueue,
715 .dequeue = netem_dequeue, 601 .dequeue = netem_dequeue,
716 .requeue = netem_requeue, 602 .peek = qdisc_peek_dequeued,
717 .drop = netem_drop, 603 .drop = netem_drop,
718 .init = netem_init, 604 .init = netem_init,
719 .reset = netem_reset, 605 .reset = netem_reset,