Browse Source

[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 <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Patrick McHardy 17 years ago
parent
commit
94de78d195
2 changed files with 45 additions and 1 deletions
  1. 5 0
      include/linux/pkt_sched.h
  2. 40 1
      net/sched/sch_sfq.c

+ 5 - 0
include/linux/pkt_sched.h

@@ -150,6 +150,11 @@ struct tc_sfq_qopt
 	unsigned	flows;		/* Maximal number of flows  */
 	unsigned	flows;		/* Maximal number of flows  */
 };
 };
 
 
+struct tc_sfq_xstats
+{
+	__s32		allot;
+};
+
 /*
 /*
  *  NOTE: limit, divisor and flows are hardwired to code at the moment.
  *  NOTE: limit, divisor and flows are hardwired to code at the moment.
  *
  *

+ 40 - 1
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;
 	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)
 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 = {
 static const struct Qdisc_class_ops sfq_class_ops = {
 	.get		=	sfq_get,
 	.get		=	sfq_get,
 	.change		=	sfq_change_class,
 	.change		=	sfq_change_class,
 	.tcf_chain	=	sfq_find_tcf,
 	.tcf_chain	=	sfq_find_tcf,
+	.dump		=	sfq_dump_class,
+	.dump_stats	=	sfq_dump_class_stats,
 	.walk		=	sfq_walk,
 	.walk		=	sfq_walk,
 };
 };