=======================================
Sources: [1] Sally Floyd and Van Jacobson, "Link-sharing and Resource
- Management Models for Packet Networks",
+ Management Models for Packet Networks",
IEEE/ACM Transactions on Networking, Vol.3, No.4, 1995
- [2] Sally Floyd, "Notes on CBQ and Guaranteed Service", 1995
+ [2] Sally Floyd, "Notes on CBQ and Guaranteed Service", 1995
- [3] Sally Floyd, "Notes on Class-Based Queueing: Setting
+ [3] Sally Floyd, "Notes on Class-Based Queueing: Setting
Parameters", 1996
[4] Sally Floyd and Michael Speer, "Experimental Results
the implementation is different. Particularly:
--- The WRR algorithm is different. Our version looks more
- reasonable (I hope) and works when quanta are allowed to be
- less than MTU, which is always the case when real time classes
- have small rates. Note, that the statement of [3] is
- incomplete, delay may actually be estimated even if class
- per-round allotment is less than MTU. Namely, if per-round
- allotment is W*r_i, and r_1+...+r_k = r < 1
+ reasonable (I hope) and works when quanta are allowed to be
+ less than MTU, which is always the case when real time classes
+ have small rates. Note, that the statement of [3] is
+ incomplete, delay may actually be estimated even if class
+ per-round allotment is less than MTU. Namely, if per-round
+ allotment is W*r_i, and r_1+...+r_k = r < 1
delay_i <= ([MTU/(W*r_i)]*W*r + W*r + k*MTU)/B
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
case TC_ACT_QUEUED:
- case TC_ACT_STOLEN:
+ case TC_ACT_STOLEN:
*qerr = NET_XMIT_SUCCESS;
case TC_ACT_SHOT:
return NULL;
return;
}
}
-
- cl = cl_prev->next_alive;
return;
}
} while ((cl_prev = cl) != q->active[prio]);
if (!cl->delayed) {
delay += cl->offtime;
- /*
+ /*
Class goes to sleep, so that it will have no
chance to work avgidle. Let's forgive it 8)
}
#endif
-/*
+/*
It is mission critical procedure.
We "regenerate" toplevel cutoff, if transmitting class
}
} while ((borrowed=borrowed->borrow) != NULL);
}
-#if 0
+#if 0
/* It is not necessary now. Uncommenting it
will save CPU cycles, but decrease fairness.
*/
(now - last) is total time between packet right edges.
(last_pktlen/rate) is "virtual" busy time, so that
- idle = (now - last) - last_pktlen/rate
+ idle = (now - last) - last_pktlen/rate
*/
idle = PSCHED_TDIFF(q->now, cl->last);
skb = cl->q->dequeue(cl->q);
/* Class did not give us any skb :-(
- It could occur even if cl->q->q.qlen != 0
+ It could occur even if cl->q->q.qlen != 0
f.e. if cl->q == "tbf"
*/
if (skb == NULL)
do {
if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) {
sch->q.qlen--;
+ if (!cl->q->q.qlen)
+ cbq_deactivate_class(cl);
return len;
}
} while ((cl = cl->next_alive) != cl_head);
q->link.sibling = &q->link;
q->link.classid = sch->handle;
q->link.qdisc = sch;
- if (!(q->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops)))
+ if (!(q->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+ sch->handle)))
q->link.q = &noop_qdisc;
q->link.priority = TC_CBQ_MAXPRIO-1;
if (cl) {
if (new == NULL) {
- if ((new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops)) == NULL)
+ if ((new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+ cl->classid)) == NULL)
return -ENOBUFS;
} else {
#ifdef CONFIG_NET_CLS_POLICE
#endif
}
sch_tree_lock(sch);
- *old = cl->q;
- cl->q = new;
- sch->q.qlen -= (*old)->q.qlen;
+ *old = xchg(&cl->q, new);
+ qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
qdisc_reset(*old);
sch_tree_unlock(sch);
return cl ? cl->q : NULL;
}
+static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg)
+{
+ struct cbq_class *cl = (struct cbq_class *)arg;
+
+ if (cl->q->q.qlen == 0)
+ cbq_deactivate_class(cl);
+}
+
static unsigned long cbq_get(struct Qdisc *sch, u32 classid)
{
struct cbq_sched_data *q = qdisc_priv(sch);
}
err = -ENOBUFS;
- cl = kmalloc(sizeof(*cl), GFP_KERNEL);
+ cl = kzalloc(sizeof(*cl), GFP_KERNEL);
if (cl == NULL)
goto failure;
- memset(cl, 0, sizeof(*cl));
cl->R_tab = rtab;
rtab = NULL;
cl->refcnt = 1;
- if (!(cl->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops)))
+ if (!(cl->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
cl->q = &noop_qdisc;
cl->classid = classid;
cl->tparent = parent;
{
struct cbq_sched_data *q = qdisc_priv(sch);
struct cbq_class *cl = (struct cbq_class*)arg;
+ unsigned int qlen;
if (cl->filters || cl->children || cl == &q->link)
return -EBUSY;
sch_tree_lock(sch);
+ qlen = cl->q->q.qlen;
+ qdisc_reset(cl->q);
+ qdisc_tree_decrease_qlen(cl->q, qlen);
+
if (cl->next_alive)
cbq_deactivate_class(cl);
static struct Qdisc_class_ops cbq_class_ops = {
.graft = cbq_graft,
.leaf = cbq_leaf,
+ .qlen_notify = cbq_qlen_notify,
.get = cbq_get,
.put = cbq_put,
.change = cbq_change_class,
{
return register_qdisc(&cbq_qdisc_ops);
}
-static void __exit cbq_module_exit(void)
+static void __exit cbq_module_exit(void)
{
unregister_qdisc(&cbq_qdisc_ops);
}