fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / sched / sch_prio.c
index f8eafc5..2567b4c 100644 (file)
  *              Init --  EINVAL when opt undefined
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -47,60 +46,92 @@ struct prio_sched_data
 };
 
 
-static __inline__ unsigned prio_classify(struct sk_buff *skb, struct Qdisc *sch)
+static struct Qdisc *
+prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
+       u32 band = skb->priority;
        struct tcf_result res;
-       u32 band;
 
-       band = skb->priority;
+       *qerr = NET_XMIT_BYPASS;
        if (TC_H_MAJ(skb->priority) != sch->handle) {
+#ifdef CONFIG_NET_CLS_ACT
+               switch (tc_classify(skb, q->filter_list, &res)) {
+               case TC_ACT_STOLEN:
+               case TC_ACT_QUEUED:
+                       *qerr = NET_XMIT_SUCCESS;
+               case TC_ACT_SHOT:
+                       return NULL;
+               };
+
+               if (!q->filter_list ) {
+#else
                if (!q->filter_list || tc_classify(skb, q->filter_list, &res)) {
+#endif
                        if (TC_H_MAJ(band))
                                band = 0;
-                       return q->prio2band[band&TC_PRIO_MAX];
+                       return q->queues[q->prio2band[band&TC_PRIO_MAX]];
                }
                band = res.classid;
        }
        band = TC_H_MIN(band) - 1;
-       return band < q->bands ? band : q->prio2band[0];
+       if (band > q->bands)
+               return q->queues[q->prio2band[0]];
+
+       return q->queues[band];
 }
 
 static int
-prio_enqueue(struct sk_buff *skb, struct Qdiscsch)
+prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
        struct Qdisc *qdisc;
        int ret;
 
-       qdisc = q->queues[prio_classify(skb, sch)];
+       qdisc = prio_classify(skb, sch, &ret);
+#ifdef CONFIG_NET_CLS_ACT
+       if (qdisc == NULL) {
 
-       if ((ret = qdisc->enqueue(skb, qdisc)) == 0) {
-               sch->stats.bytes += skb->len;
-               sch->stats.packets++;
+               if (ret == NET_XMIT_BYPASS)
+                       sch->qstats.drops++;
+               kfree_skb(skb);
+               return ret;
+       }
+#endif
+
+       if ((ret = qdisc->enqueue(skb, qdisc)) == NET_XMIT_SUCCESS) {
+               sch->bstats.bytes += skb->len;
+               sch->bstats.packets++;
                sch->q.qlen++;
-               return 0;
+               return NET_XMIT_SUCCESS;
        }
-       sch->stats.drops++;
-       return ret;
+       sch->qstats.drops++;
+       return ret; 
 }
 
 
 static int
 prio_requeue(struct sk_buff *skb, struct Qdisc* sch)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
        struct Qdisc *qdisc;
        int ret;
 
-       qdisc = q->queues[prio_classify(skb, sch)];
+       qdisc = prio_classify(skb, sch, &ret);
+#ifdef CONFIG_NET_CLS_ACT
+       if (qdisc == NULL) {
+               if (ret == NET_XMIT_BYPASS)
+                       sch->qstats.drops++;
+               kfree_skb(skb);
+               return ret;
+       }
+#endif
 
-       if ((ret = qdisc->ops->requeue(skb, qdisc)) == 0) {
+       if ((ret = qdisc->ops->requeue(skb, qdisc)) == NET_XMIT_SUCCESS) {
                sch->q.qlen++;
+               sch->qstats.requeues++;
                return 0;
        }
-       sch->stats.drops++;
-       return ret;
+       sch->qstats.drops++;
+       return NET_XMIT_DROP;
 }
 
 
@@ -108,7 +139,7 @@ static struct sk_buff *
 prio_dequeue(struct Qdisc* sch)
 {
        struct sk_buff *skb;
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        int prio;
        struct Qdisc *qdisc;
 
@@ -126,14 +157,14 @@ prio_dequeue(struct Qdisc* sch)
 
 static unsigned int prio_drop(struct Qdisc* sch)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        int prio;
        unsigned int len;
        struct Qdisc *qdisc;
 
        for (prio = q->bands-1; prio >= 0; prio--) {
                qdisc = q->queues[prio];
-               if ((len = qdisc->ops->drop(qdisc)) != 0) {
+               if (qdisc->ops->drop && (len = qdisc->ops->drop(qdisc)) != 0) {
                        sch->q.qlen--;
                        return len;
                }
@@ -146,7 +177,7 @@ static void
 prio_reset(struct Qdisc* sch)
 {
        int prio;
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
 
        for (prio=0; prio<q->bands; prio++)
                qdisc_reset(q->queues[prio]);
@@ -157,7 +188,7 @@ static void
 prio_destroy(struct Qdisc* sch)
 {
        int prio;
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        struct tcf_proto *tp;
 
        while ((tp = q->filter_list) != NULL) {
@@ -165,15 +196,13 @@ prio_destroy(struct Qdisc* sch)
                tcf_destroy(tp);
        }
 
-       for (prio=0; prio<q->bands; prio++) {
+       for (prio=0; prio<q->bands; prio++)
                qdisc_destroy(q->queues[prio]);
-               q->queues[prio] = &noop_qdisc;
-       }
 }
 
 static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        struct tc_prio_qopt *qopt = RTA_DATA(opt);
        int i;
 
@@ -193,22 +222,27 @@ static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
 
        for (i=q->bands; i<TCQ_PRIO_BANDS; i++) {
                struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc);
-               if (child != &noop_qdisc)
+               if (child != &noop_qdisc) {
+                       qdisc_tree_decrease_qlen(child, child->q.qlen);
                        qdisc_destroy(child);
+               }
        }
        sch_tree_unlock(sch);
 
-       for (i=0; i<=TC_PRIO_MAX; i++) {
-               int band = q->prio2band[i];
-               if (q->queues[band] == &noop_qdisc) {
+       for (i=0; i<q->bands; i++) {
+               if (q->queues[i] == &noop_qdisc) {
                        struct Qdisc *child;
-                       child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
+                       child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+                                                 TC_H_MAKE(sch->handle, i + 1));
                        if (child) {
                                sch_tree_lock(sch);
-                               child = xchg(&q->queues[band], child);
+                               child = xchg(&q->queues[i], child);
 
-                               if (child != &noop_qdisc)
+                               if (child != &noop_qdisc) {
+                                       qdisc_tree_decrease_qlen(child,
+                                                                child->q.qlen);
                                        qdisc_destroy(child);
+                               }
                                sch_tree_unlock(sch);
                        }
                }
@@ -218,7 +252,7 @@ static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
 
 static int prio_init(struct Qdisc *sch, struct rtattr *opt)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        int i;
 
        for (i=0; i<TCQ_PRIO_BANDS; i++)
@@ -237,7 +271,7 @@ static int prio_init(struct Qdisc *sch, struct rtattr *opt)
 
 static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        unsigned char    *b = skb->tail;
        struct tc_prio_qopt opt;
 
@@ -254,7 +288,7 @@ rtattr_failure:
 static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
                      struct Qdisc **old)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        unsigned long band = arg - 1;
 
        if (band >= q->bands)
@@ -266,7 +300,7 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        sch_tree_lock(sch);
        *old = q->queues[band];
        q->queues[band] = new;
-       sch->q.qlen -= (*old)->q.qlen;
+       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
        qdisc_reset(*old);
        sch_tree_unlock(sch);
 
@@ -276,7 +310,7 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 static struct Qdisc *
 prio_leaf(struct Qdisc *sch, unsigned long arg)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        unsigned long band = arg - 1;
 
        if (band >= q->bands)
@@ -287,7 +321,7 @@ prio_leaf(struct Qdisc *sch, unsigned long arg)
 
 static unsigned long prio_get(struct Qdisc *sch, u32 classid)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        unsigned long band = TC_H_MIN(classid);
 
        if (band - 1 >= q->bands)
@@ -309,7 +343,7 @@ static void prio_put(struct Qdisc *q, unsigned long cl)
 static int prio_change(struct Qdisc *sch, u32 handle, u32 parent, struct rtattr **tca, unsigned long *arg)
 {
        unsigned long cl = *arg;
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
 
        if (cl - 1 > q->bands)
                return -ENOENT;
@@ -318,7 +352,7 @@ static int prio_change(struct Qdisc *sch, u32 handle, u32 parent, struct rtattr
 
 static int prio_delete(struct Qdisc *sch, unsigned long cl)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        if (cl - 1 > q->bands)
                return -ENOENT;
        return 0;
@@ -328,7 +362,7 @@ static int prio_delete(struct Qdisc *sch, unsigned long cl)
 static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb,
                           struct tcmsg *tcm)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
 
        if (cl - 1 > q->bands)
                return -ENOENT;
@@ -340,7 +374,7 @@ static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *
 
 static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
        int prio;
 
        if (arg->stop)
@@ -361,7 +395,7 @@ static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 
 static struct tcf_proto ** prio_find_tcf(struct Qdisc *sch, unsigned long cl)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       struct prio_sched_data *q = qdisc_priv(sch);
 
        if (cl)
                return NULL;