X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsched%2Fsch_prio.c;h=3395ca7bcadfa76e3200e45cddf7944081965031;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=f8eafc50764475780d02ff64e1e69a0b2fb14342;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index f8eafc507..3395ca7bc 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -47,60 +47,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 Qdisc* sch) +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 == NET_XMIT_BYPASS) + sch->qstats.drops++; + kfree_skb(skb); + return ret; + } +#endif - if ((ret = qdisc->enqueue(skb, qdisc)) == 0) { - sch->stats.bytes += skb->len; - sch->stats.packets++; + 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 +140,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 +158,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 +178,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; priobands; prio++) qdisc_reset(q->queues[prio]); @@ -157,7 +189,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 +197,13 @@ prio_destroy(struct Qdisc* sch) tcf_destroy(tp); } - for (prio=0; priobands; prio++) { + for (prio=0; priobands; 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; @@ -198,14 +228,13 @@ static int prio_tune(struct Qdisc *sch, struct rtattr *opt) } 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; ibands; i++) { + if (q->queues[i] == &noop_qdisc) { struct Qdisc *child; child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); if (child) { sch_tree_lock(sch); - child = xchg(&q->queues[band], child); + child = xchg(&q->queues[i], child); if (child != &noop_qdisc) qdisc_destroy(child); @@ -218,7 +247,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; idata; + struct prio_sched_data *q = qdisc_priv(sch); unsigned char *b = skb->tail; struct tc_prio_qopt opt; @@ -254,7 +283,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) @@ -276,7 +305,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 +316,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 +338,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 +347,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 +357,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 +369,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 +390,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;