Merge to Fedora kernel-2.6.7-1.492
[linux-2.6.git] / net / sched / sch_cbq.c
index 16089ce..2d48488 100644 (file)
@@ -147,6 +147,7 @@ struct cbq_class
        long                    deficit;        /* Saved deficit for WRR */
        unsigned long           penalized;
        struct tc_stats         stats;
+       spinlock_t              *stats_lock;
        struct tc_cbq_xstats    xstats;
 
        struct tcf_proto        *filter_list;
@@ -238,7 +239,7 @@ cbq_reclassify(struct sk_buff *skb, struct cbq_class *this)
  */
 
 static struct cbq_class *
-cbq_classify(struct sk_buff *skb, struct Qdisc *sch)
+cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qres)
 {
        struct cbq_sched_data *q = (struct cbq_sched_data*)sch->data;
        struct cbq_class *head = &q->link;
@@ -256,7 +257,9 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch)
 
        for (;;) {
                int result = 0;
-
+#ifdef CONFIG_NET_CLS_ACT
+               int terminal = 0;
+#endif
                defmap = head->defaults;
 
                /*
@@ -275,6 +278,28 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch)
                                goto fallback;
                }
 
+#ifdef CONFIG_NET_CLS_ACT
+               switch (result) {
+               case TC_ACT_SHOT: /* Stop and kfree */
+                       *qres = NET_XMIT_DROP;
+                       terminal = 1;
+                       break;
+               case TC_ACT_QUEUED:
+               case TC_ACT_STOLEN: 
+                       terminal = 1;
+                       break;
+               case TC_ACT_RECLASSIFY:  /* Things look good */
+               case TC_ACT_OK: 
+               case TC_ACT_UNSPEC:
+               default:
+                       break;
+               }
+
+               if (terminal) {
+                       kfree_skb(skb);
+                       return NULL;
+               }
+#else
 #ifdef CONFIG_NET_CLS_POLICE
                switch (result) {
                case TC_POLICE_RECLASSIFY:
@@ -284,6 +309,7 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch)
                default:
                        break;
                }
+#endif
 #endif
                if (cl->level == 0)
                        return cl;
@@ -394,9 +420,9 @@ static int
 cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;
-       struct cbq_class *cl = cbq_classify(skb, sch);
        int len = skb->len;
-       int ret = NET_XMIT_POLICED;
+       int ret = NET_XMIT_SUCCESS;
+       struct cbq_class *cl = cbq_classify(skb, sch,&ret);
 
 #ifdef CONFIG_NET_CLS_POLICE
        q->rx_class = cl;
@@ -405,17 +431,18 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 #ifdef CONFIG_NET_CLS_POLICE
                cl->q->__parent = sch;
 #endif
-               if ((ret = cl->q->enqueue(skb, cl->q)) == 0) {
+               if ((ret = cl->q->enqueue(skb, cl->q)) == NET_XMIT_SUCCESS) {
                        sch->q.qlen++;
                        sch->stats.packets++;
                        sch->stats.bytes+=len;
                        cbq_mark_toplevel(q, cl);
                        if (!cl->next_alive)
                                cbq_activate_class(cl);
-                       return 0;
+                       return ret;
                }
        }
 
+#ifndef CONFIG_NET_CLS_ACT
        sch->stats.drops++;
        if (cl == NULL)
                kfree_skb(skb);
@@ -423,6 +450,16 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                cbq_mark_toplevel(q, cl);
                cl->stats.drops++;
        }
+#else
+       if ( NET_XMIT_DROP == ret) {
+               sch->stats.drops++;
+       }
+
+       if (cl != NULL) {
+               cbq_mark_toplevel(q, cl);
+               cl->stats.drops++;
+       }
+#endif
        return ret;
 }
 
@@ -1432,7 +1469,7 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt)
        q->link.ewma_log = TC_CBQ_DEF_EWMA;
        q->link.avpkt = q->link.allot/2;
        q->link.minidle = -0x7FFFFFFF;
-       q->link.stats.lock = &sch->dev->queue_lock;
+       q->link.stats_lock = &sch->dev->queue_lock;
 
        init_timer(&q->wd_timer);
        q->wd_timer.data = (unsigned long)sch;
@@ -1631,7 +1668,7 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg,
                goto rtattr_failure;
        rta->rta_len = skb->tail - b;
        cl->stats.qlen = cl->q->q.qlen;
-       if (qdisc_copy_stats(skb, &cl->stats))
+       if (qdisc_copy_stats(skb, &cl->stats, cl->stats_lock))
                goto rtattr_failure;
        spin_lock_bh(&sch->dev->queue_lock);
        cl->xstats.avgidle = cl->avgidle;
@@ -1861,7 +1898,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
 #ifdef CONFIG_NET_ESTIMATOR
                if (tca[TCA_RATE-1]) {
                        qdisc_kill_estimator(&cl->stats);
-                       qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]);
+                       qdisc_new_estimator(&cl->stats, cl->stats_lock,
+                                           tca[TCA_RATE-1]);
                }
 #endif
                return 0;
@@ -1922,7 +1960,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
        cl->allot = parent->allot;
        cl->quantum = cl->allot;
        cl->weight = cl->R_tab->rate.rate;
-       cl->stats.lock = &sch->dev->queue_lock;
+       cl->stats_lock = &sch->dev->queue_lock;
 
        sch_tree_lock(sch);
        cbq_link_class(cl);
@@ -1952,7 +1990,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
 
 #ifdef CONFIG_NET_ESTIMATOR
        if (tca[TCA_RATE-1])
-               qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]);
+               qdisc_new_estimator(&cl->stats, cl->stats_lock,
+                                   tca[TCA_RATE-1]);
 #endif
 
        *arg = (unsigned long)cl;