netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC 0/3] Add generic size table for qdiscs
@ 2008-07-17 10:09 Jussi Kivilinna
  2008-07-17 10:09 ` [PATCH RFC 1/3] net_sched: Add qdisc_enqueue wrapper Jussi Kivilinna
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Jussi Kivilinna @ 2008-07-17 10:09 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev

[Resend one patch per mail]

Here's first version of generic size table feature. Didn't get chance to
test too much yet but hfsc&sfq seems to be ok.

---

Jussi Kivilinna (3):
      net_sched: Add size table for qdiscs
      net_sched: Add accessor function for packet length for qdiscs
      net_sched: Add qdisc_enqueue wrapper


 include/linux/pkt_sched.h |   21 ++++++++
 include/linux/rtnetlink.h |    1
 include/net/pkt_sched.h   |    1
 include/net/sch_generic.h |   50 +++++++++++++++++--
 net/core/dev.c            |    3 +
 net/mac80211/wme.c        |    2 -
 net/sched/sch_api.c       |  117 ++++++++++++++++++++++++++++++++++++++++++++-
 net/sched/sch_atm.c       |    6 +-
 net/sched/sch_cbq.c       |   19 +++----
 net/sched/sch_dsmark.c    |    4 +-
 net/sched/sch_fifo.c      |    2 -
 net/sched/sch_generic.c   |    1
 net/sched/sch_gred.c      |   12 ++---
 net/sched/sch_hfsc.c      |   16 +++---
 net/sched/sch_htb.c       |   12 ++---
 net/sched/sch_netem.c     |   26 ++++++----
 net/sched/sch_prio.c      |    5 +-
 net/sched/sch_red.c       |    4 +-
 net/sched/sch_sfq.c       |   16 +++---
 net/sched/sch_tbf.c       |   12 +++--
 net/sched/sch_teql.c      |    6 +-
 21 files changed, 259 insertions(+), 77 deletions(-)

--

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

* [PATCH RFC 1/3] net_sched: Add qdisc_enqueue wrapper
  2008-07-17 10:09 [PATCH RFC 0/3] Add generic size table for qdiscs Jussi Kivilinna
@ 2008-07-17 10:09 ` Jussi Kivilinna
  2008-07-17 10:10   ` Patrick McHardy
  2008-07-17 10:09 ` [PATCH RFC 2/3] net_sched: Add accessor function for packet length for qdiscs Jussi Kivilinna
  2008-07-17 10:09 ` [PATCH RFC 3/3] net_sched: Add size table " Jussi Kivilinna
  2 siblings, 1 reply; 11+ messages in thread
From: Jussi Kivilinna @ 2008-07-17 10:09 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---

 include/net/sch_generic.h |    5 +++++
 net/core/dev.c            |    2 +-
 net/mac80211/wme.c        |    2 +-
 net/sched/sch_atm.c       |    2 +-
 net/sched/sch_cbq.c       |    5 +++--
 net/sched/sch_dsmark.c    |    2 +-
 net/sched/sch_hfsc.c      |    2 +-
 net/sched/sch_htb.c       |    3 +--
 net/sched/sch_netem.c     |   19 +++++++++++--------
 net/sched/sch_prio.c      |    3 ++-
 net/sched/sch_red.c       |    2 +-
 net/sched/sch_tbf.c       |    3 ++-
 12 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 5ba66b5..e3b0d71 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -258,6 +258,11 @@ static inline bool qdisc_tx_is_noop(const struct net_device *dev)
 	return (txq->qdisc == &noop_qdisc);
 }
 
+static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	return sch->enqueue(skb, sch);
+}
+
 static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 				       struct sk_buff_head *list)
 {
diff --git a/net/core/dev.c b/net/core/dev.c
index 9b49f74..ee2df34 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1733,7 +1733,7 @@ gso:
 		if (q->enqueue) {
 			/* reset queue_mapping to zero */
 			skb_set_queue_mapping(skb, 0);
-			rc = q->enqueue(skb, q);
+			rc = qdisc_enqueue(skb, q);
 			qdisc_run(txq);
 			spin_unlock(&txq->lock);
 
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 6ae43a3..e263917 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -212,7 +212,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 	} else {
 		skb_set_queue_mapping(skb, queue);
 		qdisc = q->queues[queue];
-		err = qdisc->enqueue(skb, qdisc);
+		err = qdisc_enqueue(skb, qdisc);
 		if (err == NET_XMIT_SUCCESS) {
 			qd->q.qlen++;
 			qd->bstats.bytes += skb->len;
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 0de757e..68ed35e 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -429,7 +429,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 #endif
 	}
 
-	ret = flow->q->enqueue(skb, flow->q);
+	ret = qdisc_enqueue(skb, flow->q);
 	if (ret != 0) {
 drop: __maybe_unused
 		sch->qstats.drops++;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 4efc836..1bcb3e8 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -387,7 +387,8 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 #ifdef CONFIG_NET_CLS_ACT
 	cl->q->__parent = sch;
 #endif
-	if ((ret = cl->q->enqueue(skb, cl->q)) == NET_XMIT_SUCCESS) {
+	ret = qdisc_enqueue(skb, cl->q);
+	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->bstats.packets++;
 		sch->bstats.bytes+=len;
@@ -671,7 +672,7 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
 		q->rx_class = cl;
 		cl->q->__parent = sch;
 
-		if (cl->q->enqueue(skb, cl->q) == 0) {
+		if (qdisc_enqueue(skb, cl->q) == 0) {
 			sch->q.qlen++;
 			sch->bstats.packets++;
 			sch->bstats.bytes+=len;
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 3aafbd1..44d347e 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -252,7 +252,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		}
 	}
 
-	err = p->q->enqueue(skb, p->q);
+	err = qdisc_enqueue(skb, p->q);
 	if (err != NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		return err;
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 997d520..0ded6d0 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1586,7 +1586,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 	}
 
 	len = skb->len;
-	err = cl->qdisc->enqueue(skb, cl->qdisc);
+	err = qdisc_enqueue(skb, cl->qdisc);
 	if (unlikely(err != NET_XMIT_SUCCESS)) {
 		cl->qstats.drops++;
 		sch->qstats.drops++;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index c8ca54c..5fc0325 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -572,8 +572,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		kfree_skb(skb);
 		return ret;
 #endif
-	} else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) !=
-		   NET_XMIT_SUCCESS) {
+	} else if (qdisc_enqueue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		cl->qstats.drops++;
 		return NET_XMIT_DROP;
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index bc585f2..cbdbc6a 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -82,6 +82,11 @@ struct netem_skb_cb {
 	psched_time_t	time_to_send;
 };
 
+static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
+{
+	return (struct netem_skb_cb *)skb->cb;
+}
+
 /* init_crandom - initialize correlated random number generator
  * Use entropy source for initial seed.
  */
@@ -184,7 +189,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
 		q->duplicate = 0;
 
-		rootq->enqueue(skb2, rootq);
+		qdisc_enqueue(skb2, rootq);
 		q->duplicate = dupsave;
 	}
 
@@ -205,7 +210,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8);
 	}
 
-	cb = (struct netem_skb_cb *)skb->cb;
+	cb = netem_skb_cb(skb);
 	if (q->gap == 0 		/* not doing reordering */
 	    || q->counter < q->gap 	/* inside last reordering gap */
 	    || q->reorder < get_crandom(&q->reorder_cor)) {
@@ -218,7 +223,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		now = psched_get_time();
 		cb->time_to_send = now + delay;
 		++q->counter;
-		ret = q->qdisc->enqueue(skb, q->qdisc);
+		ret = qdisc_enqueue(skb, q->qdisc);
 	} else {
 		/*
 		 * Do re-ordering by putting one out of N packets at the front
@@ -277,8 +282,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 
 	skb = q->qdisc->dequeue(q->qdisc);
 	if (skb) {
-		const struct netem_skb_cb *cb
-			= (const struct netem_skb_cb *)skb->cb;
+		const struct netem_skb_cb *cb = netem_skb_cb(skb);
 		psched_time_t now = psched_get_time();
 
 		/* if more time remaining? */
@@ -454,7 +458,7 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
 {
 	struct fifo_sched_data *q = qdisc_priv(sch);
 	struct sk_buff_head *list = &sch->q;
-	psched_time_t tnext = ((struct netem_skb_cb *)nskb->cb)->time_to_send;
+	psched_time_t tnext = netem_skb_cb(nskb)->time_to_send;
 	struct sk_buff *skb;
 
 	if (likely(skb_queue_len(list) < q->limit)) {
@@ -465,8 +469,7 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
 		}
 
 		skb_queue_reverse_walk(list, skb) {
-			const struct netem_skb_cb *cb
-				= (const struct netem_skb_cb *)skb->cb;
+			const struct netem_skb_cb *cb = netem_skb_cb(skb);
 
 			if (tnext >= cb->time_to_send)
 				break;
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 39157f7..918d090 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -86,7 +86,8 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 	}
 #endif
 
-	if ((ret = qdisc->enqueue(skb, qdisc)) == NET_XMIT_SUCCESS) {
+	ret = qdisc_enqueue(skb, qdisc);
+	if (ret == NET_XMIT_SUCCESS) {
 		sch->bstats.bytes += skb->len;
 		sch->bstats.packets++;
 		sch->q.qlen++;
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 77098ac..b48a391 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -92,7 +92,7 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 			break;
 	}
 
-	ret = child->enqueue(skb, child);
+	ret = qdisc_enqueue(skb, child);
 	if (likely(ret == NET_XMIT_SUCCESS)) {
 		sch->bstats.bytes += skb->len;
 		sch->bstats.packets++;
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 444c227..7d705b8 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -133,7 +133,8 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 		return NET_XMIT_DROP;
 	}
 
-	if ((ret = q->qdisc->enqueue(skb, q->qdisc)) != 0) {
+	ret = qdisc_enqueue(skb, q->qdisc);
+	if (ret != 0) {
 		sch->qstats.drops++;
 		return ret;
 	}


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

* [PATCH RFC 2/3] net_sched: Add accessor function for packet length for qdiscs
  2008-07-17 10:09 [PATCH RFC 0/3] Add generic size table for qdiscs Jussi Kivilinna
  2008-07-17 10:09 ` [PATCH RFC 1/3] net_sched: Add qdisc_enqueue wrapper Jussi Kivilinna
@ 2008-07-17 10:09 ` Jussi Kivilinna
  2008-07-17 10:11   ` Patrick McHardy
  2008-07-17 10:09 ` [PATCH RFC 3/3] net_sched: Add size table " Jussi Kivilinna
  2 siblings, 1 reply; 11+ messages in thread
From: Jussi Kivilinna @ 2008-07-17 10:09 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---

 include/net/sch_generic.h |   17 +++++++++++------
 net/sched/sch_atm.c       |    4 ++--
 net/sched/sch_cbq.c       |   14 ++++++--------
 net/sched/sch_dsmark.c    |    2 +-
 net/sched/sch_fifo.c      |    2 +-
 net/sched/sch_gred.c      |   12 ++++++------
 net/sched/sch_hfsc.c      |   14 ++++++--------
 net/sched/sch_htb.c       |    9 +++++----
 net/sched/sch_netem.c     |    6 +++---
 net/sched/sch_prio.c      |    2 +-
 net/sched/sch_red.c       |    2 +-
 net/sched/sch_sfq.c       |   16 ++++++++--------
 net/sched/sch_tbf.c       |    9 ++++++---
 net/sched/sch_teql.c      |    6 +++---
 14 files changed, 60 insertions(+), 55 deletions(-)

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index e3b0d71..1f1de3b 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -258,6 +258,11 @@ static inline bool qdisc_tx_is_noop(const struct net_device *dev)
 	return (txq->qdisc == &noop_qdisc);
 }
 
+static inline unsigned int qdisc_tx_len(struct sk_buff *skb)
+{
+	return skb->len;
+}
+
 static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	return sch->enqueue(skb, sch);
@@ -267,8 +272,8 @@ static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 				       struct sk_buff_head *list)
 {
 	__skb_queue_tail(list, skb);
-	sch->qstats.backlog += skb->len;
-	sch->bstats.bytes += skb->len;
+	sch->qstats.backlog += qdisc_tx_len(skb);
+	sch->bstats.bytes += qdisc_tx_len(skb);
 	sch->bstats.packets++;
 
 	return NET_XMIT_SUCCESS;
@@ -285,7 +290,7 @@ static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch,
 	struct sk_buff *skb = __skb_dequeue(list);
 
 	if (likely(skb != NULL))
-		sch->qstats.backlog -= skb->len;
+		sch->qstats.backlog -= qdisc_tx_len(skb);
 
 	return skb;
 }
@@ -301,7 +306,7 @@ static inline struct sk_buff *__qdisc_dequeue_tail(struct Qdisc *sch,
 	struct sk_buff *skb = __skb_dequeue_tail(list);
 
 	if (likely(skb != NULL))
-		sch->qstats.backlog -= skb->len;
+		sch->qstats.backlog -= qdisc_tx_len(skb);
 
 	return skb;
 }
@@ -315,7 +320,7 @@ static inline int __qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch,
 				  struct sk_buff_head *list)
 {
 	__skb_queue_head(list, skb);
-	sch->qstats.backlog += skb->len;
+	sch->qstats.backlog += qdisc_tx_len(skb);
 	sch->qstats.requeues++;
 
 	return NET_XMIT_SUCCESS;
@@ -348,7 +353,7 @@ static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch,
 	struct sk_buff *skb = __qdisc_dequeue_tail(sch, list);
 
 	if (likely(skb != NULL)) {
-		unsigned int len = skb->len;
+		unsigned int len = qdisc_tx_len(skb);
 		kfree_skb(skb);
 		return len;
 	}
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 68ed35e..fdadbf0 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -437,9 +437,9 @@ drop: __maybe_unused
 			flow->qstats.drops++;
 		return ret;
 	}
-	sch->bstats.bytes += skb->len;
+	sch->bstats.bytes += qdisc_tx_len(skb);
 	sch->bstats.packets++;
-	flow->bstats.bytes += skb->len;
+	flow->bstats.bytes += qdisc_tx_len(skb);
 	flow->bstats.packets++;
 	/*
 	 * Okay, this may seem weird. We pretend we've dropped the packet if
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 1bcb3e8..a4b7351 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -370,7 +370,6 @@ static int
 cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct cbq_sched_data *q = qdisc_priv(sch);
-	int len = skb->len;
 	int uninitialized_var(ret);
 	struct cbq_class *cl = cbq_classify(skb, sch, &ret);
 
@@ -391,7 +390,7 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->bstats.packets++;
-		sch->bstats.bytes+=len;
+		sch->bstats.bytes += qdisc_tx_len(skb);
 		cbq_mark_toplevel(q, cl);
 		if (!cl->next_alive)
 			cbq_activate_class(cl);
@@ -658,7 +657,6 @@ static enum hrtimer_restart cbq_undelay(struct hrtimer *timer)
 #ifdef CONFIG_NET_CLS_ACT
 static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
 {
-	int len = skb->len;
 	struct Qdisc *sch = child->__parent;
 	struct cbq_sched_data *q = qdisc_priv(sch);
 	struct cbq_class *cl = q->rx_class;
@@ -675,7 +673,7 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
 		if (qdisc_enqueue(skb, cl->q) == 0) {
 			sch->q.qlen++;
 			sch->bstats.packets++;
-			sch->bstats.bytes+=len;
+			sch->bstats.bytes += qdisc_tx_len(skb);
 			if (!cl->next_alive)
 				cbq_activate_class(cl);
 			return 0;
@@ -881,7 +879,7 @@ cbq_dequeue_prio(struct Qdisc *sch, int prio)
 			if (skb == NULL)
 				goto skip_class;
 
-			cl->deficit -= skb->len;
+			cl->deficit -= qdisc_tx_len(skb);
 			q->tx_class = cl;
 			q->tx_borrowed = borrow;
 			if (borrow != cl) {
@@ -889,11 +887,11 @@ cbq_dequeue_prio(struct Qdisc *sch, int prio)
 				borrow->xstats.borrows++;
 				cl->xstats.borrows++;
 #else
-				borrow->xstats.borrows += skb->len;
-				cl->xstats.borrows += skb->len;
+				borrow->xstats.borrows += qdisc_tx_len(skb);
+				cl->xstats.borrows += qdisc_tx_len(skb);
 #endif
 			}
-			q->tx_len = skb->len;
+			q->tx_len = qdisc_tx_len(skb);
 
 			if (cl->deficit <= 0) {
 				q->active[prio] = cl;
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 44d347e..4a4cd62 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -258,7 +258,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		return err;
 	}
 
-	sch->bstats.bytes += skb->len;
+	sch->bstats.bytes += qdisc_tx_len(skb);
 	sch->bstats.packets++;
 	sch->q.qlen++;
 
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
index 1d97fa4..9f63fb4 100644
--- a/net/sched/sch_fifo.c
+++ b/net/sched/sch_fifo.c
@@ -27,7 +27,7 @@ static int bfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct fifo_sched_data *q = qdisc_priv(sch);
 
-	if (likely(sch->qstats.backlog + skb->len <= q->limit))
+	if (likely(sch->qstats.backlog + qdisc_tx_len(skb) <= q->limit))
 		return qdisc_enqueue_tail(skb, sch);
 
 	return qdisc_reshape_fail(skb, sch);
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 39fa285..36f4326 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -188,7 +188,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 	}
 
 	q->packetsin++;
-	q->bytesin += skb->len;
+	q->bytesin += qdisc_tx_len(skb);
 
 	if (gred_wred_mode(t))
 		gred_load_wred_set(t, q);
@@ -226,8 +226,8 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 			break;
 	}
 
-	if (q->backlog + skb->len <= q->limit) {
-		q->backlog += skb->len;
+	if (q->backlog + qdisc_tx_len(skb) <= q->limit) {
+		q->backlog += qdisc_tx_len(skb);
 		return qdisc_enqueue_tail(skb, sch);
 	}
 
@@ -254,7 +254,7 @@ static int gred_requeue(struct sk_buff *skb, struct Qdisc* sch)
 	} else {
 		if (red_is_idling(&q->parms))
 			red_end_of_idle_period(&q->parms);
-		q->backlog += skb->len;
+		q->backlog += qdisc_tx_len(skb);
 	}
 
 	return qdisc_requeue(skb, sch);
@@ -277,7 +277,7 @@ static struct sk_buff *gred_dequeue(struct Qdisc* sch)
 				       "VQ 0x%x after dequeue, screwing up "
 				       "backlog.\n", tc_index_to_dp(skb));
 		} else {
-			q->backlog -= skb->len;
+			q->backlog -= qdisc_tx_len(skb);
 
 			if (!q->backlog && !gred_wred_mode(t))
 				red_start_of_idle_period(&q->parms);
@@ -299,7 +299,7 @@ static unsigned int gred_drop(struct Qdisc* sch)
 
 	skb = qdisc_dequeue_tail(sch);
 	if (skb) {
-		unsigned int len = skb->len;
+		unsigned int len = qdisc_tx_len(skb);
 		struct gred_sched_data *q;
 		u16 dp = tc_index_to_dp(skb);
 
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 0ded6d0..76f8278 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -895,7 +895,7 @@ qdisc_peek_len(struct Qdisc *sch)
 			printk("qdisc_peek_len: non work-conserving qdisc ?\n");
 		return 0;
 	}
-	len = skb->len;
+	len = qdisc_tx_len(skb);
 	if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) {
 		if (net_ratelimit())
 			printk("qdisc_peek_len: failed to requeue\n");
@@ -1574,7 +1574,6 @@ static int
 hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct hfsc_class *cl;
-	unsigned int len;
 	int err;
 
 	cl = hfsc_classify(skb, sch, &err);
@@ -1585,7 +1584,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		return err;
 	}
 
-	len = skb->len;
 	err = qdisc_enqueue(skb, cl->qdisc);
 	if (unlikely(err != NET_XMIT_SUCCESS)) {
 		cl->qstats.drops++;
@@ -1594,12 +1592,12 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 	}
 
 	if (cl->qdisc->q.qlen == 1)
-		set_active(cl, len);
+		set_active(cl, qdisc_tx_len(skb));
 
 	cl->bstats.packets++;
-	cl->bstats.bytes += len;
+	cl->bstats.bytes += qdisc_tx_len(skb);
 	sch->bstats.packets++;
-	sch->bstats.bytes += len;
+	sch->bstats.bytes += qdisc_tx_len(skb);
 	sch->q.qlen++;
 
 	return NET_XMIT_SUCCESS;
@@ -1649,9 +1647,9 @@ hfsc_dequeue(struct Qdisc *sch)
 		return NULL;
 	}
 
-	update_vf(cl, skb->len, cur_time);
+	update_vf(cl, qdisc_tx_len(skb), cur_time);
 	if (realtime)
-		cl->cl_cumul += skb->len;
+		cl->cl_cumul += qdisc_tx_len(skb);
 
 	if (cl->qdisc->q.qlen != 0) {
 		if (cl->cl_flags & HFSC_RSC) {
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 5fc0325..5e1dcf8 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -579,13 +579,13 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 	} else {
 		cl->bstats.packets +=
 			skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
-		cl->bstats.bytes += skb->len;
+		cl->bstats.bytes += qdisc_tx_len(skb);
 		htb_activate(q, cl);
 	}
 
 	sch->q.qlen++;
 	sch->bstats.packets += skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
-	sch->bstats.bytes += skb->len;
+	sch->bstats.bytes += qdisc_tx_len(skb);
 	return NET_XMIT_SUCCESS;
 }
 
@@ -642,7 +642,7 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
 static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
 			     int level, struct sk_buff *skb)
 {
-	int bytes = skb->len;
+	int bytes = qdisc_tx_len(skb);
 	long toks, diff;
 	enum htb_cmode old_mode;
 
@@ -855,7 +855,8 @@ next:
 	} while (cl != start);
 
 	if (likely(skb != NULL)) {
-		if ((cl->un.leaf.deficit[level] -= skb->len) < 0) {
+		cl->un.leaf.deficit[level] -= qdisc_tx_len(skb);
+		if (cl->un.leaf.deficit[level] < 0) {
 			cl->un.leaf.deficit[level] += cl->un.leaf.quantum;
 			htb_next_rb_node((level ? cl->parent->un.inner.ptr : q->
 					  ptr[0]) + prio);
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index cbdbc6a..bc9d6af 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -236,7 +236,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
 	if (likely(ret == NET_XMIT_SUCCESS)) {
 		sch->q.qlen++;
-		sch->bstats.bytes += skb->len;
+		sch->bstats.bytes += qdisc_tx_len(skb);
 		sch->bstats.packets++;
 	} else
 		sch->qstats.drops++;
@@ -477,8 +477,8 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
 
 		__skb_queue_after(list, skb, nskb);
 
-		sch->qstats.backlog += nskb->len;
-		sch->bstats.bytes += nskb->len;
+		sch->qstats.backlog += qdisc_tx_len(nskb);
+		sch->bstats.bytes += qdisc_tx_len(nskb);
 		sch->bstats.packets++;
 
 		return NET_XMIT_SUCCESS;
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 918d090..b5889e8 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -88,7 +88,7 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
 	ret = qdisc_enqueue(skb, qdisc);
 	if (ret == NET_XMIT_SUCCESS) {
-		sch->bstats.bytes += skb->len;
+		sch->bstats.bytes += qdisc_tx_len(skb);
 		sch->bstats.packets++;
 		sch->q.qlen++;
 		return NET_XMIT_SUCCESS;
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index b48a391..6f34e80 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -94,7 +94,7 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
 	ret = qdisc_enqueue(skb, child);
 	if (likely(ret == NET_XMIT_SUCCESS)) {
-		sch->bstats.bytes += skb->len;
+		sch->bstats.bytes += qdisc_tx_len(skb);
 		sch->bstats.packets++;
 		sch->q.qlen++;
 	} else {
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 8458f63..ca3876b 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -245,7 +245,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
 	if (d > 1) {
 		sfq_index x = q->dep[d + SFQ_DEPTH].next;
 		skb = q->qs[x].prev;
-		len = skb->len;
+		len = qdisc_tx_len(skb);
 		__skb_unlink(skb, &q->qs[x]);
 		kfree_skb(skb);
 		sfq_dec(q, x);
@@ -261,7 +261,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
 		q->next[q->tail] = q->next[d];
 		q->allot[q->next[d]] += q->quantum;
 		skb = q->qs[d].prev;
-		len = skb->len;
+		len = qdisc_tx_len(skb);
 		__skb_unlink(skb, &q->qs[d]);
 		kfree_skb(skb);
 		sfq_dec(q, d);
@@ -305,7 +305,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 	if (q->qs[x].qlen >= q->limit)
 		return qdisc_drop(skb, sch);
 
-	sch->qstats.backlog += skb->len;
+	sch->qstats.backlog += qdisc_tx_len(skb);
 	__skb_queue_tail(&q->qs[x], skb);
 	sfq_inc(q, x);
 	if (q->qs[x].qlen == 1) {		/* The flow is new */
@@ -320,7 +320,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		}
 	}
 	if (++sch->q.qlen <= q->limit) {
-		sch->bstats.bytes += skb->len;
+		sch->bstats.bytes += qdisc_tx_len(skb);
 		sch->bstats.packets++;
 		return 0;
 	}
@@ -352,7 +352,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc *sch)
 		q->hash[x] = hash;
 	}
 
-	sch->qstats.backlog += skb->len;
+	sch->qstats.backlog += qdisc_tx_len(skb);
 	__skb_queue_head(&q->qs[x], skb);
 	/* If selected queue has length q->limit+1, this means that
 	 * all another queues are empty and we do simple tail drop.
@@ -363,7 +363,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc *sch)
 		skb = q->qs[x].prev;
 		__skb_unlink(skb, &q->qs[x]);
 		sch->qstats.drops++;
-		sch->qstats.backlog -= skb->len;
+		sch->qstats.backlog -= qdisc_tx_len(skb);
 		kfree_skb(skb);
 		return NET_XMIT_CN;
 	}
@@ -411,7 +411,7 @@ sfq_dequeue(struct Qdisc *sch)
 	skb = __skb_dequeue(&q->qs[a]);
 	sfq_dec(q, a);
 	sch->q.qlen--;
-	sch->qstats.backlog -= skb->len;
+	sch->qstats.backlog -= qdisc_tx_len(skb);
 
 	/* Is the slot empty? */
 	if (q->qs[a].qlen == 0) {
@@ -423,7 +423,7 @@ sfq_dequeue(struct Qdisc *sch)
 		}
 		q->next[q->tail] = a;
 		q->allot[a] += q->quantum;
-	} else if ((q->allot[a] -= skb->len) <= 0) {
+	} else if ((q->allot[a] -= qdisc_tx_len(skb)) <= 0) {
 		q->tail = a;
 		a = q->next[a];
 		q->allot[a] += q->quantum;
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 7d705b8..1e3d52e 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -123,7 +123,10 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	int ret;
 
-	if (skb->len > q->max_size) {
+	/* qdisc_tx_len() before qdisc_enqueue() wrapper, might return different
+	 * length than after wrapper. Should recalculate tx_len here if q->qdisc
+	 * has size table? */
+	if (qdisc_tx_len(skb) > q->max_size) {
 		sch->qstats.drops++;
 #ifdef CONFIG_NET_CLS_ACT
 		if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch))
@@ -140,7 +143,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 	}
 
 	sch->q.qlen++;
-	sch->bstats.bytes += skb->len;
+	sch->bstats.bytes += qdisc_tx_len(skb);
 	sch->bstats.packets++;
 	return 0;
 }
@@ -181,7 +184,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
 		psched_time_t now;
 		long toks;
 		long ptoks = 0;
-		unsigned int len = skb->len;
+		unsigned int len = qdisc_tx_len(skb);
 
 		now = psched_get_time();
 		toks = psched_tdiff_bounded(now, q->t_c, q->buffer);
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 8ac0598..2b25275 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -83,7 +83,7 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
 	if (q->q.qlen < dev->tx_queue_len) {
 		__skb_queue_tail(&q->q, skb);
-		sch->bstats.bytes += skb->len;
+		sch->bstats.bytes += qdisc_tx_len(skb);
 		sch->bstats.packets++;
 		return 0;
 	}
@@ -270,7 +270,6 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
 	struct Qdisc *start, *q;
 	int busy;
 	int nores;
-	int len = skb->len;
 	int subq = skb_get_queue_mapping(skb);
 	struct sk_buff *skb_res = NULL;
 
@@ -305,7 +304,8 @@ restart:
 					master->slaves = NEXT_SLAVE(q);
 					netif_wake_queue(dev);
 					master->stats.tx_packets++;
-					master->stats.tx_bytes += len;
+					master->stats.tx_bytes +=
+						qdisc_tx_len(skb);
 					return 0;
 				}
 				netif_tx_unlock(slave);


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

* [PATCH RFC 3/3] net_sched: Add size table for qdiscs
  2008-07-17 10:09 [PATCH RFC 0/3] Add generic size table for qdiscs Jussi Kivilinna
  2008-07-17 10:09 ` [PATCH RFC 1/3] net_sched: Add qdisc_enqueue wrapper Jussi Kivilinna
  2008-07-17 10:09 ` [PATCH RFC 2/3] net_sched: Add accessor function for packet length for qdiscs Jussi Kivilinna
@ 2008-07-17 10:09 ` Jussi Kivilinna
  2008-07-17 10:30   ` Patrick McHardy
  2 siblings, 1 reply; 11+ messages in thread
From: Jussi Kivilinna @ 2008-07-17 10:09 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev

Add size table functions for qdiscs and calculate packet size in
qdisc_enqueue().

Based on patch by Patrick McHardy
 http://marc.info/?l=linux-netdev&m=115201979221729&w=2

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---

 include/linux/pkt_sched.h |   21 ++++++++
 include/linux/rtnetlink.h |    1 
 include/net/pkt_sched.h   |    1 
 include/net/sch_generic.h |   30 +++++++++++-
 net/core/dev.c            |    1 
 net/sched/sch_api.c       |  117 ++++++++++++++++++++++++++++++++++++++++++++-
 net/sched/sch_generic.c   |    1 
 net/sched/sch_netem.c     |    3 +
 net/sched/sch_tbf.c       |    6 +-
 9 files changed, 174 insertions(+), 7 deletions(-)

diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index dbb7ac3..eae53bf 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -85,6 +85,27 @@ struct tc_ratespec
 
 #define TC_RTAB_SIZE	1024
 
+struct tc_sizespec {
+	unsigned char	cell_log;
+	unsigned char	size_log;
+	short		cell_align;
+	int		overhead;
+	unsigned	linklayer;
+	unsigned	mpu;
+	unsigned	mtu;
+};
+
+#define TC_STAB_DATA_SIZE 1024
+
+enum {
+	TCA_STAB_UNSPEC,
+	TCA_STAB_BASE,
+	TCA_STAB_DATA,
+	__TCA_STAB_MAX
+};
+
+#define TCA_STAB_MAX (__TCA_STAB_MAX - 1)
+
 /* FIFO section */
 
 struct tc_fifo_qopt
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index b358c70..f4d386c 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -482,6 +482,7 @@ enum
 	TCA_RATE,
 	TCA_FCNT,
 	TCA_STATS2,
+	TCA_STAB,
 	__TCA_MAX
 };
 
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index d58c1a5..7a8a2a0 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -83,6 +83,7 @@ extern struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
 extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
 		struct nlattr *tab);
 extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
+extern void qdisc_put_stab(struct qdisc_size_table *tab);
 
 extern void __qdisc_run(struct netdev_queue *txq);
 
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 1f1de3b..81805d0 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -23,6 +23,13 @@ struct qdisc_rate_table
 	int		refcnt;
 };
 
+struct qdisc_size_table {
+	struct list_head	list;
+	struct tc_sizespec	szopts;
+	int			refcnt;
+	u16			data[512];
+};
+
 struct Qdisc
 {
 	int 			(*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
@@ -33,6 +40,7 @@ struct Qdisc
 #define TCQ_F_INGRESS	4
 	int			padded;
 	struct Qdisc_ops	*ops;
+	struct qdisc_size_table	*stab;
 	u32			handle;
 	u32			parent;
 	atomic_t		refcnt;
@@ -154,6 +162,16 @@ struct tcf_proto
 	struct tcf_proto_ops	*ops;
 };
 
+struct qdisc_skb_cb {
+	unsigned int		tx_len;
+	char			data[];
+};
+
+static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb)
+{
+	return (struct qdisc_skb_cb *)skb->cb;
+}
+
 static inline struct net_device *qdisc_dev(struct Qdisc *qdisc)
 {
 	return qdisc->dev_queue->dev;
@@ -224,6 +242,8 @@ extern struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
 extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
 				       struct netdev_queue *dev_queue,
 				       struct Qdisc_ops *ops, u32 parentid);
+extern void qdisc_calculate_tx_len(struct sk_buff *skb,
+				   struct qdisc_size_table *stab);
 extern void tcf_destroy(struct tcf_proto *tp);
 extern void tcf_destroy_chain(struct tcf_proto **fl);
 
@@ -258,13 +278,21 @@ static inline bool qdisc_tx_is_noop(const struct net_device *dev)
 	return (txq->qdisc == &noop_qdisc);
 }
 
+static inline void qdisc_root_init_tx_len(struct sk_buff *skb,
+					  struct Qdisc *sch)
+{
+	qdisc_skb_cb(skb)->tx_len = skb->len;
+}
+
 static inline unsigned int qdisc_tx_len(struct sk_buff *skb)
 {
-	return skb->len;
+	return qdisc_skb_cb(skb)->tx_len;
 }
 
 static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
+	if (sch->stab)
+		qdisc_calculate_tx_len(skb, sch->stab);
 	return sch->enqueue(skb, sch);
 }
 
diff --git a/net/core/dev.c b/net/core/dev.c
index ee2df34..8223b56 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1733,6 +1733,7 @@ gso:
 		if (q->enqueue) {
 			/* reset queue_mapping to zero */
 			skb_set_queue_mapping(skb, 0);
+			qdisc_root_init_tx_len(skb, q);
 			rc = qdisc_enqueue(skb, q);
 			qdisc_run(txq);
 			spin_unlock(&txq->lock);
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 95873f8..4d98cb7 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -278,6 +278,97 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab)
 }
 EXPORT_SYMBOL(qdisc_put_rtab);
 
+static LIST_HEAD(qdisc_stab_list);
+
+static const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = {
+	[TCA_STAB_BASE]	= { .len = sizeof(struct tc_sizespec) },
+	[TCA_STAB_DATA] = { .type = NLA_BINARY, .len = TC_STAB_DATA_SIZE },
+};
+
+static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt, int *err)
+{
+	struct nlattr *tb[TCA_STAB_MAX + 1];
+	struct qdisc_size_table *stab;
+	struct tc_sizespec *s;
+	u16 *tab;
+
+	*err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy);
+	if (*err < 0)
+		return NULL;
+
+	s = nla_data(tb[TCA_STAB_BASE]);
+	tab = nla_data(tb[TCA_STAB_DATA]);
+
+	*err = -EINVAL;
+	if (!s || !tab || nla_len(tb[TCA_STAB_DATA]) < TC_STAB_DATA_SIZE)
+		return NULL;
+
+	list_for_each_entry(stab, &qdisc_stab_list, list) {
+		if (memcmp(&stab->szopts, s, sizeof(*s)) == 0 &&
+		    memcmp(stab->data, tab, TC_STAB_DATA_SIZE) == 0) {
+			stab->refcnt++;
+			*err = 0;
+			return stab;
+		}
+	}
+
+	*err = -ENOMEM;
+	stab = kmalloc(sizeof(*stab), GFP_KERNEL);
+	if (stab) {
+		stab->szopts = *s;
+		stab->refcnt = 1;
+		memcpy(stab->data, tab, TC_STAB_DATA_SIZE);
+		list_add_tail(&stab->list, &qdisc_stab_list);
+		*err = 0;
+	}
+	return stab;
+}
+
+void qdisc_put_stab(struct qdisc_size_table *tab)
+{
+	if (!tab || --tab->refcnt)
+		return;
+	list_del(&tab->list);
+	kfree(tab);
+}
+EXPORT_SYMBOL(qdisc_put_stab);
+
+static int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab)
+{
+	struct nlattr *nest;
+
+	nest = nla_nest_start(skb, TCA_STAB);
+	NLA_PUT(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts);
+	NLA_PUT(skb, TCA_STAB_DATA, TC_STAB_DATA_SIZE, stab->data);
+	nla_nest_end(skb, nest);
+
+	return skb->len;
+
+nla_put_failure:
+	return -1;
+}
+
+void qdisc_calculate_tx_len(struct sk_buff *skb, struct qdisc_size_table *stab)
+{
+	unsigned int pktlen = skb->len;
+	unsigned char size_log;
+	int slot;
+
+	slot = pktlen + stab->szopts.cell_align + stab->szopts.overhead;
+	if (unlikely(slot < 0))
+		slot = 0;
+	slot >>= stab->szopts.cell_log;
+	size_log = stab->szopts.size_log;
+	if (unlikely(slot > 511))
+		pktlen = ((u32)stab->data[511] << size_log) * (slot >> 9) +
+			((u32)stab->data[slot & 0x1FF] << size_log);
+	else
+		pktlen = (u32)stab->data[slot] << size_log;
+
+	qdisc_skb_cb(skb)->tx_len = pktlen;
+}
+EXPORT_SYMBOL(qdisc_calculate_tx_len);
+
 static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
 {
 	struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
@@ -619,6 +710,11 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
 	sch->handle = handle;
 
 	if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) {
+		if (tca[TCA_STAB]) {
+			sch->stab = qdisc_get_stab(tca[TCA_STAB], &err);
+			if (sch->stab == NULL)
+				goto err_out3;
+		}
 		if (tca[TCA_RATE]) {
 			err = gen_new_estimator(&sch->bstats, &sch->rate_est,
 						&sch->dev_queue->lock,
@@ -641,6 +737,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
 		return sch;
 	}
 err_out3:
+	qdisc_put_stab(sch->stab);
 	dev_put(dev);
 	kfree((char *) sch - sch->padded);
 err_out2:
@@ -652,15 +749,28 @@ err_out:
 
 static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
 {
-	if (tca[TCA_OPTIONS]) {
-		int err;
+	struct qdisc_size_table *stab = NULL;
+	int err = 0;
 
+	if (tca[TCA_OPTIONS]) {
 		if (sch->ops->change == NULL)
 			return -EINVAL;
 		err = sch->ops->change(sch, tca[TCA_OPTIONS]);
 		if (err)
 			return err;
 	}
+
+	if (tca[TCA_STAB]) {
+		stab = qdisc_get_stab(tca[TCA_STAB], &err);
+		if (stab == NULL)
+			return err;
+	}
+
+	spin_lock_bh(&sch->dev_queue->lock);
+	qdisc_put_stab(sch->stab);
+	sch->stab = stab;
+	spin_unlock_bh(&sch->dev_queue->lock);
+
 	if (tca[TCA_RATE])
 		gen_replace_estimator(&sch->bstats, &sch->rate_est,
 				      &sch->dev_queue->lock, tca[TCA_RATE]);
@@ -952,6 +1062,9 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
 		goto nla_put_failure;
 	q->qstats.qlen = q->q.qlen;
 
+	if (q->stab != NULL && qdisc_dump_stab(skb, q->stab) < 0)
+		goto nla_put_failure;
+
 	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
 					 TCA_XSTATS, &q->dev_queue->lock, &d) < 0)
 		goto nla_put_failure;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 243de93..53e941b 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -530,6 +530,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
 		return;
 
 	list_del(&qdisc->list);
+	qdisc_put_stab(qdisc->stab);
 	gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
 	if (ops->reset)
 		ops->reset(qdisc);
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index bc9d6af..f75ba82 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -84,7 +84,7 @@ struct netem_skb_cb {
 
 static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
 {
-	return (struct netem_skb_cb *)skb->cb;
+	return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
 }
 
 /* init_crandom - initialize correlated random number generator
@@ -189,6 +189,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
 		q->duplicate = 0;
 
+		qdisc_root_init_tx_len(skb2, rootq);
 		qdisc_enqueue(skb2, rootq);
 		q->duplicate = dupsave;
 	}
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 1e3d52e..862c0e3 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -123,9 +123,9 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	int ret;
 
-	/* qdisc_tx_len() before qdisc_enqueue() wrapper, might return different
-	 * length than after wrapper. Should recalculate tx_len here if q->qdisc
-	 * has size table? */
+	if (q->qdisc->stab)
+		qdisc_calculate_tx_len(skb, q->qdisc->stab);
+
 	if (qdisc_tx_len(skb) > q->max_size) {
 		sch->qstats.drops++;
 #ifdef CONFIG_NET_CLS_ACT


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

* Re: [PATCH RFC 1/3] net_sched: Add qdisc_enqueue wrapper
  2008-07-17 10:09 ` [PATCH RFC 1/3] net_sched: Add qdisc_enqueue wrapper Jussi Kivilinna
@ 2008-07-17 10:10   ` Patrick McHardy
  0 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2008-07-17 10:10 UTC (permalink / raw)
  To: Jussi Kivilinna; +Cc: netdev

Jussi Kivilinna wrote:
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
> ---
> 
>  include/net/sch_generic.h |    5 +++++
>  net/core/dev.c            |    2 +-
>  net/mac80211/wme.c        |    2 +-
>  net/sched/sch_atm.c       |    2 +-
>  net/sched/sch_cbq.c       |    5 +++--
>  net/sched/sch_dsmark.c    |    2 +-
>  net/sched/sch_hfsc.c      |    2 +-
>  net/sched/sch_htb.c       |    3 +--
>  net/sched/sch_netem.c     |   19 +++++++++++--------
>  net/sched/sch_prio.c      |    3 ++-
>  net/sched/sch_red.c       |    2 +-
>  net/sched/sch_tbf.c       |    3 ++-
>  12 files changed, 30 insertions(+), 20 deletions(-)

This one looks fine.


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

* Re: [PATCH RFC 2/3] net_sched: Add accessor function for packet length for qdiscs
  2008-07-17 10:09 ` [PATCH RFC 2/3] net_sched: Add accessor function for packet length for qdiscs Jussi Kivilinna
@ 2008-07-17 10:11   ` Patrick McHardy
  2008-07-17 11:33     ` Jussi Kivilinna
  0 siblings, 1 reply; 11+ messages in thread
From: Patrick McHardy @ 2008-07-17 10:11 UTC (permalink / raw)
  To: Jussi Kivilinna; +Cc: netdev

Jussi Kivilinna wrote:
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
> ---
> 
>  include/net/sch_generic.h |   17 +++++++++++------
>  net/sched/sch_atm.c       |    4 ++--
>  net/sched/sch_cbq.c       |   14 ++++++--------
>  net/sched/sch_dsmark.c    |    2 +-
>  net/sched/sch_fifo.c      |    2 +-
>  net/sched/sch_gred.c      |   12 ++++++------
>  net/sched/sch_hfsc.c      |   14 ++++++--------
>  net/sched/sch_htb.c       |    9 +++++----
>  net/sched/sch_netem.c     |    6 +++---
>  net/sched/sch_prio.c      |    2 +-
>  net/sched/sch_red.c       |    2 +-
>  net/sched/sch_sfq.c       |   16 ++++++++--------
>  net/sched/sch_tbf.c       |    9 ++++++---
>  net/sched/sch_teql.c      |    6 +++---
>  14 files changed, 60 insertions(+), 55 deletions(-)
> 
> diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
> index e3b0d71..1f1de3b 100644
> --- a/include/net/sch_generic.h
> +++ b/include/net/sch_generic.h
> @@ -258,6 +258,11 @@ static inline bool qdisc_tx_is_noop(const struct net_device *dev)
>  	return (txq->qdisc == &noop_qdisc);
>  }
>  
> +static inline unsigned int qdisc_tx_len(struct sk_buff *skb)
> +{
> +	return skb->len;
> +}


Just one question - should this also be useable for ingress? If so
a different name would make sense.

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

* Re: [PATCH RFC 3/3] net_sched: Add size table for qdiscs
  2008-07-17 10:09 ` [PATCH RFC 3/3] net_sched: Add size table " Jussi Kivilinna
@ 2008-07-17 10:30   ` Patrick McHardy
  2008-07-17 18:02     ` Jussi Kivilinna
  0 siblings, 1 reply; 11+ messages in thread
From: Patrick McHardy @ 2008-07-17 10:30 UTC (permalink / raw)
  To: Jussi Kivilinna; +Cc: netdev

Jussi Kivilinna wrote:
> diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
> index dbb7ac3..eae53bf 100644
> --- a/include/linux/pkt_sched.h
> +++ b/include/linux/pkt_sched.h
> @@ -85,6 +85,27 @@ struct tc_ratespec
>  
>  #define TC_RTAB_SIZE	1024
>  
> +struct tc_sizespec {
> +	unsigned char	cell_log;
> +	unsigned char	size_log;
> +	short		cell_align;
> +	int		overhead;
> +	unsigned	linklayer;
> +	unsigned	mpu;
> +	unsigned	mtu;
> +};

Please use "unsigned int".

> +
> +#define TC_STAB_DATA_SIZE 1024
> +
> +enum {
> +	TCA_STAB_UNSPEC,
> +	TCA_STAB_BASE,
> +	TCA_STAB_DATA,
> +	__TCA_STAB_MAX
> +};

Since you already split the STAB into a base and a data
structure, wouldn't it make sense to have the data size
dynamic for user-defined granularity?

> +static LIST_HEAD(qdisc_stab_list);
> +
> +static const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = {
> +	[TCA_STAB_BASE]	= { .len = sizeof(struct tc_sizespec) },
> +	[TCA_STAB_DATA] = { .type = NLA_BINARY, .len = TC_STAB_DATA_SIZE },
> +};
> +
> +static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt, int *err)
> +{
> +	struct nlattr *tb[TCA_STAB_MAX + 1];
> +	struct qdisc_size_table *stab;
> +	struct tc_sizespec *s;
> +	u16 *tab;
> +
> +	*err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy);
> +	if (*err < 0)
> +		return NULL;

ERR_PTR is cleaner than pointer return values IMO.

> diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
> index bc9d6af..f75ba82 100644
> --- a/net/sched/sch_netem.c
> +++ b/net/sched/sch_netem.c
> @@ -84,7 +84,7 @@ struct netem_skb_cb {
>  
>  static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
>  {
> -	return (struct netem_skb_cb *)skb->cb;
> +	return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
>  }

A BUILD_BUG_ON to make sure the skb->cb size is not exceeded would
be good to have.

>  /* init_crandom - initialize correlated random number generator
> @@ -189,6 +189,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
>  		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
>  		q->duplicate = 0;
>  
> +		qdisc_root_init_tx_len(skb2, rootq);
>  		qdisc_enqueue(skb2, rootq);

How about adding qdisc_enqueue_root() to perform both these steps
(its similar to net/core/dev.c).

> diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
> index 1e3d52e..862c0e3 100644
> --- a/net/sched/sch_tbf.c
> +++ b/net/sched/sch_tbf.c
> @@ -123,9 +123,9 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
>  	struct tbf_sched_data *q = qdisc_priv(sch);
>  	int ret;
>  
> -	/* qdisc_tx_len() before qdisc_enqueue() wrapper, might return different
> -	 * length than after wrapper. Should recalculate tx_len here if q->qdisc
> -	 * has size table? */
> +	if (q->qdisc->stab)
> +		qdisc_calculate_tx_len(skb, q->qdisc->stab);
> +

I don't think this will help, the inner qdisc might again have
an inner qdisc that increases the size. So this probably needs
to be handled during dequeue.

>  	if (qdisc_tx_len(skb) > q->max_size) {
>  		sch->qstats.drops++;
>  #ifdef CONFIG_NET_CLS_ACT
> 


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

* Re: [PATCH RFC 2/3] net_sched: Add accessor function for packet length for qdiscs
  2008-07-17 10:11   ` Patrick McHardy
@ 2008-07-17 11:33     ` Jussi Kivilinna
  0 siblings, 0 replies; 11+ messages in thread
From: Jussi Kivilinna @ 2008-07-17 11:33 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev

Quoting "Patrick McHardy" <kaber@trash.net>:

> Jussi Kivilinna wrote:
>> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
>> ---
>>
>> include/net/sch_generic.h |   17 +++++++++++------
>> net/sched/sch_atm.c       |    4 ++--
>> net/sched/sch_cbq.c       |   14 ++++++--------
>> net/sched/sch_dsmark.c    |    2 +-
>> net/sched/sch_fifo.c      |    2 +-
>> net/sched/sch_gred.c      |   12 ++++++------
>> net/sched/sch_hfsc.c      |   14 ++++++--------
>> net/sched/sch_htb.c       |    9 +++++----
>> net/sched/sch_netem.c     |    6 +++---
>> net/sched/sch_prio.c      |    2 +-
>> net/sched/sch_red.c       |    2 +-
>> net/sched/sch_sfq.c       |   16 ++++++++--------
>> net/sched/sch_tbf.c       |    9 ++++++---
>> net/sched/sch_teql.c      |    6 +++---
>> 14 files changed, 60 insertions(+), 55 deletions(-)
>>
>> diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
>> index e3b0d71..1f1de3b 100644
>> --- a/include/net/sch_generic.h
>> +++ b/include/net/sch_generic.h
>> @@ -258,6 +258,11 @@ static inline bool qdisc_tx_is_noop(const   
>> struct net_device *dev)
>> 	return (txq->qdisc == &noop_qdisc);
>> }
>> +static inline unsigned int qdisc_tx_len(struct sk_buff *skb)
>> +{
>> +	return skb->len;
>> +}
>
>
> Just one question - should this also be useable for ingress? If so
> a different name would make sense.
>
>

Yes, it should be. Police action has rate table that could be replaced  
with size table, so qdisc_pkt_len() would be better name.

  - Jussi


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

* Re: [PATCH RFC 3/3] net_sched: Add size table for qdiscs
  2008-07-17 10:30   ` Patrick McHardy
@ 2008-07-17 18:02     ` Jussi Kivilinna
  2008-07-21 13:00       ` Patrick McHardy
  0 siblings, 1 reply; 11+ messages in thread
From: Jussi Kivilinna @ 2008-07-17 18:02 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev

Quoting "Patrick McHardy" <kaber@trash.net>:

> Jussi Kivilinna wrote:
>> diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
>> index dbb7ac3..eae53bf 100644
>> --- a/include/linux/pkt_sched.h
>> +++ b/include/linux/pkt_sched.h
>> @@ -85,6 +85,27 @@ struct tc_ratespec
>>  #define TC_RTAB_SIZE	1024
>> +struct tc_sizespec {
>> +	unsigned char	cell_log;
>> +	unsigned char	size_log;
>> +	short		cell_align;
>> +	int		overhead;
>> +	unsigned	linklayer;
>> +	unsigned	mpu;
>> +	unsigned	mtu;
>> +};
>
> Please use "unsigned int".
>

Ok.

>> +
>> +#define TC_STAB_DATA_SIZE 1024
>> +
>> +enum {
>> +	TCA_STAB_UNSPEC,
>> +	TCA_STAB_BASE,
>> +	TCA_STAB_DATA,
>> +	__TCA_STAB_MAX
>> +};
>
> Since you already split the STAB into a base and a data
> structure, wouldn't it make sense to have the data size
> dynamic for user-defined granularity?
>

Yes, it would.

>> +static LIST_HEAD(qdisc_stab_list);
>> +
>> +static const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = {
>> +	[TCA_STAB_BASE]	= { .len = sizeof(struct tc_sizespec) },
>> +	[TCA_STAB_DATA] = { .type = NLA_BINARY, .len = TC_STAB_DATA_SIZE },
>> +};
>> +
>> +static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt,  
>>  int *err)
>> +{
>> +	struct nlattr *tb[TCA_STAB_MAX + 1];
>> +	struct qdisc_size_table *stab;
>> +	struct tc_sizespec *s;
>> +	u16 *tab;
>> +
>> +	*err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy);
>> +	if (*err < 0)
>> +		return NULL;
>
> ERR_PTR is cleaner than pointer return values IMO.
>

Ok.

>> diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
>> index bc9d6af..f75ba82 100644
>> --- a/net/sched/sch_netem.c
>> +++ b/net/sched/sch_netem.c
>> @@ -84,7 +84,7 @@ struct netem_skb_cb {
>>  static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
>> {
>> -	return (struct netem_skb_cb *)skb->cb;
>> +	return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
>> }
>
> A BUILD_BUG_ON to make sure the skb->cb size is not exceeded would
> be good to have.
>

Ok.

>> /* init_crandom - initialize correlated random number generator
>> @@ -189,6 +189,7 @@ static int netem_enqueue(struct sk_buff *skb,   
>> struct Qdisc *sch)
>> 		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
>> 		q->duplicate = 0;
>> +		qdisc_root_init_tx_len(skb2, rootq);
>> 		qdisc_enqueue(skb2, rootq);
>
> How about adding qdisc_enqueue_root() to perform both these steps
> (its similar to net/core/dev.c).
>

Sure.

>> diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
>> index 1e3d52e..862c0e3 100644
>> --- a/net/sched/sch_tbf.c
>> +++ b/net/sched/sch_tbf.c
>> @@ -123,9 +123,9 @@ static int tbf_enqueue(struct sk_buff *skb,   
>> struct Qdisc* sch)
>> 	struct tbf_sched_data *q = qdisc_priv(sch);
>> 	int ret;
>> -	/* qdisc_tx_len() before qdisc_enqueue() wrapper, might return different
>> -	 * length than after wrapper. Should recalculate tx_len here if q->qdisc
>> -	 * has size table? */
>> +	if (q->qdisc->stab)
>> +		qdisc_calculate_tx_len(skb, q->qdisc->stab);
>> +
>
> I don't think this will help, the inner qdisc might again have
> an inner qdisc that increases the size. So this probably needs
> to be handled during dequeue.
>

I don't quite follow you here, what needs to be handled during  
dequeue? tbf's q->max_size check?

>> 	if (qdisc_tx_len(skb) > q->max_size) {
>> 		sch->qstats.drops++;
>> #ifdef CONFIG_NET_CLS_ACT
>>
>
>
>




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

* Re: [PATCH RFC 3/3] net_sched: Add size table for qdiscs
  2008-07-17 18:02     ` Jussi Kivilinna
@ 2008-07-21 13:00       ` Patrick McHardy
  2008-07-21 13:03         ` Jussi Kivilinna
  0 siblings, 1 reply; 11+ messages in thread
From: Patrick McHardy @ 2008-07-21 13:00 UTC (permalink / raw)
  To: Jussi Kivilinna; +Cc: netdev

Jussi Kivilinna wrote:
> Quoting "Patrick McHardy" <kaber@trash.net>:
> 
>>> @@ -123,9 +123,9 @@ static int tbf_enqueue(struct sk_buff *skb,  
>>> struct Qdisc* sch)
>>>     struct tbf_sched_data *q = qdisc_priv(sch);
>>>     int ret;
>>> -    /* qdisc_tx_len() before qdisc_enqueue() wrapper, might return 
>>> different
>>> -     * length than after wrapper. Should recalculate tx_len here if 
>>> q->qdisc
>>> -     * has size table? */
>>> +    if (q->qdisc->stab)
>>> +        qdisc_calculate_tx_len(skb, q->qdisc->stab);
>>> +
>>
>> I don't think this will help, the inner qdisc might again have
>> an inner qdisc that increases the size. So this probably needs
>> to be handled during dequeue.
>>
> 
> I don't quite follow you here, what needs to be handled during dequeue? 
> tbf's q->max_size check?


Yes. You check on ->enqueue by using the inner qdiscs size table,
but that qdisc might again have an inner qdisc which increases
the size, which you can't check during ->enqueue.

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

* Re: [PATCH RFC 3/3] net_sched: Add size table for qdiscs
  2008-07-21 13:00       ` Patrick McHardy
@ 2008-07-21 13:03         ` Jussi Kivilinna
  0 siblings, 0 replies; 11+ messages in thread
From: Jussi Kivilinna @ 2008-07-21 13:03 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev

Quoting "Patrick McHardy" <kaber@trash.net>:

>
> Yes. You check on ->enqueue by using the inner qdiscs size table,
> but that qdisc might again have an inner qdisc which increases
> the size, which you can't check during ->enqueue.
>
>

Ok, I'll send patch when I get back next week.



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

end of thread, other threads:[~2008-07-21 13:03 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-17 10:09 [PATCH RFC 0/3] Add generic size table for qdiscs Jussi Kivilinna
2008-07-17 10:09 ` [PATCH RFC 1/3] net_sched: Add qdisc_enqueue wrapper Jussi Kivilinna
2008-07-17 10:10   ` Patrick McHardy
2008-07-17 10:09 ` [PATCH RFC 2/3] net_sched: Add accessor function for packet length for qdiscs Jussi Kivilinna
2008-07-17 10:11   ` Patrick McHardy
2008-07-17 11:33     ` Jussi Kivilinna
2008-07-17 10:09 ` [PATCH RFC 3/3] net_sched: Add size table " Jussi Kivilinna
2008-07-17 10:30   ` Patrick McHardy
2008-07-17 18:02     ` Jussi Kivilinna
2008-07-21 13:00       ` Patrick McHardy
2008-07-21 13:03         ` Jussi Kivilinna

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).