netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/10] SFQ: backport some features from ESFQ (try 3)
@ 2007-08-25 22:26 Corey Hickey
  2007-08-25 22:26 ` [PATCH 01/10] Preparatory refactoring part 1 Corey Hickey
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:26 UTC (permalink / raw)
  To: netdev

Patchset try 2 addresses the review by Michael Buesch.
Patchset try 3 addresses the review by Patrick McHardy.

The first 7 patches in this series resemble the corresponding 7 patches
I sent previously. There aren't any major changes--just modifications
to address errors noticed in review and slight reorganizations to make
the next patches easier.

Patches 8-10 implement parameter passing via nested compat attributes.
This is necessary for using 'tc qdisc change' to disable perturbation.
The rest of the parameters were added for consistency.

Iproute2 patches will follow shortly.



The following is the original patch text.

This set of patches adds some of ESFQ's modifications to the original 
SFQ. Thus far, I have received support for this approach rather than for 
trying to get ESFQ included as a separate qdisc.

http://mailman.ds9a.nl/pipermail/lartc/2007q2/021056.html

My patches here implement "tc qdisc change", user-configurable depth 
(number of flows), and user-configurable divisor (for setting hash table 
size). I've left out the remaining ESFQ features (usage of jhash and 
different hashing methods) because Patrick McHardy intends to submit a 
patch that will supersede that functionality; see the URL above.

Default values remain the same, and SFQ's default behavior remains the 
same, so there should be no user disruption.

Thanks for your consideration,
Corey



 include/linux/pkt_sched.h |   23 ++-
 net/sched/sch_sfq.c       |  356 ++++++++++++++++++++++++++++++--------------
 2 files changed, 257 insertions(+), 122 deletions(-)


[PATCH 01/10] Preparatory refactoring part 1.
[PATCH 02/10] Preparatory refactoring part 2.
[PATCH 03/10] Move two functions.
[PATCH 04/10] Make "depth" (number of queues) user-configurable:
[PATCH 05/10] Add divisor.
[PATCH 06/10] Make qdisc changeable.
[PATCH 07/10] Remove comments about hardcoded values.
[PATCH 08/10] Multiply perturb_period by HZ when used rather than when assigned.
[PATCH 09/10] Change perturb_period to unsigned.
[PATCH 10/10] Use nested compat attributes to pass parameters.



^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 01/10] Preparatory refactoring part 1.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
@ 2007-08-25 22:26 ` Corey Hickey
  2007-08-25 22:26 ` [PATCH 02/10] Preparatory refactoring part 2 Corey Hickey
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:26 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

Make a new function sfq_q_enqueue() that operates directly on the
queue data. This will be useful for implementing sfq_change() in
a later patch. A pleasant side-effect is reducing most of the
duplicate code in sfq_enqueue() and sfq_requeue().

Similarly, make a new function sfq_q_dequeue().

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 net/sched/sch_sfq.c |   72 +++++++++++++++++++++++++++------------------------
 1 files changed, 38 insertions(+), 34 deletions(-)

diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 9579573..346e966 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -77,6 +77,9 @@
 #define SFQ_DEPTH		128
 #define SFQ_HASH_DIVISOR	1024
 
+#define SFQ_HEAD 0
+#define SFQ_TAIL 1
+
 /* This type should contain at least SFQ_DEPTH*2 values */
 typedef unsigned char sfq_index;
 
@@ -244,10 +247,9 @@ static unsigned int sfq_drop(struct Qdisc *sch)
 	return 0;
 }
 
-static int
-sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
+static void
+sfq_q_enqueue(struct sk_buff *skb, struct sfq_sched_data *q, unsigned int end)
 {
-	struct sfq_sched_data *q = qdisc_priv(sch);
 	unsigned hash = sfq_hash(q, skb);
 	sfq_index x;
 
@@ -256,8 +258,12 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 		q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
 		q->hash[x] = hash;
 	}
-	sch->qstats.backlog += skb->len;
-	__skb_queue_tail(&q->qs[x], skb);
+
+	if (end == SFQ_TAIL)
+		__skb_queue_tail(&q->qs[x], skb);
+	else
+		__skb_queue_head(&q->qs[x], skb);
+
 	sfq_inc(q, x);
 	if (q->qs[x].qlen == 1) {		/* The flow is new */
 		if (q->tail == SFQ_DEPTH) {	/* It is the first flow */
@@ -270,6 +276,15 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 			q->tail = x;
 		}
 	}
+}
+
+static int
+sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
+{
+	struct sfq_sched_data *q = qdisc_priv(sch);
+
+	sfq_q_enqueue(skb, q, SFQ_TAIL);
+	sch->qstats.backlog += skb->len;
 	if (++sch->q.qlen < q->limit-1) {
 		sch->bstats.bytes += skb->len;
 		sch->bstats.packets++;
@@ -284,45 +299,21 @@ static int
 sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
-	unsigned hash = sfq_hash(q, skb);
-	sfq_index x;
 
-	x = q->ht[hash];
-	if (x == SFQ_DEPTH) {
-		q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
-		q->hash[x] = hash;
-	}
+	sfq_q_enqueue(skb, q, SFQ_HEAD);
 	sch->qstats.backlog += skb->len;
-	__skb_queue_head(&q->qs[x], skb);
-	sfq_inc(q, x);
-	if (q->qs[x].qlen == 1) {		/* The flow is new */
-		if (q->tail == SFQ_DEPTH) {	/* It is the first flow */
-			q->tail = x;
-			q->next[x] = x;
-			q->allot[x] = q->quantum;
-		} else {
-			q->next[x] = q->next[q->tail];
-			q->next[q->tail] = x;
-			q->tail = x;
-		}
-	}
 	if (++sch->q.qlen < q->limit - 1) {
 		sch->qstats.requeues++;
 		return 0;
 	}
 
-	sch->qstats.drops++;
 	sfq_drop(sch);
 	return NET_XMIT_CN;
 }
 
-
-
-
-static struct sk_buff *
-sfq_dequeue(struct Qdisc* sch)
+static struct
+sk_buff *sfq_q_dequeue(struct sfq_sched_data *q)
 {
-	struct sfq_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
 	sfq_index a, old_a;
 
@@ -335,8 +326,6 @@ sfq_dequeue(struct Qdisc* sch)
 	/* Grab packet */
 	skb = __skb_dequeue(&q->qs[a]);
 	sfq_dec(q, a);
-	sch->q.qlen--;
-	sch->qstats.backlog -= skb->len;
 
 	/* Is the slot empty? */
 	if (q->qs[a].qlen == 0) {
@@ -353,6 +342,21 @@ sfq_dequeue(struct Qdisc* sch)
 		a = q->next[a];
 		q->allot[a] += q->quantum;
 	}
+
+	return skb;
+}
+
+static struct sk_buff
+*sfq_dequeue(struct Qdisc* sch)
+{
+	struct sfq_sched_data *q = qdisc_priv(sch);
+	struct sk_buff *skb;
+
+	skb = sfq_q_dequeue(q);
+	if (skb == NULL)
+		return NULL;
+	sch->q.qlen--;
+	sch->qstats.backlog -= skb->len;
 	return skb;
 }
 
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 02/10] Preparatory refactoring part 2.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
  2007-08-25 22:26 ` [PATCH 01/10] Preparatory refactoring part 1 Corey Hickey
@ 2007-08-25 22:26 ` Corey Hickey
  2007-08-25 22:26 ` [PATCH 03/10] Move two functions Corey Hickey
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:26 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

Factor code out of sfq_init() and sfq_destroy(), again so that the
new functions can be used by sfq_change() later.

Actually, as the diff itself shows, most of the sfq_q_init() code
comes from the original sfq_change(), but sfq_change() is only
called by sfq_init() right now. Thus, it is safe to remove
sfq_change(); "tc qdisc change" doesn't yet work for sfq anyway.

Setting default parameters is moved into a separate function for
clarity.

The sfq_destroy() --> sfq_q_destroy() change looks pointless here,
but it's cleaner to split now and add code to sfq_q_destroy() in a
later patch.

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 net/sched/sch_sfq.c |   96 +++++++++++++++++++++++++++++----------------------
 1 files changed, 55 insertions(+), 41 deletions(-)

diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 346e966..f95a0dc 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -382,43 +382,42 @@ static void sfq_perturbation(unsigned long arg)
 	}
 }
 
-static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
+static void
+sfq_default_parameters(struct Qdisc *sch)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
-	struct tc_sfq_qopt *ctl = RTA_DATA(opt);
-	unsigned int qlen;
-
-	if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
-		return -EINVAL;
-
-	sch_tree_lock(sch);
-	q->quantum = ctl->quantum ? : psched_mtu(sch->dev);
-	q->perturb_period = ctl->perturb_period*HZ;
-	if (ctl->limit)
-		q->limit = min_t(u32, ctl->limit, SFQ_DEPTH);
 
-	qlen = sch->q.qlen;
-	while (sch->q.qlen >= q->limit-1)
-		sfq_drop(sch);
-	qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
-
-	del_timer(&q->perturb_timer);
-	if (q->perturb_period) {
-		q->perturb_timer.expires = jiffies + q->perturb_period;
-		add_timer(&q->perturb_timer);
-	}
-	sch_tree_unlock(sch);
-	return 0;
+	q->quantum = psched_mtu(sch->dev);
+	q->perturbation = 0;
+	q->perturb_period = 0;
+	q->limit = SFQ_DEPTH;
 }
 
-static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
+
+static int
+sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 {
-	struct sfq_sched_data *q = qdisc_priv(sch);
 	int i;
 
-	init_timer(&q->perturb_timer);
-	q->perturb_timer.data = (unsigned long)sch;
-	q->perturb_timer.function = sfq_perturbation;
+	/* At this point, parameters are set to either defaults (sfq_init) or
+	 * the previous values (sfq_change). So, overwrite the parameters as
+	 * specified. */
+	if (opt) {
+		struct tc_sfq_qopt *ctl = RTA_DATA(opt);
+
+		if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
+			return -EINVAL;
+
+		if (ctl->quantum)
+			q->quantum = ctl->quantum;
+		if (ctl->perturb_period)
+			q->perturb_period = ctl->perturb_period * HZ;
+		if (ctl->limit)
+			q->limit = ctl->limit;
+	}
+	q->limit = min_t(u32, q->limit, SFQ_DEPTH);
+	q->tail = SFQ_DEPTH;
+	q->max_depth = 0;
 
 	for (i=0; i<SFQ_HASH_DIVISOR; i++)
 		q->ht[i] = SFQ_DEPTH;
@@ -427,28 +426,43 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
 		q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH;
 		q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH;
 	}
-	q->limit = SFQ_DEPTH;
-	q->max_depth = 0;
-	q->tail = SFQ_DEPTH;
-	if (opt == NULL) {
-		q->quantum = psched_mtu(sch->dev);
-		q->perturb_period = 0;
-	} else {
-		int err = sfq_change(sch, opt);
-		if (err)
-			return err;
-	}
+
 	for (i=0; i<SFQ_DEPTH; i++)
 		sfq_link(q, i);
 	return 0;
 }
 
-static void sfq_destroy(struct Qdisc *sch)
+static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
+	int err;
+
+	sfq_default_parameters(sch);
+	if ((err = sfq_q_init(q, opt)))
+		return err;
+
+	init_timer(&q->perturb_timer);
+	q->perturb_timer.data = (unsigned long)sch;
+	q->perturb_timer.function = sfq_perturbation;
+	if (q->perturb_period) {
+		q->perturb_timer.expires = jiffies + q->perturb_period;
+		add_timer(&q->perturb_timer);
+	}
+
+	return 0;
+}
+
+static void sfq_q_destroy(struct sfq_sched_data *q)
+{
 	del_timer(&q->perturb_timer);
 }
 
+static void sfq_destroy(struct Qdisc *sch)
+{
+	struct sfq_sched_data *q = qdisc_priv(sch);
+	sfq_q_destroy(q);
+}
+
 static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 03/10] Move two functions.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
  2007-08-25 22:26 ` [PATCH 01/10] Preparatory refactoring part 1 Corey Hickey
  2007-08-25 22:26 ` [PATCH 02/10] Preparatory refactoring part 2 Corey Hickey
@ 2007-08-25 22:26 ` Corey Hickey
  2007-08-25 22:26 ` [PATCH 04/10] Make "depth" (number of queues) user-configurable: Corey Hickey
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:26 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

Move sfq_q_destroy() to above sfq_q_init() so that it can be used
by an error case in a later patch.

Move sfq_destroy() as well, for clarity.

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 net/sched/sch_sfq.c |   22 +++++++++++-----------
 1 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index f95a0dc..676195d 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -382,6 +382,17 @@ static void sfq_perturbation(unsigned long arg)
 	}
 }
 
+static void sfq_q_destroy(struct sfq_sched_data *q)
+{
+	del_timer(&q->perturb_timer);
+}
+
+static void sfq_destroy(struct Qdisc *sch)
+{
+	struct sfq_sched_data *q = qdisc_priv(sch);
+	sfq_q_destroy(q);
+}
+
 static void
 sfq_default_parameters(struct Qdisc *sch)
 {
@@ -452,17 +463,6 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
 	return 0;
 }
 
-static void sfq_q_destroy(struct sfq_sched_data *q)
-{
-	del_timer(&q->perturb_timer);
-}
-
-static void sfq_destroy(struct Qdisc *sch)
-{
-	struct sfq_sched_data *q = qdisc_priv(sch);
-	sfq_q_destroy(q);
-}
-
 static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 04/10] Make "depth" (number of queues) user-configurable:
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
                   ` (2 preceding siblings ...)
  2007-08-25 22:26 ` [PATCH 03/10] Move two functions Corey Hickey
@ 2007-08-25 22:26 ` Corey Hickey
  2007-08-25 22:26 ` [PATCH 05/10] Add divisor Corey Hickey
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:26 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

* replace #define with a parameter
* use old hardcoded value as a default
* kcalloc() arrays in sfq_q_init()
* free() arrays in sfq_q_destroy()

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 net/sched/sch_sfq.c |   84 +++++++++++++++++++++++++++++++++++----------------
 1 files changed, 58 insertions(+), 26 deletions(-)

diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 676195d..2e6d607 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -74,14 +74,16 @@
 
 	It is easy to increase these values, but not in flight.  */
 
-#define SFQ_DEPTH		128
+#define SFQ_DEPTH_DEFAULT	128
 #define SFQ_HASH_DIVISOR	1024
 
 #define SFQ_HEAD 0
 #define SFQ_TAIL 1
 
-/* This type should contain at least SFQ_DEPTH*2 values */
-typedef unsigned char sfq_index;
+/* This type must contain greater than depth*2 values, so depth is constrained 
+ * accordingly. */
+typedef unsigned int sfq_index;
+#define SFQ_MAX_DEPTH (UINT_MAX / 2 - 1)
 
 struct sfq_head
 {
@@ -95,6 +97,7 @@ struct sfq_sched_data
 	int		perturb_period;
 	unsigned	quantum;	/* Allotment per round: MUST BE >= MTU */
 	int		limit;
+	unsigned	depth;
 
 /* Variables */
 	struct timer_list perturb_timer;
@@ -103,11 +106,11 @@ struct sfq_sched_data
 	sfq_index	max_depth;	/* Maximal depth */
 
 	sfq_index	ht[SFQ_HASH_DIVISOR];	/* Hash table */
-	sfq_index	next[SFQ_DEPTH];	/* Active slots link */
-	short		allot[SFQ_DEPTH];	/* Current allotment per slot */
-	unsigned short	hash[SFQ_DEPTH];	/* Hash value indexed by slots */
-	struct sk_buff_head	qs[SFQ_DEPTH];		/* Slot queue */
-	struct sfq_head	dep[SFQ_DEPTH*2];	/* Linked list of slots, indexed by depth */
+	sfq_index	*next;			/* Active slots link */
+	short		*allot;			/* Current allotment per slot */
+	unsigned short	*hash;			/* Hash value indexed by slots */
+	struct sk_buff_head	*qs;		/* Slot queue */
+	struct sfq_head	*dep;			/* Linked list of slots, indexed by depth */
 };
 
 static __inline__ unsigned sfq_fold_hash(struct sfq_sched_data *q, u32 h, u32 h1)
@@ -164,7 +167,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
 static inline void sfq_link(struct sfq_sched_data *q, sfq_index x)
 {
 	sfq_index p, n;
-	int d = q->qs[x].qlen + SFQ_DEPTH;
+	int d = q->qs[x].qlen + q->depth;
 
 	p = d;
 	n = q->dep[d].next;
@@ -215,7 +218,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
 	   drop a packet from it */
 
 	if (d > 1) {
-		sfq_index x = q->dep[d+SFQ_DEPTH].next;
+		sfq_index x = q->dep[d + q->depth].next;
 		skb = q->qs[x].prev;
 		len = skb->len;
 		__skb_unlink(skb, &q->qs[x]);
@@ -238,7 +241,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
 		kfree_skb(skb);
 		sfq_dec(q, d);
 		sch->q.qlen--;
-		q->ht[q->hash[d]] = SFQ_DEPTH;
+		q->ht[q->hash[d]] = q->depth;
 		sch->qstats.drops++;
 		sch->qstats.backlog -= len;
 		return len;
@@ -254,8 +257,8 @@ sfq_q_enqueue(struct sk_buff *skb, struct sfq_sched_data *q, unsigned int end)
 	sfq_index x;
 
 	x = q->ht[hash];
-	if (x == SFQ_DEPTH) {
-		q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
+	if (x == q->depth) {
+		q->ht[hash] = x = q->dep[q->depth].next;
 		q->hash[x] = hash;
 	}
 
@@ -266,7 +269,7 @@ sfq_q_enqueue(struct sk_buff *skb, struct sfq_sched_data *q, unsigned int end)
 
 	sfq_inc(q, x);
 	if (q->qs[x].qlen == 1) {		/* The flow is new */
-		if (q->tail == SFQ_DEPTH) {	/* It is the first flow */
+		if (q->tail == q->depth) {	/* It is the first flow */
 			q->tail = x;
 			q->next[x] = x;
 			q->allot[x] = q->quantum;
@@ -318,7 +321,7 @@ sk_buff *sfq_q_dequeue(struct sfq_sched_data *q)
 	sfq_index a, old_a;
 
 	/* No active slots */
-	if (q->tail == SFQ_DEPTH)
+	if (q->tail == q->depth)
 		return NULL;
 
 	a = old_a = q->next[q->tail];
@@ -329,10 +332,10 @@ sk_buff *sfq_q_dequeue(struct sfq_sched_data *q)
 
 	/* Is the slot empty? */
 	if (q->qs[a].qlen == 0) {
-		q->ht[q->hash[a]] = SFQ_DEPTH;
+		q->ht[q->hash[a]] = q->depth;
 		a = q->next[a];
 		if (a == old_a) {
-			q->tail = SFQ_DEPTH;
+			q->tail = q->depth;
 			return skb;
 		}
 		q->next[q->tail] = a;
@@ -385,6 +388,11 @@ static void sfq_perturbation(unsigned long arg)
 static void sfq_q_destroy(struct sfq_sched_data *q)
 {
 	del_timer(&q->perturb_timer);
+	kfree(q->dep);
+	kfree(q->next);
+	kfree(q->allot);
+	kfree(q->hash);
+	kfree(q->qs);
 }
 
 static void sfq_destroy(struct Qdisc *sch)
@@ -401,7 +409,7 @@ sfq_default_parameters(struct Qdisc *sch)
 	q->quantum = psched_mtu(sch->dev);
 	q->perturbation = 0;
 	q->perturb_period = 0;
-	q->limit = SFQ_DEPTH;
+	q->limit = q->depth = SFQ_DEPTH_DEFAULT;
 }
 
 
@@ -423,24 +431,48 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 			q->quantum = ctl->quantum;
 		if (ctl->perturb_period)
 			q->perturb_period = ctl->perturb_period * HZ;
+		if (ctl->flows)
+			q->depth = ctl->flows;
 		if (ctl->limit)
 			q->limit = ctl->limit;
+
+		if (q->depth > SFQ_MAX_DEPTH)
+			return -EINVAL;
 	}
-	q->limit = min_t(u32, q->limit, SFQ_DEPTH);
-	q->tail = SFQ_DEPTH;
+	q->limit = min_t(u32, q->limit, q->depth);
+	q->tail = q->depth;
 	q->max_depth = 0;
 
+	q->dep = kcalloc(1 + q->depth*2, sizeof(struct sfq_head), GFP_KERNEL);
+	if (!q->dep)
+		goto err_case;
+	q->next = kcalloc(q->depth, sizeof(sfq_index), GFP_KERNEL);
+	if (!q->next)
+		goto err_case;
+	q->allot = kcalloc(q->depth, sizeof(short), GFP_KERNEL);
+	if (!q->allot)
+		goto err_case;
+	q->hash = kcalloc(q->depth, sizeof(unsigned short), GFP_KERNEL);
+	if (!q->hash)
+		goto err_case;
+	q->qs = kcalloc(q->depth, sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!q->qs)
+		goto err_case;
+
 	for (i=0; i<SFQ_HASH_DIVISOR; i++)
-		q->ht[i] = SFQ_DEPTH;
-	for (i=0; i<SFQ_DEPTH; i++) {
+		q->ht[i] = q->depth;
+	for (i=0; i < q->depth; i++) {
 		skb_queue_head_init(&q->qs[i]);
-		q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH;
-		q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH;
+		q->dep[i + q->depth].next = i + q->depth;
+		q->dep[i + q->depth].prev = i + q->depth;
 	}
 
-	for (i=0; i<SFQ_DEPTH; i++)
+	for (i=0; i < q->depth; i++)
 		sfq_link(q, i);
 	return 0;
+err_case:
+	sfq_q_destroy(q);
+	return -ENOBUFS;
 }
 
 static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
@@ -474,7 +506,7 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 
 	opt.limit = q->limit;
 	opt.divisor = SFQ_HASH_DIVISOR;
-	opt.flows = q->limit;
+	opt.flows = q->depth;
 
 	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
 
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 05/10] Add divisor.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
                   ` (3 preceding siblings ...)
  2007-08-25 22:26 ` [PATCH 04/10] Make "depth" (number of queues) user-configurable: Corey Hickey
@ 2007-08-25 22:26 ` Corey Hickey
  2007-08-25 22:27 ` [PATCH 06/10] Make qdisc changeable Corey Hickey
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:26 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

Make hash divisor user-configurable.

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 net/sched/sch_sfq.c |   18 +++++++++++++-----
 1 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 2e6d607..827b885 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -75,7 +75,7 @@
 	It is easy to increase these values, but not in flight.  */
 
 #define SFQ_DEPTH_DEFAULT	128
-#define SFQ_HASH_DIVISOR	1024
+#define SFQ_DIVISOR_DEFAULT	1024
 
 #define SFQ_HEAD 0
 #define SFQ_TAIL 1
@@ -98,6 +98,7 @@ struct sfq_sched_data
 	unsigned	quantum;	/* Allotment per round: MUST BE >= MTU */
 	int		limit;
 	unsigned	depth;
+	unsigned	hash_divisor;
 
 /* Variables */
 	struct timer_list perturb_timer;
@@ -105,7 +106,7 @@ struct sfq_sched_data
 	sfq_index	tail;		/* Index of current slot in round */
 	sfq_index	max_depth;	/* Maximal depth */
 
-	sfq_index	ht[SFQ_HASH_DIVISOR];	/* Hash table */
+	sfq_index	*ht;			/* Hash table */
 	sfq_index	*next;			/* Active slots link */
 	short		*allot;			/* Current allotment per slot */
 	unsigned short	*hash;			/* Hash value indexed by slots */
@@ -120,7 +121,7 @@ static __inline__ unsigned sfq_fold_hash(struct sfq_sched_data *q, u32 h, u32 h1
 	/* Have we any rotation primitives? If not, WHY? */
 	h ^= (h1<<pert) ^ (h1>>(0x1F - pert));
 	h ^= h>>10;
-	return h & 0x3FF;
+	return h & (q->hash_divisor-1);
 }
 
 static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
@@ -388,6 +389,7 @@ static void sfq_perturbation(unsigned long arg)
 static void sfq_q_destroy(struct sfq_sched_data *q)
 {
 	del_timer(&q->perturb_timer);
+	kfree(q->ht);
 	kfree(q->dep);
 	kfree(q->next);
 	kfree(q->allot);
@@ -409,6 +411,7 @@ sfq_default_parameters(struct Qdisc *sch)
 	q->quantum = psched_mtu(sch->dev);
 	q->perturbation = 0;
 	q->perturb_period = 0;
+	q->hash_divisor = SFQ_DIVISOR_DEFAULT;
 	q->limit = q->depth = SFQ_DEPTH_DEFAULT;
 }
 
@@ -431,6 +434,8 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 			q->quantum = ctl->quantum;
 		if (ctl->perturb_period)
 			q->perturb_period = ctl->perturb_period * HZ;
+		if (ctl->divisor)
+			q->hash_divisor = ctl->divisor;
 		if (ctl->flows)
 			q->depth = ctl->flows;
 		if (ctl->limit)
@@ -443,6 +448,9 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 	q->tail = q->depth;
 	q->max_depth = 0;
 
+	q->ht = kcalloc(q->hash_divisor, sizeof(sfq_index), GFP_KERNEL);
+	if (!q->ht)
+		goto err_case;
 	q->dep = kcalloc(1 + q->depth*2, sizeof(struct sfq_head), GFP_KERNEL);
 	if (!q->dep)
 		goto err_case;
@@ -459,7 +467,7 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 	if (!q->qs)
 		goto err_case;
 
-	for (i=0; i<SFQ_HASH_DIVISOR; i++)
+	for (i=0; i<q->hash_divisor; i++)
 		q->ht[i] = q->depth;
 	for (i=0; i < q->depth; i++) {
 		skb_queue_head_init(&q->qs[i]);
@@ -505,7 +513,7 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 	opt.perturb_period = q->perturb_period/HZ;
 
 	opt.limit = q->limit;
-	opt.divisor = SFQ_HASH_DIVISOR;
+	opt.divisor = q->hash_divisor;
 	opt.flows = q->depth;
 
 	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 06/10] Make qdisc changeable.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
                   ` (4 preceding siblings ...)
  2007-08-25 22:26 ` [PATCH 05/10] Add divisor Corey Hickey
@ 2007-08-25 22:27 ` Corey Hickey
  2007-08-25 22:27 ` [PATCH 07/10] Remove comments about hardcoded values Corey Hickey
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:27 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

Re-implement sfq_change() and enable Qdisc_opts.change so "tc qdisc
change" will work.

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 net/sched/sch_sfq.c |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 63 insertions(+), 1 deletions(-)

diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 827b885..08e6862 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -415,6 +415,16 @@ sfq_default_parameters(struct Qdisc *sch)
 	q->limit = q->depth = SFQ_DEPTH_DEFAULT;
 }
 
+static void
+sfq_copy_parameters(struct sfq_sched_data *dst, struct sfq_sched_data *src)
+{
+	dst->quantum        = src->quantum;
+	dst->perturbation   = src->perturbation;
+	dst->perturb_period = src->perturb_period;
+	dst->hash_divisor   = src->hash_divisor;
+	dst->limit          = src->limit;
+	dst->depth          = src->depth;
+}
 
 static int
 sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
@@ -503,6 +513,58 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
 	return 0;
 }
 
+static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
+{
+	struct sfq_sched_data *q = qdisc_priv(sch);
+	struct sfq_sched_data tmp;
+	struct sk_buff *skb;
+	unsigned int qlen;
+	int err;
+	
+	/* set up tmp queue */
+	memset(&tmp, 0, sizeof(struct sfq_sched_data));
+	sfq_copy_parameters(&tmp, q);
+	if ((err = sfq_q_init(&tmp, opt)))
+		return err;
+
+	/* copy packets from the old queue to the tmp queue */
+	sch_tree_lock(sch);
+	qlen = sch->q.qlen;
+	while (sch->q.qlen >= tmp.limit - 1)
+		sfq_drop(sch);
+	qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+	while ((skb = sfq_q_dequeue(q)) != NULL)
+		sfq_q_enqueue(skb, &tmp, SFQ_TAIL);
+	
+	/* clean up the old queue */
+	sfq_q_destroy(q);
+
+	/* copy elements of the tmp queue into the old queue */
+	q->perturb_period = tmp.perturb_period;
+	q->quantum        = tmp.quantum;
+	q->limit          = tmp.limit;
+	q->depth          = tmp.depth;
+	q->hash_divisor   = tmp.hash_divisor;
+	q->tail           = tmp.tail;
+	q->max_depth      = tmp.max_depth;
+	q->ht    = tmp.ht;
+	q->dep   = tmp.dep;
+	q->next  = tmp.next;
+	q->allot = tmp.allot;
+	q->hash  = tmp.hash;
+	q->qs    = tmp.qs;
+
+	/* finish up */
+	if (q->perturb_period) {
+		q->perturb_timer.expires = jiffies + q->perturb_period;
+		add_timer(&q->perturb_timer);
+	} else {
+		q->perturbation = 0;
+	}
+	sch_tree_unlock(sch);
+	return 0;
+}
+
 static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
@@ -537,7 +599,7 @@ static struct Qdisc_ops sfq_qdisc_ops = {
 	.init		=	sfq_init,
 	.reset		=	sfq_reset,
 	.destroy	=	sfq_destroy,
-	.change		=	NULL,
+	.change		=	sfq_change,
 	.dump		=	sfq_dump,
 	.owner		=	THIS_MODULE,
 };
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 07/10] Remove comments about hardcoded values.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
                   ` (5 preceding siblings ...)
  2007-08-25 22:27 ` [PATCH 06/10] Make qdisc changeable Corey Hickey
@ 2007-08-25 22:27 ` Corey Hickey
  2007-08-25 22:27 ` [PATCH 08/10] Multiply perturb_period by HZ when used rather than when assigned Corey Hickey
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:27 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

None of these are true anymore (hooray!).

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 include/linux/pkt_sched.h |    8 --------
 net/sched/sch_sfq.c       |   17 +++--------------
 2 files changed, 3 insertions(+), 22 deletions(-)

diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 268c515..58a0ea6 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -148,14 +148,6 @@ struct tc_sfq_qopt
 	unsigned	flows;		/* Maximal number of flows  */
 };
 
-/*
- *  NOTE: limit, divisor and flows are hardwired to code at the moment.
- *
- *	limit=flows=128, divisor=1024;
- *
- *	The only reason for this is efficiency, it is possible
- *	to change these parameters in compile time.
- */
 
 /* RED section */
 
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 08e6862..77ffce3 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -61,18 +61,7 @@
 
 	We still need true WFQ for top level CSZ, but using WFQ
 	for the best effort traffic is absolutely pointless:
-	SFQ is superior for this purpose.
-
-	IMPLEMENTATION:
-	This implementation limits maximal queue length to 128;
-	maximal mtu to 2^15-1; number of hash buckets to 1024.
-	The only goal of this restrictions was that all data
-	fit into one 4K page :-). Struct sfq_sched_data is
-	organized in anti-cache manner: all the data for a bucket
-	are scattered over different locations. This is not good,
-	but it allowed me to put it into 4K.
-
-	It is easy to increase these values, but not in flight.  */
+	SFQ is superior for this purpose. */
 
 #define SFQ_DEPTH_DEFAULT	128
 #define SFQ_DIVISOR_DEFAULT	1024
@@ -520,7 +509,7 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
 	struct sk_buff *skb;
 	unsigned int qlen;
 	int err;
-	
+
 	/* set up tmp queue */
 	memset(&tmp, 0, sizeof(struct sfq_sched_data));
 	sfq_copy_parameters(&tmp, q);
@@ -535,7 +524,7 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
 	qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
 	while ((skb = sfq_q_dequeue(q)) != NULL)
 		sfq_q_enqueue(skb, &tmp, SFQ_TAIL);
-	
+
 	/* clean up the old queue */
 	sfq_q_destroy(q);
 
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 08/10] Multiply perturb_period by HZ when used rather than when assigned.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
                   ` (6 preceding siblings ...)
  2007-08-25 22:27 ` [PATCH 07/10] Remove comments about hardcoded values Corey Hickey
@ 2007-08-25 22:27 ` Corey Hickey
  2007-08-25 22:27 ` [PATCH 09/10] Change perturb_period to unsigned Corey Hickey
  2007-08-25 22:27 ` [PATCH 10/10] Use nested compat attributes to pass parameters Corey Hickey
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:27 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

perturb_period is the only parameter that doesn't match 1:1 with the
value from userspace. This change makes it easy and clean to use a
small macro for setting parameters (in a subsequent patch).

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 net/sched/sch_sfq.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 77ffce3..f9f4460 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -370,7 +370,7 @@ static void sfq_perturbation(unsigned long arg)
 	q->perturbation = net_random()&0x1F;
 
 	if (q->perturb_period) {
-		q->perturb_timer.expires = jiffies + q->perturb_period;
+		q->perturb_timer.expires = jiffies + q->perturb_period * HZ;
 		add_timer(&q->perturb_timer);
 	}
 }
@@ -432,7 +432,7 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 		if (ctl->quantum)
 			q->quantum = ctl->quantum;
 		if (ctl->perturb_period)
-			q->perturb_period = ctl->perturb_period * HZ;
+			q->perturb_period = ctl->perturb_period;
 		if (ctl->divisor)
 			q->hash_divisor = ctl->divisor;
 		if (ctl->flows)
@@ -495,7 +495,7 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
 	q->perturb_timer.data = (unsigned long)sch;
 	q->perturb_timer.function = sfq_perturbation;
 	if (q->perturb_period) {
-		q->perturb_timer.expires = jiffies + q->perturb_period;
+		q->perturb_timer.expires = jiffies + q->perturb_period * HZ;
 		add_timer(&q->perturb_timer);
 	}
 
@@ -545,7 +545,7 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
 
 	/* finish up */
 	if (q->perturb_period) {
-		q->perturb_timer.expires = jiffies + q->perturb_period;
+		q->perturb_timer.expires = jiffies + q->perturb_period * HZ;
 		add_timer(&q->perturb_timer);
 	} else {
 		q->perturbation = 0;
@@ -561,7 +561,7 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 	struct tc_sfq_qopt opt;
 
 	opt.quantum = q->quantum;
-	opt.perturb_period = q->perturb_period/HZ;
+	opt.perturb_period = q->perturb_period;
 
 	opt.limit = q->limit;
 	opt.divisor = q->hash_divisor;
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 09/10] Change perturb_period to unsigned.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
                   ` (7 preceding siblings ...)
  2007-08-25 22:27 ` [PATCH 08/10] Multiply perturb_period by HZ when used rather than when assigned Corey Hickey
@ 2007-08-25 22:27 ` Corey Hickey
  2007-08-25 22:27 ` [PATCH 10/10] Use nested compat attributes to pass parameters Corey Hickey
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:27 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

perturb_period is currently a signed integer, but I can't see any good
reason why this is so--a negative perturbation period will add a timer
that expires in the past, causing constant perturbation, which makes
hashing useless.

	if (q->perturb_period) {
		q->perturb_timer.expires = jiffies + q->perturb_period;
		add_timer(&q->perturb_timer);
	}

Strictly speaking, this will break binary compatibility with older
versions of tc, but that ought not to be a problem because (a) there's
no valid use for a negative perturb_period, and (b) negative values
will be seen as high values (> INT_MAX), which don't work anyway.

If perturb_period is too large, (perturb_period * HZ) will overflow the
size of an unsigned int and wrap around. So, check for thet and reject
values that are too high.

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 include/linux/pkt_sched.h |    2 +-
 net/sched/sch_sfq.c       |    8 ++++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 58a0ea6..8559974 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -142,7 +142,7 @@ enum
 struct tc_sfq_qopt
 {
 	unsigned	quantum;	/* Bytes per round allocated to flow */
-	int		perturb_period;	/* Period of hash perturbation */
+	unsigned	perturb_period;	/* Period of hash perturbation */
 	__u32		limit;		/* Maximal packets in queue */
 	unsigned	divisor;	/* Hash divisor  */
 	unsigned	flows;		/* Maximal number of flows  */
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index f9f4460..157adc8 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -74,6 +74,9 @@
 typedef unsigned int sfq_index;
 #define SFQ_MAX_DEPTH (UINT_MAX / 2 - 1)
 
+/* We don't want perturb_period * HZ to overflow an unsigned int. */
+#define SFQ_MAX_PERTURB (UINT_MAX / HZ)
+
 struct sfq_head
 {
 	sfq_index	next;
@@ -83,7 +86,7 @@ struct sfq_head
 struct sfq_sched_data
 {
 /* Parameters */
-	int		perturb_period;
+	unsigned	perturb_period;
 	unsigned	quantum;	/* Allotment per round: MUST BE >= MTU */
 	int		limit;
 	unsigned	depth;
@@ -440,7 +443,8 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 		if (ctl->limit)
 			q->limit = ctl->limit;
 
-		if (q->depth > SFQ_MAX_DEPTH)
+		if (q->perturb_period > SFQ_MAX_PERTURB ||
+		    q->depth > SFQ_MAX_DEPTH)
 			return -EINVAL;
 	}
 	q->limit = min_t(u32, q->limit, q->depth);
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 10/10] Use nested compat attributes to pass parameters.
  2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
                   ` (8 preceding siblings ...)
  2007-08-25 22:27 ` [PATCH 09/10] Change perturb_period to unsigned Corey Hickey
@ 2007-08-25 22:27 ` Corey Hickey
  9 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-08-25 22:27 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

This fixes the ambiguity between, for example:
tc qdisc change ... perturb 0
tc qdisc change ...

Without this patch, there is no way for SFQ to differentiate between
a parameter specified to be 0 and a parameter that was omitted.

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 include/linux/pkt_sched.h |   13 +++++++++++
 net/sched/sch_sfq.c       |   53 +++++++++++++++++++++++++++++---------------
 2 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 8559974..aad04eb 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -148,6 +148,19 @@ struct tc_sfq_qopt
 	unsigned	flows;		/* Maximal number of flows  */
 };
 
+enum
+{
+	TCA_SFQ_UNSPEC,
+	TCA_SFQ_COMPAT,
+	TCA_SFQ_QUANTUM,
+	TCA_SFQ_PERTURB,
+	TCA_SFQ_LIMIT,
+	TCA_SFQ_DIVISOR,
+	TCA_SFQ_FLOWS,
+	__TCA_SFQ_MAX,
+};
+
+#define TCA_SFQ_MAX (__TCA_SFQ_MAX - 1)
 
 /* RED section */
 
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 157adc8..62232c9 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -427,25 +427,31 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 	 * the previous values (sfq_change). So, overwrite the parameters as
 	 * specified. */
 	if (opt) {
-		struct tc_sfq_qopt *ctl = RTA_DATA(opt);
-
-		if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
-			return -EINVAL;
-
-		if (ctl->quantum)
-			q->quantum = ctl->quantum;
-		if (ctl->perturb_period)
-			q->perturb_period = ctl->perturb_period;
-		if (ctl->divisor)
-			q->hash_divisor = ctl->divisor;
-		if (ctl->flows)
-			q->depth = ctl->flows;
-		if (ctl->limit)
-			q->limit = ctl->limit;
-
+		struct tc_sfq_qopt *ctl;
+		struct rtattr *tb[TCA_SFQ_MAX];
+
+		if (rtattr_parse_nested_compat(tb, TCA_SFQ_MAX, opt, ctl,
+				       sizeof(*ctl)))
+			goto rtattr_failure;
+
+#define GET_PARAM(dst, nest, compat) do { \
+	struct rtattr *rta = tb[(nest) - 1]; \
+	if (rta) \
+		(dst) = RTA_GET_U32(rta); \
+	else if ((compat)) \
+		(dst) = (compat); \
+} while (0)
+
+		GET_PARAM(q->quantum,        TCA_SFQ_QUANTUM, ctl->quantum);
+		GET_PARAM(q->perturb_period, TCA_SFQ_PERTURB,
+				ctl->perturb_period);
+		GET_PARAM(q->hash_divisor,   TCA_SFQ_DIVISOR, ctl->divisor);
+		GET_PARAM(q->depth,          TCA_SFQ_FLOWS,   ctl->flows);
+		GET_PARAM(q->limit,          TCA_SFQ_LIMIT,   ctl->limit);
+		
 		if (q->perturb_period > SFQ_MAX_PERTURB ||
 		    q->depth > SFQ_MAX_DEPTH)
-			return -EINVAL;
+			goto rtattr_failure;
 	}
 	q->limit = min_t(u32, q->limit, q->depth);
 	q->tail = q->depth;
@@ -481,6 +487,8 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 	for (i=0; i < q->depth; i++)
 		sfq_link(q, i);
 	return 0;
+rtattr_failure:
+	return -EINVAL;
 err_case:
 	sfq_q_destroy(q);
 	return -ENOBUFS;
@@ -562,17 +570,26 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
 	unsigned char *b = skb_tail_pointer(skb);
+	struct rtattr *nest;
 	struct tc_sfq_qopt opt;
 
 	opt.quantum = q->quantum;
 	opt.perturb_period = q->perturb_period;
-
 	opt.limit = q->limit;
 	opt.divisor = q->hash_divisor;
 	opt.flows = q->depth;
 
+	nest = RTA_NEST_COMPAT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+
+	RTA_PUT_U32(skb, TCA_SFQ_QUANTUM, q->quantum);
+	RTA_PUT_U32(skb, TCA_SFQ_PERTURB, q->perturb_period);
+	RTA_PUT_U32(skb, TCA_SFQ_LIMIT,   q->limit);
+	RTA_PUT_U32(skb, TCA_SFQ_DIVISOR, q->hash_divisor);
+	RTA_PUT_U32(skb, TCA_SFQ_FLOWS,   q->depth);
 	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
 
+	RTA_NEST_COMPAT_END(skb, nest);
+
 	return skb->len;
 
 rtattr_failure:
-- 
1.5.2.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 09/10] Change perturb_period to unsigned.
  2007-09-28 22:52 SFQ: backport some features from ESFQ (try 4) Corey Hickey
@ 2007-09-28 22:52 ` Corey Hickey
  2007-10-01 13:45   ` Patrick McHardy
  0 siblings, 1 reply; 14+ messages in thread
From: Corey Hickey @ 2007-09-28 22:52 UTC (permalink / raw)
  To: netdev; +Cc: Corey Hickey

perturb_period is currently a signed integer, but I can't see any good
reason why this is so--a negative perturbation period will add a timer
that expires in the past, causing constant perturbation, which makes
hashing useless.

	if (q->perturb_period) {
		q->perturb_timer.expires = jiffies + q->perturb_period;
		add_timer(&q->perturb_timer);
	}

Strictly speaking, this will break binary compatibility with older
versions of tc, but that ought not to be a problem because (a) there's
no valid use for a negative perturb_period, and (b) negative values
will be seen as high values (> INT_MAX), which don't work anyway.

If perturb_period is too large, (perturb_period * HZ) will overflow the
size of an unsigned int and wrap around. So, check for thet and reject
values that are too high.

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 include/linux/pkt_sched.h |    2 +-
 net/sched/sch_sfq.c       |    8 ++++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 58a0ea6..8559974 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -142,7 +142,7 @@ enum
 struct tc_sfq_qopt
 {
 	unsigned	quantum;	/* Bytes per round allocated to flow */
-	int		perturb_period;	/* Period of hash perturbation */
+	unsigned	perturb_period;	/* Period of hash perturbation */
 	__u32		limit;		/* Maximal packets in queue */
 	unsigned	divisor;	/* Hash divisor  */
 	unsigned	flows;		/* Maximal number of flows  */
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 2d3cc38..170fd37 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -74,6 +74,9 @@
 typedef unsigned int sfq_index;
 #define SFQ_MAX_DEPTH (UINT_MAX / 2 - 1)
 
+/* We don't want perturb_period * HZ to overflow an unsigned int. */
+#define SFQ_MAX_PERTURB (UINT_MAX / HZ)
+
 struct sfq_head
 {
 	sfq_index	next;
@@ -83,7 +86,7 @@ struct sfq_head
 struct sfq_sched_data
 {
 /* Parameters */
-	int		perturb_period;
+	unsigned	perturb_period;
 	unsigned	quantum;	/* Allotment per round: MUST BE >= MTU */
 	int		limit;
 	unsigned	depth;
@@ -441,7 +444,8 @@ sfq_q_init(struct sfq_sched_data *q, struct rtattr *opt)
 		if (ctl->limit)
 			q->limit = ctl->limit;
 
-		if (q->depth > SFQ_MAX_DEPTH)
+		if (q->perturb_period > SFQ_MAX_PERTURB ||
+		    q->depth > SFQ_MAX_DEPTH)
 			return -EINVAL;
 	}
 	q->limit = min_t(u32, q->limit, q->depth - 2);
-- 
1.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 09/10] Change perturb_period to unsigned.
  2007-09-28 22:52 ` [PATCH 09/10] Change perturb_period to unsigned Corey Hickey
@ 2007-10-01 13:45   ` Patrick McHardy
  2007-10-01 20:47     ` Corey Hickey
  0 siblings, 1 reply; 14+ messages in thread
From: Patrick McHardy @ 2007-10-01 13:45 UTC (permalink / raw)
  To: Corey Hickey; +Cc: netdev

Corey Hickey wrote:
> perturb_period is currently a signed integer, but I can't see any good
> reason why this is so--a negative perturbation period will add a timer
> that expires in the past, causing constant perturbation, which makes
> hashing useless.
> 
> 	if (q->perturb_period) {
> 		q->perturb_timer.expires = jiffies + q->perturb_period;
> 		add_timer(&q->perturb_timer);
> 	}
> 
> Strictly speaking, this will break binary compatibility with older
> versions of tc, but that ought not to be a problem because (a) there's
> no valid use for a negative perturb_period, and (b) negative values
> will be seen as high values (> INT_MAX), which don't work anyway.
> 
> If perturb_period is too large, (perturb_period * HZ) will overflow the
> size of an unsigned int and wrap around. So, check for thet and reject
> values that are too high.


Sounds reasonable.

> --- a/net/sched/sch_sfq.c
> +++ b/net/sched/sch_sfq.c
> @@ -74,6 +74,9 @@
>  typedef unsigned int sfq_index;
>  #define SFQ_MAX_DEPTH (UINT_MAX / 2 - 1)
>  
> +/* We don't want perturb_period * HZ to overflow an unsigned int. */
> +#define SFQ_MAX_PERTURB (UINT_MAX / HZ)


jiffies are unsigned long.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 09/10] Change perturb_period to unsigned.
  2007-10-01 13:45   ` Patrick McHardy
@ 2007-10-01 20:47     ` Corey Hickey
  0 siblings, 0 replies; 14+ messages in thread
From: Corey Hickey @ 2007-10-01 20:47 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev

Patrick McHardy wrote:
> Corey Hickey wrote:
>> perturb_period is currently a signed integer, but I can't see any good
>> reason why this is so--a negative perturbation period will add a timer
>> that expires in the past, causing constant perturbation, which makes
>> hashing useless.
>>
>> 	if (q->perturb_period) {
>> 		q->perturb_timer.expires = jiffies + q->perturb_period;
>> 		add_timer(&q->perturb_timer);
>> 	}
>>
>> Strictly speaking, this will break binary compatibility with older
>> versions of tc, but that ought not to be a problem because (a) there's
>> no valid use for a negative perturb_period, and (b) negative values
>> will be seen as high values (> INT_MAX), which don't work anyway.
>>
>> If perturb_period is too large, (perturb_period * HZ) will overflow the
>> size of an unsigned int and wrap around. So, check for thet and reject
>> values that are too high.
> 
> 
> Sounds reasonable.
> 
>> --- a/net/sched/sch_sfq.c
>> +++ b/net/sched/sch_sfq.c
>> @@ -74,6 +74,9 @@
>>  typedef unsigned int sfq_index;
>>  #define SFQ_MAX_DEPTH (UINT_MAX / 2 - 1)
>>  
>> +/* We don't want perturb_period * HZ to overflow an unsigned int. */
>> +#define SFQ_MAX_PERTURB (UINT_MAX / HZ)
> 
> 
> jiffies are unsigned long.

Hmm. You're right. It looks like my previous patch obviated the need for 
this part. I'll remove it.

-Corey

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2007-10-01 20:47 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-25 22:26 [PATCH 00/10] SFQ: backport some features from ESFQ (try 3) Corey Hickey
2007-08-25 22:26 ` [PATCH 01/10] Preparatory refactoring part 1 Corey Hickey
2007-08-25 22:26 ` [PATCH 02/10] Preparatory refactoring part 2 Corey Hickey
2007-08-25 22:26 ` [PATCH 03/10] Move two functions Corey Hickey
2007-08-25 22:26 ` [PATCH 04/10] Make "depth" (number of queues) user-configurable: Corey Hickey
2007-08-25 22:26 ` [PATCH 05/10] Add divisor Corey Hickey
2007-08-25 22:27 ` [PATCH 06/10] Make qdisc changeable Corey Hickey
2007-08-25 22:27 ` [PATCH 07/10] Remove comments about hardcoded values Corey Hickey
2007-08-25 22:27 ` [PATCH 08/10] Multiply perturb_period by HZ when used rather than when assigned Corey Hickey
2007-08-25 22:27 ` [PATCH 09/10] Change perturb_period to unsigned Corey Hickey
2007-08-25 22:27 ` [PATCH 10/10] Use nested compat attributes to pass parameters Corey Hickey
  -- strict thread matches above, loose matches on Subject: below --
2007-09-28 22:52 SFQ: backport some features from ESFQ (try 4) Corey Hickey
2007-09-28 22:52 ` [PATCH 09/10] Change perturb_period to unsigned Corey Hickey
2007-10-01 13:45   ` Patrick McHardy
2007-10-01 20:47     ` Corey Hickey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).