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