diff options
Diffstat (limited to 'net/sched/sch_netem.c')
-rw-r--r-- | net/sched/sch_netem.c | 160 |
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 */ | ||
249 | static 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 | |||
262 | static unsigned int netem_drop(struct Qdisc* sch) | 252 | static 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 | ||
351 | static int get_correlation(struct Qdisc *sch, const struct nlattr *attr) | 336 | static 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 | ||
362 | static int get_reorder(struct Qdisc *sch, const struct nlattr *attr) | 346 | static 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 | ||
372 | static int get_corrupt(struct Qdisc *sch, const struct nlattr *attr) | 355 | static 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 | ||
382 | static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = { | 364 | static 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 | ||
624 | static 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 | |||
638 | static 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 | |||
655 | static 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 | |||
661 | static unsigned long netem_get(struct Qdisc *sch, u32 classid) | ||
662 | { | ||
663 | return 1; | ||
664 | } | ||
665 | |||
666 | static void netem_put(struct Qdisc *sch, unsigned long arg) | ||
667 | { | ||
668 | } | ||
669 | |||
670 | static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | ||
671 | struct nlattr **tca, unsigned long *arg) | ||
672 | { | ||
673 | return -ENOSYS; | ||
674 | } | ||
675 | |||
676 | static int netem_delete(struct Qdisc *sch, unsigned long arg) | ||
677 | { | ||
678 | return -ENOSYS; | ||
679 | } | ||
680 | |||
681 | static 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 | |||
693 | static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl) | ||
694 | { | ||
695 | return NULL; | ||
696 | } | ||
697 | |||
698 | static 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 | |||
710 | static struct Qdisc_ops netem_qdisc_ops __read_mostly = { | 597 | static 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, |