diff options
author | Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 2008-07-20 03:08:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-20 03:08:47 -0400 |
commit | 175f9c1bba9b825d22b142d183c9e175488b260c (patch) | |
tree | 6b9cdb2e3802e7fc8422dc0d0cc200f6d4d1d0a5 /net/sched | |
parent | 0abf77e55a2459aa9905be4b226e4729d5b4f0cb (diff) |
net_sched: Add size table for qdiscs
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>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_api.c | 151 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 1 | ||||
-rw-r--r-- | net/sched/sch_netem.c | 5 |
3 files changed, 153 insertions, 4 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index fb43731c9860..5219d5f9d754 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -286,6 +286,129 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab) | |||
286 | } | 286 | } |
287 | EXPORT_SYMBOL(qdisc_put_rtab); | 287 | EXPORT_SYMBOL(qdisc_put_rtab); |
288 | 288 | ||
289 | static LIST_HEAD(qdisc_stab_list); | ||
290 | static DEFINE_SPINLOCK(qdisc_stab_lock); | ||
291 | |||
292 | static const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = { | ||
293 | [TCA_STAB_BASE] = { .len = sizeof(struct tc_sizespec) }, | ||
294 | [TCA_STAB_DATA] = { .type = NLA_BINARY }, | ||
295 | }; | ||
296 | |||
297 | static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) | ||
298 | { | ||
299 | struct nlattr *tb[TCA_STAB_MAX + 1]; | ||
300 | struct qdisc_size_table *stab; | ||
301 | struct tc_sizespec *s; | ||
302 | unsigned int tsize = 0; | ||
303 | u16 *tab = NULL; | ||
304 | int err; | ||
305 | |||
306 | err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy); | ||
307 | if (err < 0) | ||
308 | return ERR_PTR(err); | ||
309 | if (!tb[TCA_STAB_BASE]) | ||
310 | return ERR_PTR(-EINVAL); | ||
311 | |||
312 | s = nla_data(tb[TCA_STAB_BASE]); | ||
313 | |||
314 | if (s->tsize > 0) { | ||
315 | if (!tb[TCA_STAB_DATA]) | ||
316 | return ERR_PTR(-EINVAL); | ||
317 | tab = nla_data(tb[TCA_STAB_DATA]); | ||
318 | tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); | ||
319 | } | ||
320 | |||
321 | if (!s || tsize != s->tsize || (!tab && tsize > 0)) | ||
322 | return ERR_PTR(-EINVAL); | ||
323 | |||
324 | spin_lock(&qdisc_stab_lock); | ||
325 | |||
326 | list_for_each_entry(stab, &qdisc_stab_list, list) { | ||
327 | if (memcmp(&stab->szopts, s, sizeof(*s))) | ||
328 | continue; | ||
329 | if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16))) | ||
330 | continue; | ||
331 | stab->refcnt++; | ||
332 | spin_unlock(&qdisc_stab_lock); | ||
333 | return stab; | ||
334 | } | ||
335 | |||
336 | spin_unlock(&qdisc_stab_lock); | ||
337 | |||
338 | stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL); | ||
339 | if (!stab) | ||
340 | return ERR_PTR(-ENOMEM); | ||
341 | |||
342 | stab->refcnt = 1; | ||
343 | stab->szopts = *s; | ||
344 | if (tsize > 0) | ||
345 | memcpy(stab->data, tab, tsize * sizeof(u16)); | ||
346 | |||
347 | spin_lock(&qdisc_stab_lock); | ||
348 | list_add_tail(&stab->list, &qdisc_stab_list); | ||
349 | spin_unlock(&qdisc_stab_lock); | ||
350 | |||
351 | return stab; | ||
352 | } | ||
353 | |||
354 | void qdisc_put_stab(struct qdisc_size_table *tab) | ||
355 | { | ||
356 | if (!tab) | ||
357 | return; | ||
358 | |||
359 | spin_lock(&qdisc_stab_lock); | ||
360 | |||
361 | if (--tab->refcnt == 0) { | ||
362 | list_del(&tab->list); | ||
363 | kfree(tab); | ||
364 | } | ||
365 | |||
366 | spin_unlock(&qdisc_stab_lock); | ||
367 | } | ||
368 | EXPORT_SYMBOL(qdisc_put_stab); | ||
369 | |||
370 | static int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab) | ||
371 | { | ||
372 | struct nlattr *nest; | ||
373 | |||
374 | nest = nla_nest_start(skb, TCA_STAB); | ||
375 | NLA_PUT(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts); | ||
376 | nla_nest_end(skb, nest); | ||
377 | |||
378 | return skb->len; | ||
379 | |||
380 | nla_put_failure: | ||
381 | return -1; | ||
382 | } | ||
383 | |||
384 | void qdisc_calculate_pkt_len(struct sk_buff *skb, struct qdisc_size_table *stab) | ||
385 | { | ||
386 | int pkt_len, slot; | ||
387 | |||
388 | pkt_len = skb->len + stab->szopts.overhead; | ||
389 | if (unlikely(!stab->szopts.tsize)) | ||
390 | goto out; | ||
391 | |||
392 | slot = pkt_len + stab->szopts.cell_align; | ||
393 | if (unlikely(slot < 0)) | ||
394 | slot = 0; | ||
395 | |||
396 | slot >>= stab->szopts.cell_log; | ||
397 | if (likely(slot < stab->szopts.tsize)) | ||
398 | pkt_len = stab->data[slot]; | ||
399 | else | ||
400 | pkt_len = stab->data[stab->szopts.tsize - 1] * | ||
401 | (slot / stab->szopts.tsize) + | ||
402 | stab->data[slot % stab->szopts.tsize]; | ||
403 | |||
404 | pkt_len <<= stab->szopts.size_log; | ||
405 | out: | ||
406 | if (unlikely(pkt_len < 1)) | ||
407 | pkt_len = 1; | ||
408 | qdisc_skb_cb(skb)->pkt_len = pkt_len; | ||
409 | } | ||
410 | EXPORT_SYMBOL(qdisc_calculate_pkt_len); | ||
411 | |||
289 | static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) | 412 | static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) |
290 | { | 413 | { |
291 | struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, | 414 | struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, |
@@ -613,6 +736,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, | |||
613 | struct nlattr *kind = tca[TCA_KIND]; | 736 | struct nlattr *kind = tca[TCA_KIND]; |
614 | struct Qdisc *sch; | 737 | struct Qdisc *sch; |
615 | struct Qdisc_ops *ops; | 738 | struct Qdisc_ops *ops; |
739 | struct qdisc_size_table *stab; | ||
616 | 740 | ||
617 | ops = qdisc_lookup_ops(kind); | 741 | ops = qdisc_lookup_ops(kind); |
618 | #ifdef CONFIG_KMOD | 742 | #ifdef CONFIG_KMOD |
@@ -670,6 +794,14 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, | |||
670 | sch->handle = handle; | 794 | sch->handle = handle; |
671 | 795 | ||
672 | if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { | 796 | if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { |
797 | if (tca[TCA_STAB]) { | ||
798 | stab = qdisc_get_stab(tca[TCA_STAB]); | ||
799 | if (IS_ERR(stab)) { | ||
800 | err = PTR_ERR(stab); | ||
801 | goto err_out3; | ||
802 | } | ||
803 | sch->stab = stab; | ||
804 | } | ||
673 | if (tca[TCA_RATE]) { | 805 | if (tca[TCA_RATE]) { |
674 | err = gen_new_estimator(&sch->bstats, &sch->rate_est, | 806 | err = gen_new_estimator(&sch->bstats, &sch->rate_est, |
675 | qdisc_root_lock(sch), | 807 | qdisc_root_lock(sch), |
@@ -691,6 +823,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, | |||
691 | return sch; | 823 | return sch; |
692 | } | 824 | } |
693 | err_out3: | 825 | err_out3: |
826 | qdisc_put_stab(sch->stab); | ||
694 | dev_put(dev); | 827 | dev_put(dev); |
695 | kfree((char *) sch - sch->padded); | 828 | kfree((char *) sch - sch->padded); |
696 | err_out2: | 829 | err_out2: |
@@ -702,15 +835,26 @@ err_out: | |||
702 | 835 | ||
703 | static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) | 836 | static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) |
704 | { | 837 | { |
705 | if (tca[TCA_OPTIONS]) { | 838 | struct qdisc_size_table *stab = NULL; |
706 | int err; | 839 | int err = 0; |
707 | 840 | ||
841 | if (tca[TCA_OPTIONS]) { | ||
708 | if (sch->ops->change == NULL) | 842 | if (sch->ops->change == NULL) |
709 | return -EINVAL; | 843 | return -EINVAL; |
710 | err = sch->ops->change(sch, tca[TCA_OPTIONS]); | 844 | err = sch->ops->change(sch, tca[TCA_OPTIONS]); |
711 | if (err) | 845 | if (err) |
712 | return err; | 846 | return err; |
713 | } | 847 | } |
848 | |||
849 | if (tca[TCA_STAB]) { | ||
850 | stab = qdisc_get_stab(tca[TCA_STAB]); | ||
851 | if (IS_ERR(stab)) | ||
852 | return PTR_ERR(stab); | ||
853 | } | ||
854 | |||
855 | qdisc_put_stab(sch->stab); | ||
856 | sch->stab = stab; | ||
857 | |||
714 | if (tca[TCA_RATE]) | 858 | if (tca[TCA_RATE]) |
715 | gen_replace_estimator(&sch->bstats, &sch->rate_est, | 859 | gen_replace_estimator(&sch->bstats, &sch->rate_est, |
716 | qdisc_root_lock(sch), tca[TCA_RATE]); | 860 | qdisc_root_lock(sch), tca[TCA_RATE]); |
@@ -994,6 +1138,9 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, | |||
994 | goto nla_put_failure; | 1138 | goto nla_put_failure; |
995 | q->qstats.qlen = q->q.qlen; | 1139 | q->qstats.qlen = q->q.qlen; |
996 | 1140 | ||
1141 | if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) | ||
1142 | goto nla_put_failure; | ||
1143 | |||
997 | if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, | 1144 | if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, |
998 | TCA_XSTATS, qdisc_root_lock(q), &d) < 0) | 1145 | TCA_XSTATS, qdisc_root_lock(q), &d) < 0) |
999 | goto nla_put_failure; | 1146 | goto nla_put_failure; |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 522a41a9f904..27a51f04db49 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -469,6 +469,7 @@ static void __qdisc_destroy(struct rcu_head *head) | |||
469 | struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu); | 469 | struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu); |
470 | const struct Qdisc_ops *ops = qdisc->ops; | 470 | const struct Qdisc_ops *ops = qdisc->ops; |
471 | 471 | ||
472 | qdisc_put_stab(qdisc->stab); | ||
472 | gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); | 473 | gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); |
473 | if (ops->reset) | 474 | if (ops->reset) |
474 | ops->reset(qdisc); | 475 | ops->reset(qdisc); |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index ae49be00022f..a59085700678 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
@@ -84,8 +84,9 @@ struct netem_skb_cb { | |||
84 | 84 | ||
85 | static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) | 85 | static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) |
86 | { | 86 | { |
87 | BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct netem_skb_cb)); | 87 | BUILD_BUG_ON(sizeof(skb->cb) < |
88 | return (struct netem_skb_cb *)skb->cb; | 88 | sizeof(struct qdisc_skb_cb) + sizeof(struct netem_skb_cb)); |
89 | return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data; | ||
89 | } | 90 | } |
90 | 91 | ||
91 | /* init_crandom - initialize correlated random number generator | 92 | /* init_crandom - initialize correlated random number generator |