Merge to Fedora kernel-2.6.7-1.492
[linux-2.6.git] / net / sched / sch_prio.c
index f8eafc5..a13d219 100644 (file)
@@ -47,60 +47,103 @@ struct prio_sched_data
 };
 
 
-static __inline__ unsigned prio_classify(struct sk_buff *skb, struct Qdisc *sch)
+struct Qdisc *prio_classify(struct sk_buff *skb, struct Qdisc *sch,int *r)
 {
        struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+       u32 band = skb->priority;
        struct tcf_result res;
-       u32 band;
 
-       band = skb->priority;
        if (TC_H_MAJ(skb->priority) != sch->handle) {
+#ifdef CONFIG_NET_CLS_ACT
+               int result = 0, terminal = 0;
+               result = tc_classify(skb, q->filter_list, &res);
+
+               switch (result) {
+                       case TC_ACT_SHOT:
+                               *r = NET_XMIT_DROP;
+                               terminal = 1;
+                               break;
+                       case TC_ACT_STOLEN:
+                       case TC_ACT_QUEUED:
+                               terminal = 1;
+                               break;
+                       case TC_ACT_RECLASSIFY:
+                       case TC_ACT_OK:
+                       case TC_ACT_UNSPEC:
+                       default:
+                       break;
+               };
+               if (terminal) {
+                       kfree_skb(skb);
+                       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 Qdisc* sch)
 {
-       struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
        struct Qdisc *qdisc;
-       int ret;
+       int ret = NET_XMIT_SUCCESS;
+
+       qdisc = prio_classify(skb, sch, &ret);
 
-       qdisc = q->queues[prio_classify(skb, sch)];
+       if (NULL == qdisc)
+               goto dropped;
 
-       if ((ret = qdisc->enqueue(skb, qdisc)) == 0) {
+       if ((ret = qdisc->enqueue(skb, qdisc)) == NET_XMIT_SUCCESS) {
                sch->stats.bytes += skb->len;
                sch->stats.packets++;
                sch->q.qlen++;
-               return 0;
+               return NET_XMIT_SUCCESS;
        }
-       sch->stats.drops++;
-       return ret;
+
+dropped:
+#ifdef CONFIG_NET_CLS_ACT
+       if (NET_XMIT_DROP == ret) {
+#endif
+               sch->stats.drops++;
+#ifdef CONFIG_NET_CLS_ACT
+       } else {
+               sch->stats.overlimits++; /* abuse, but noone uses it */
+       }
+#endif
+       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;
+       int ret = NET_XMIT_DROP;
 
-       qdisc = q->queues[prio_classify(skb, sch)];
+       qdisc = prio_classify(skb, sch, &ret);
+       if (qdisc == NULL)
+               goto dropped;
 
        if ((ret = qdisc->ops->requeue(skb, qdisc)) == 0) {
                sch->q.qlen++;
                return 0;
        }
+dropped:
        sch->stats.drops++;
-       return ret;
+       return NET_XMIT_DROP;
 }