X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsched%2Fsch_prio.c;h=a13d219946924d71a405392cb9969b5a737ef9b7;hb=70790a4b5cd6c0291e5b1a2836e2832d46036ac6;hp=f8eafc50764475780d02ff64e1e69a0b2fb14342;hpb=413ba3004a4036bb5d6e52d2faa2b19cb13561dc;p=linux-2.6.git diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index f8eafc507..a13d21994 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -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; }