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