[NET_SCHED 03/04]: sch_sfq: make internal queues visible as classes
From: Patrick McHardy <hidden>
Date: 2008-01-31 17:58:07
Subsystem:
networking [general], tc subsystem, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim, Jiri Pirko, Linus Torvalds
[NET_SCHED]: sch_sfq: make internal queues visible as classes Add support for dumping statistics and make internal queues visible as classes. Signed-off-by: Patrick McHardy <redacted> --- commit 7a281f8ef334a35d699682315e9f80a3e006376c tree 0a2cbd55e22f1913e9cf0cc28da2956952110243 parent 6049892cc4acca9af393e134e4cdaf6b3e1ccad9 author Patrick McHardy [off-list ref] Wed, 30 Jan 2008 21:59:29 +0100 committer Patrick McHardy [off-list ref] Thu, 31 Jan 2008 18:52:56 +0100 include/linux/pkt_sched.h | 5 +++++ net/sched/sch_sfq.c | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletions(-)
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 3276135..dbb7ac3 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h@@ -150,6 +150,11 @@ struct tc_sfq_qopt unsigned flows; /* Maximal number of flows */ }; +struct tc_sfq_xstats +{ + __s32 allot; +}; + /* * NOTE: limit, divisor and flows are hardwired to code at the moment. *
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index d818d19..a20e2ef 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c@@ -566,15 +566,54 @@ static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl) return &q->filter_list; } +static int sfq_dump_class(struct Qdisc *sch, unsigned long cl, + struct sk_buff *skb, struct tcmsg *tcm) +{ + tcm->tcm_handle |= TC_H_MIN(cl); + return 0; +} + +static int sfq_dump_class_stats(struct Qdisc *sch, unsigned long cl, + struct gnet_dump *d) +{ + struct sfq_sched_data *q = qdisc_priv(sch); + sfq_index idx = q->ht[cl-1]; + struct gnet_stats_queue qs = { .qlen = q->qs[idx].qlen }; + struct tc_sfq_xstats xstats = { .allot = q->allot[idx] }; + + if (gnet_stats_copy_queue(d, &qs) < 0) + return -1; + return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); +} + static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg) { - return; + struct sfq_sched_data *q = qdisc_priv(sch); + unsigned int i; + + if (arg->stop) + return; + + for (i = 0; i < SFQ_HASH_DIVISOR; i++) { + if (q->ht[i] == SFQ_DEPTH || + arg->count < arg->skip) { + arg->count++; + continue; + } + if (arg->fn(sch, i + 1, arg) < 0) { + arg->stop = 1; + break; + } + arg->count++; + } } static const struct Qdisc_class_ops sfq_class_ops = { .get = sfq_get, .change = sfq_change_class, .tcf_chain = sfq_find_tcf, + .dump = sfq_dump_class, + .dump_stats = sfq_dump_class_stats, .walk = sfq_walk, };