patch-2.2.4 linux/net/sched/sch_prio.c
Next file: linux/net/sched/sch_red.c
Previous file: linux/net/sched/sch_generic.c
Back to the patch index
Back to the overall index
- Lines: 197
- Date:
Sun Mar 21 07:22:00 1999
- Orig file:
v2.2.3/linux/net/sched/sch_prio.c
- Orig date:
Sat May 2 14:19:55 1998
diff -u --recursive --new-file v2.2.3/linux/net/sched/sch_prio.c linux/net/sched/sch_prio.c
@@ -49,17 +49,19 @@
{
struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
struct tcf_result res;
+ u32 band;
- res.classid = skb->priority;
- if (TC_H_MAJ(res.classid) != sch->handle) {
+ band = skb->priority;
+ if (TC_H_MAJ(skb->priority) != sch->handle) {
if (!q->filter_list || tc_classify(skb, q->filter_list, &res)) {
- if (TC_H_MAJ(res.classid))
- res.classid = 0;
- res.classid = q->prio2band[res.classid&TC_PRIO_MAX] + 1;
+ if (TC_H_MAJ(band))
+ band = 0;
+ return q->prio2band[band&TC_PRIO_MAX];
}
+ band = res.classid;
}
-
- return res.classid - 1;
+ band = TC_H_MIN(band) - 1;
+ return band < q->bands ? band : q->prio2band[0];
}
static int
@@ -160,38 +162,74 @@
MOD_DEC_USE_COUNT;
}
+static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
+{
+ struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+ struct tc_prio_qopt *qopt = RTA_DATA(opt);
+ int i;
+
+ if (opt->rta_len < RTA_LENGTH(sizeof(*qopt)))
+ return -EINVAL;
+ if (qopt->bands > TCQ_PRIO_BANDS || qopt->bands < 2)
+ return -EINVAL;
+
+ for (i=0; i<=TC_PRIO_MAX; i++) {
+ if (qopt->priomap[i] >= qopt->bands)
+ return -EINVAL;
+ }
+
+ start_bh_atomic();
+ q->bands = qopt->bands;
+ memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
+
+ for (i=q->bands; i<TCQ_PRIO_BANDS; i++) {
+ struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc);
+ if (child != &noop_qdisc)
+ qdisc_destroy(child);
+ }
+ end_bh_atomic();
+
+ for (i=0; i<=TC_PRIO_MAX; i++) {
+ int band = q->prio2band[i];
+ if (q->queues[band] == &noop_qdisc) {
+ struct Qdisc *child;
+ child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
+ if (child) {
+ net_serialize_enter();
+ child = xchg(&q->queues[band], child);
+ net_serialize_leave();
+ if (child != &noop_qdisc)
+ qdisc_destroy(child);
+ }
+ }
+ }
+ return 0;
+}
+
static int prio_init(struct Qdisc *sch, struct rtattr *opt)
{
static const u8 prio2band[TC_PRIO_MAX+1] =
{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 };
struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
- unsigned mask = 0;
int i;
+ for (i=0; i<TCQ_PRIO_BANDS; i++)
+ q->queues[i] = &noop_qdisc;
+
if (opt == NULL) {
q->bands = 3;
memcpy(q->prio2band, prio2band, sizeof(prio2band));
- mask = 7;
+ for (i=0; i<3; i++) {
+ struct Qdisc *child;
+ child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
+ if (child)
+ q->queues[i] = child;
+ }
} else {
- struct tc_prio_qopt *qopt = RTA_DATA(opt);
+ int err;
- if (opt->rta_len < RTA_LENGTH(sizeof(*qopt)))
- return -EINVAL;
- if (qopt->bands > TCQ_PRIO_BANDS)
- return -EINVAL;
- q->bands = qopt->bands;
- for (i=0; i<=TC_PRIO_MAX; i++) {
- if (qopt->priomap[i] >= q->bands)
- return -EINVAL;
- q->prio2band[i] = qopt->priomap[i];
- mask |= (1<<qopt->priomap[i]);
- }
- }
- for (i=0; i<TCQ_PRIO_BANDS; i++) {
- if (mask&(1<<i))
- q->queues[i] = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
- if (q->queues[i] == NULL)
- q->queues[i] = &noop_qdisc;
+ if ((err= prio_tune(sch, opt)) != 0)
+ return err;
}
MOD_INC_USE_COUNT;
return 0;
@@ -232,6 +270,18 @@
return 0;
}
+static struct Qdisc *
+prio_leaf(struct Qdisc *sch, unsigned long arg)
+{
+ struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+ unsigned long band = arg - 1;
+
+ if (band >= q->bands)
+ return NULL;
+
+ return q->queues[band];
+}
+
static unsigned long prio_get(struct Qdisc *sch, u32 classid)
{
struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
@@ -242,6 +292,12 @@
return band;
}
+static unsigned long prio_bind(struct Qdisc *sch, unsigned long parent, u32 classid)
+{
+ return prio_get(sch, classid);
+}
+
+
static void prio_put(struct Qdisc *q, unsigned long cl)
{
return;
@@ -267,12 +323,15 @@
#ifdef CONFIG_RTNETLINK
-static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm)
+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;
if (cl - 1 > q->bands)
return -ENOENT;
+ if (q->queues[cl-1])
+ tcm->tcm_info = q->queues[cl-1]->handle;
return 0;
}
#endif
@@ -310,6 +369,8 @@
static struct Qdisc_class_ops prio_class_ops =
{
prio_graft,
+ prio_leaf,
+
prio_get,
prio_put,
prio_change,
@@ -317,7 +378,7 @@
prio_walk,
prio_find_tcf,
- prio_get,
+ prio_bind,
prio_put,
#ifdef CONFIG_RTNETLINK
@@ -340,6 +401,7 @@
prio_init,
prio_reset,
prio_destroy,
+ prio_tune,
#ifdef CONFIG_RTNETLINK
prio_dump,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)