Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
[linux-drm-fsl-dcu.git] / net / sched / sch_netem.c
index 45939bafbdf894dfcb61a0ed993d1d79204aa5a8..1ccbfb55b0b8cf6f5e3ab76707cb1fc88e6f4015 100644 (file)
@@ -4,10 +4,10 @@
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
  *             as published by the Free Software Foundation; either version
- *             2 of the License, or (at your option) any later version.
+ *             2 of the License.
  *
  *             Many of the algorithms and ideas for this came from
- *             NIST Net which is not copyrighted. 
+ *             NIST Net which is not copyrighted.
  *
  * Authors:    Stephen Hemminger <shemminger@osdl.org>
  *             Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>
@@ -114,7 +114,7 @@ static unsigned long get_crandom(struct crndstate *state)
  * std deviation sigma.  Uses table lookup to approximate the desired
  * distribution, and a uniformly-distributed pseudo-random source.
  */
-static long tabledist(unsigned long mu, long sigma, 
+static long tabledist(unsigned long mu, long sigma,
                      struct crndstate *state, const struct disttable *dist)
 {
        long t, x;
@@ -126,7 +126,7 @@ static long tabledist(unsigned long mu, long sigma,
        rnd = get_crandom(state);
 
        /* default uniform distribution */
-       if (dist == NULL) 
+       if (dist == NULL)
                return (rnd % (2*sigma)) - sigma + mu;
 
        t = dist->table[rnd % dist->size];
@@ -170,6 +170,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return NET_XMIT_BYPASS;
        }
 
+       skb_orphan(skb);
+
        /*
         * If we need to duplicate packet, then re-insert at top of the
         * qdisc tree, since parent queuer expects that only one
@@ -216,7 +218,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                ++q->counter;
                ret = q->qdisc->enqueue(skb, q->qdisc);
        } else {
-               /* 
+               /*
                 * Do re-ordering by putting one out of N packets at the front
                 * of the queue.
                 */
@@ -285,13 +287,10 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
                        psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now);
 
                        if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
+                               qdisc_tree_decrease_qlen(q->qdisc, 1);
                                sch->qstats.drops++;
-
-                               /* After this qlen is confused */
                                printk(KERN_ERR "netem: queue discpline %s could not requeue\n",
                                       q->qdisc->ops->id);
-
-                               sch->q.qlen--;
                        }
 
                        mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay));
@@ -324,7 +323,7 @@ static void netem_reset(struct Qdisc *sch)
 /* Pass size change message down to embedded FIFO */
 static int set_fifo_limit(struct Qdisc *q, int limit)
 {
-        struct rtattr *rta;
+       struct rtattr *rta;
        int ret = -ENOMEM;
 
        /* Hack to avoid sending change message to non-FIFO */
@@ -334,9 +333,9 @@ static int set_fifo_limit(struct Qdisc *q, int limit)
        rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
        if (rta) {
                rta->rta_type = RTM_NEWQDISC;
-               rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); 
+               rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
                ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
-               
+
                ret = q->ops->change(q, rta);
                kfree(rta);
        }
@@ -365,7 +364,7 @@ static int get_dist_table(struct Qdisc *sch, const struct rtattr *attr)
        d->size = n;
        for (i = 0; i < n; i++)
                d->table[i] = data[i];
-       
+
        spin_lock_bh(&sch->dev->queue_lock);
        d = xchg(&q->delay_dist, d);
        spin_unlock_bh(&sch->dev->queue_lock);
@@ -420,7 +419,7 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt)
        struct netem_sched_data *q = qdisc_priv(sch);
        struct tc_netem_qopt *qopt;
        int ret;
-       
+
        if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt))
                return -EINVAL;
 
@@ -430,7 +429,7 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt)
                pr_debug("netem: can't set fifo limit\n");
                return ret;
        }
-       
+
        q->latency = qopt->latency;
        q->jitter = qopt->jitter;
        q->limit = qopt->limit;
@@ -446,10 +445,10 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt)
 
        /* Handle nested options after initial queue options.
         * Should have put all options in nested format but too late now.
-        */ 
+        */
        if (RTA_PAYLOAD(opt) > sizeof(*qopt)) {
                struct rtattr *tb[TCA_NETEM_MAX];
-               if (rtattr_parse(tb, TCA_NETEM_MAX, 
+               if (rtattr_parse(tb, TCA_NETEM_MAX,
                                 RTA_DATA(opt) + sizeof(*qopt),
                                 RTA_PAYLOAD(opt) - sizeof(*qopt)))
                        return -EINVAL;
@@ -572,7 +571,8 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt)
        q->timer.function = netem_watchdog;
        q->timer.data = (unsigned long) sch;
 
-       q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops);
+       q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,
+                                    TC_H_MAKE(sch->handle, 1));
        if (!q->qdisc) {
                pr_debug("netem: qdisc create failed\n");
                return -ENOMEM;
@@ -659,8 +659,8 @@ static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 
        sch_tree_lock(sch);
        *old = xchg(&q->qdisc, new);
+       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
        qdisc_reset(*old);
-       sch->q.qlen = 0;
        sch_tree_unlock(sch);
 
        return 0;
@@ -681,7 +681,7 @@ static void netem_put(struct Qdisc *sch, unsigned long arg)
 {
 }
 
-static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid, 
+static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                            struct rtattr **tca, unsigned long *arg)
 {
        return -ENOSYS;