commit d89898d2e77b5c1753d21174870277d235994afa Author: Patrick McHardy Date: Sun Jan 20 19:31:05 2008 +0100 [NET_SCHED]: Consolidate class ops for pseudo classful qdisc Signed-off-by: Patrick McHardy diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index decc339..ca6e4de 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -351,4 +351,10 @@ static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask) } #endif +struct pc_sched_data { + struct Qdisc *qdisc; +}; + +extern const struct Qdisc_class_ops pseudo_classful_ops; + #endif diff --git a/net/sched/Kconfig b/net/sched/Kconfig index f5ab54b..b6b4260 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -43,6 +43,9 @@ if NET_SCHED comment "Queueing/Scheduling" +config NET_SCH_PC + tristate + config NET_SCH_CBQ tristate "Class Based Queueing (CBQ)" ---help--- @@ -119,6 +122,7 @@ config NET_SCH_RR config NET_SCH_RED tristate "Random Early Detection (RED)" + select NET_SCH_PC ---help--- Say Y here if you want to use the Random Early Detection (RED) packet scheduling algorithm. @@ -153,6 +157,7 @@ config NET_SCH_TEQL config NET_SCH_TBF tristate "Token Bucket Filter (TBF)" + select NET_SCH_PC ---help--- Say Y here if you want to use the Token Bucket Filter (TBF) packet scheduling algorithm. @@ -186,6 +191,7 @@ config NET_SCH_DSMARK config NET_SCH_NETEM tristate "Network emulator (NETEM)" + select NET_SCH_PC ---help--- Say Y if you want to emulate network delay, loss, and packet re-ordering. This is often useful to simulate networks when diff --git a/net/sched/Makefile b/net/sched/Makefile index 81ecbe8..593bb3a 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o obj-$(CONFIG_NET_ACT_NAT) += act_nat.o obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o +obj-$(CONFIG_NET_SCH_PC) += sch_pseudo_classful.o obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index f6c24fd..2444a97 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -52,7 +52,8 @@ */ struct netem_sched_data { - struct Qdisc *qdisc; + struct pc_sched_data class; + struct qdisc_watchdog watchdog; psched_tdiff_t latency; @@ -218,7 +219,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 = qdisc_enqueue(skb, q->qdisc); + ret = qdisc_enqueue(skb, q->class.qdisc); } else { /* * Do re-ordering by putting one out of N packets at the front @@ -226,7 +227,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) */ cb->time_to_send = psched_get_time(); q->counter = 0; - ret = qdisc_requeue(skb, q->qdisc); + ret = qdisc_requeue(skb, q->class.qdisc); } if (likely(ret == NET_XMIT_SUCCESS)) { @@ -246,7 +247,7 @@ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch) struct netem_sched_data *q = qdisc_priv(sch); int ret; - ret = qdisc_requeue(skb, q->qdisc); + ret = qdisc_requeue(skb, q->class.qdisc); if (ret == NET_XMIT_SUCCESS) { sch->q.qlen++; sch->qstats.requeues++; @@ -260,7 +261,7 @@ static unsigned int netem_drop(struct Qdisc* sch) struct netem_sched_data *q = qdisc_priv(sch); unsigned int len = 0; - len = qdisc_drop(q->qdisc); + len = qdisc_drop(q->class.qdisc); if (len > 0) { sch->q.qlen--; sch->qstats.drops++; @@ -277,7 +278,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) if (sch->flags & TCQ_F_THROTTLED) return NULL; - skb = qdisc_dequeue(q->qdisc); + skb = qdisc_dequeue(q->class.qdisc); if (skb) { const struct netem_skb_cb *cb = (const struct netem_skb_cb *)skb->cb; @@ -290,11 +291,11 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) return skb; } - if (unlikely(qdisc_requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) { - qdisc_tree_decrease_qlen(q->qdisc, 1); + if (unlikely(qdisc_requeue(skb, q->class.qdisc) != NET_XMIT_SUCCESS)) { + qdisc_tree_decrease_qlen(q->class.qdisc, 1); sch->qstats.drops++; printk(KERN_ERR "netem: %s could not requeue\n", - q->qdisc->ops->id); + q->class.qdisc->ops->id); } qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send); @@ -307,7 +308,7 @@ static void netem_reset(struct Qdisc *sch) { struct netem_sched_data *q = qdisc_priv(sch); - qdisc_reset(q->qdisc); + qdisc_reset(q->class.qdisc); sch->q.qlen = 0; qdisc_watchdog_cancel(&q->watchdog); } @@ -394,7 +395,7 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt) return -EINVAL; qopt = RTA_DATA(opt); - ret = fifo_set_limit(q->qdisc, qopt->limit); + ret = fifo_set_limit(q->class.qdisc, qopt->limit); if (ret) { pr_debug("netem: can't set fifo limit\n"); return ret; @@ -547,9 +548,9 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt) qdisc_watchdog_init(&q->watchdog, sch); - q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops, - TC_H_MAKE(sch->handle, 1)); - if (!q->qdisc) { + q->class.qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops, + TC_H_MAKE(sch->handle, 1)); + if (!q->class.qdisc) { pr_debug("netem: qdisc create failed\n"); return -ENOMEM; } @@ -557,7 +558,7 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt) ret = netem_change(sch, opt); if (ret) { pr_debug("netem: change failed\n"); - qdisc_destroy(q->qdisc); + qdisc_destroy(q->class.qdisc); } return ret; } @@ -567,7 +568,7 @@ static void netem_destroy(struct Qdisc *sch) struct netem_sched_data *q = qdisc_priv(sch); qdisc_watchdog_cancel(&q->watchdog); - qdisc_destroy(q->qdisc); + qdisc_destroy(q->class.qdisc); kfree(q->delay_dist); } @@ -611,95 +612,9 @@ rtattr_failure: return -1; } -static int netem_dump_class(struct Qdisc *sch, unsigned long cl, - struct sk_buff *skb, struct tcmsg *tcm) -{ - struct netem_sched_data *q = qdisc_priv(sch); - - if (cl != 1) /* only one class */ - return -ENOENT; - - tcm->tcm_handle |= TC_H_MIN(1); - tcm->tcm_info = q->qdisc->handle; - - return 0; -} - -static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) -{ - struct netem_sched_data *q = qdisc_priv(sch); - - if (new == NULL) - new = &noop_qdisc; - - sch_tree_lock(sch); - *old = xchg(&q->qdisc, new); - qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); - qdisc_reset(*old); - sch_tree_unlock(sch); - - return 0; -} - -static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg) -{ - struct netem_sched_data *q = qdisc_priv(sch); - return q->qdisc; -} - -static unsigned long netem_get(struct Qdisc *sch, u32 classid) -{ - return 1; -} - -static void netem_put(struct Qdisc *sch, unsigned long arg) -{ -} - -static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct rtattr **tca, unsigned long *arg) -{ - return -ENOSYS; -} - -static int netem_delete(struct Qdisc *sch, unsigned long arg) -{ - return -ENOSYS; -} - -static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker) -{ - if (!walker->stop) { - if (walker->count >= walker->skip) - if (walker->fn(sch, 1, walker) < 0) { - walker->stop = 1; - return; - } - walker->count++; - } -} - -static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl) -{ - return NULL; -} - -static const struct Qdisc_class_ops netem_class_ops = { - .graft = netem_graft, - .leaf = netem_leaf, - .get = netem_get, - .put = netem_put, - .change = netem_change_class, - .delete = netem_delete, - .walk = netem_walk, - .tcf_chain = netem_find_tcf, - .dump = netem_dump_class, -}; - static struct Qdisc_ops netem_qdisc_ops __read_mostly = { .id = "netem", - .cl_ops = &netem_class_ops, + .cl_ops = &pseudo_classful_ops, .priv_size = sizeof(struct netem_sched_data), .enqueue = netem_enqueue, .dequeue = netem_dequeue, diff --git a/net/sched/sch_pseudo_classful.c b/net/sched/sch_pseudo_classful.c new file mode 100644 index 0000000..5b9fba5 --- /dev/null +++ b/net/sched/sch_pseudo_classful.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2007 Patrick McHardy, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +static int sch_pc_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, + struct Qdisc **old) +{ + struct pc_sched_data *q = qdisc_priv(sch); + + if (new == NULL) + new = &noop_qdisc; + + sch_tree_lock(sch); + *old = xchg(&q->qdisc, new); + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); + return 0; +} + +static int sch_pc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + struct rtattr **tca, unsigned long *arg) +{ + return -ENOSYS; +} + +static struct Qdisc *sch_pc_leaf(struct Qdisc *sch, unsigned long arg) +{ + return ((struct pc_sched_data *)qdisc_priv(sch))->qdisc; +} + +static unsigned long sch_pc_get(struct Qdisc *sch, u32 classid) +{ + return 1; +} + +static void sch_pc_put(struct Qdisc *sch, unsigned long arg) +{ + return; +} + +static int sch_pc_delete(struct Qdisc *sch, unsigned long arg) +{ + return -ENOSYS; +} + +static struct tcf_proto **sch_pc_tcf_chain(struct Qdisc *sch, unsigned long cl) +{ + return NULL; +} + +static int sch_pc_dump_class(struct Qdisc *sch, unsigned long cl, + struct sk_buff *skb, struct tcmsg *tcm) +{ + struct pc_sched_data *q = qdisc_priv(sch); + + if (cl != 1) + return -ENOENT; + + tcm->tcm_handle |= TC_H_MIN(1); + tcm->tcm_info = q->qdisc->handle; + return 0; +} + +static void sch_pc_walk(struct Qdisc *sch, struct qdisc_walker *walker) +{ + if (!walker->stop) { + if (walker->count >= walker->skip) + if (walker->fn(sch, 1, walker) < 0) { + walker->stop = 1; + return; + } + walker->count++; + } +} + +const struct Qdisc_class_ops pseudo_classful_ops = { + .graft = sch_pc_graft, + .leaf = sch_pc_leaf, + .get = sch_pc_get, + .put = sch_pc_put, + .change = sch_pc_change_class, + .delete = sch_pc_delete, + .walk = sch_pc_walk, + .tcf_chain = sch_pc_tcf_chain, + .dump = sch_pc_dump_class, +}; +EXPORT_SYMBOL(pseudo_classful_ops); + +MODULE_LICENSE("GPL"); diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 076f1ef..fc61675 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -38,11 +38,12 @@ struct red_sched_data { + struct pc_sched_data class; + u32 limit; /* HARD maximal queue length */ unsigned char flags; struct red_parms parms; struct red_stats stats; - struct Qdisc *qdisc; }; static inline int red_use_ecn(struct red_sched_data *q) @@ -58,7 +59,7 @@ static inline int red_use_harddrop(struct red_sched_data *q) static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch) { struct red_sched_data *q = qdisc_priv(sch); - struct Qdisc *child = q->qdisc; + struct Qdisc *child = q->class.qdisc; int ret; q->parms.qavg = red_calc_qavg(&q->parms, child->qstats.backlog); @@ -111,7 +112,7 @@ congestion_drop: static int red_requeue(struct sk_buff *skb, struct Qdisc* sch) { struct red_sched_data *q = qdisc_priv(sch); - struct Qdisc *child = q->qdisc; + struct Qdisc *child = q->class.qdisc; int ret; if (red_is_idling(&q->parms)) @@ -129,7 +130,7 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch) { struct sk_buff *skb; struct red_sched_data *q = qdisc_priv(sch); - struct Qdisc *child = q->qdisc; + struct Qdisc *child = q->class.qdisc; skb = qdisc_dequeue(child); if (skb) @@ -143,7 +144,7 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch) static unsigned int red_drop(struct Qdisc* sch) { struct red_sched_data *q = qdisc_priv(sch); - struct Qdisc *child = q->qdisc; + struct Qdisc *child = q->class.qdisc; unsigned int len; len = qdisc_drop(child); @@ -164,7 +165,7 @@ static void red_reset(struct Qdisc* sch) { struct red_sched_data *q = qdisc_priv(sch); - qdisc_reset(q->qdisc); + qdisc_reset(q->class.qdisc); sch->q.qlen = 0; red_restart(&q->parms); } @@ -172,7 +173,7 @@ static void red_reset(struct Qdisc* sch) static void red_destroy(struct Qdisc *sch) { struct red_sched_data *q = qdisc_priv(sch); - qdisc_destroy(q->qdisc); + qdisc_destroy(q->class.qdisc); } static int red_change(struct Qdisc *sch, struct rtattr *opt) @@ -203,8 +204,9 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt) q->flags = ctl->flags; q->limit = ctl->limit; if (child) { - qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); - qdisc_destroy(xchg(&q->qdisc, child)); + qdisc_tree_decrease_qlen(q->class.qdisc, + q->class.qdisc->q.qlen); + qdisc_destroy(xchg(&q->class.qdisc, child)); } red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, @@ -222,7 +224,7 @@ static int red_init(struct Qdisc* sch, struct rtattr *opt) { struct red_sched_data *q = qdisc_priv(sch); - q->qdisc = &noop_qdisc; + q->class.qdisc = &noop_qdisc; return red_change(sch, opt); } @@ -261,94 +263,10 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) return gnet_stats_copy_app(d, &st, sizeof(st)); } -static int red_dump_class(struct Qdisc *sch, unsigned long cl, - struct sk_buff *skb, struct tcmsg *tcm) -{ - struct red_sched_data *q = qdisc_priv(sch); - - if (cl != 1) - return -ENOENT; - tcm->tcm_handle |= TC_H_MIN(1); - tcm->tcm_info = q->qdisc->handle; - return 0; -} - -static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) -{ - struct red_sched_data *q = qdisc_priv(sch); - - if (new == NULL) - new = &noop_qdisc; - - sch_tree_lock(sch); - *old = xchg(&q->qdisc, new); - qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); - qdisc_reset(*old); - sch_tree_unlock(sch); - return 0; -} - -static struct Qdisc *red_leaf(struct Qdisc *sch, unsigned long arg) -{ - struct red_sched_data *q = qdisc_priv(sch); - return q->qdisc; -} - -static unsigned long red_get(struct Qdisc *sch, u32 classid) -{ - return 1; -} - -static void red_put(struct Qdisc *sch, unsigned long arg) -{ - return; -} - -static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct rtattr **tca, unsigned long *arg) -{ - return -ENOSYS; -} - -static int red_delete(struct Qdisc *sch, unsigned long cl) -{ - return -ENOSYS; -} - -static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker) -{ - if (!walker->stop) { - if (walker->count >= walker->skip) - if (walker->fn(sch, 1, walker) < 0) { - walker->stop = 1; - return; - } - walker->count++; - } -} - -static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl) -{ - return NULL; -} - -static const struct Qdisc_class_ops red_class_ops = { - .graft = red_graft, - .leaf = red_leaf, - .get = red_get, - .put = red_put, - .change = red_change_class, - .delete = red_delete, - .walk = red_walk, - .tcf_chain = red_find_tcf, - .dump = red_dump_class, -}; - static struct Qdisc_ops red_qdisc_ops __read_mostly = { .id = "red", .priv_size = sizeof(struct red_sched_data), - .cl_ops = &red_class_ops, + .cl_ops = &pseudo_classful_ops, .enqueue = red_enqueue, .dequeue = red_dequeue, .requeue = red_requeue, diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 5fd4dff..6590ce3 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -99,6 +99,8 @@ struct tbf_sched_data { + struct pc_sched_data class; + /* Parameters */ u32 limit; /* Maximal length of backlog: bytes */ u32 buffer; /* Token bucket depth/rate: MUST BE >= MTU/B */ @@ -111,7 +113,6 @@ struct tbf_sched_data long tokens; /* Current number of B tokens */ long ptokens; /* Current number of P tokens */ psched_time_t t_c; /* Time check-point */ - struct Qdisc *qdisc; /* Inner qdisc, default - bfifo queue */ struct qdisc_watchdog watchdog; /* Watchdog timer */ }; @@ -133,7 +134,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) return NET_XMIT_DROP; } - ret = qdisc_enqueue(skb, q->qdisc); + ret = qdisc_enqueue(skb, q->class.qdisc); if (ret != NET_XMIT_SUCCESS) { sch->qstats.drops++; return ret; @@ -150,7 +151,7 @@ static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch) struct tbf_sched_data *q = qdisc_priv(sch); int ret; - ret = qdisc_requeue(skb, q->qdisc); + ret = qdisc_requeue(skb, q->class.qdisc); if (ret == NET_XMIT_SUCCESS) { sch->q.qlen++; sch->qstats.requeues++; @@ -164,7 +165,7 @@ static unsigned int tbf_drop(struct Qdisc* sch) struct tbf_sched_data *q = qdisc_priv(sch); unsigned int len = 0; - len = qdisc_drop(q->qdisc); + len = qdisc_drop(q->class.qdisc); if (len > 0) { sch->q.qlen--; sch->qstats.drops++; @@ -177,7 +178,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch) struct tbf_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; - skb = qdisc_dequeue(q->qdisc); + skb = qdisc_dequeue(q->class.qdisc); if (skb) { psched_time_t now; @@ -222,9 +223,9 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch) (cf. CSZ, HPFQ, HFSC) */ - if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { + if (q->class.qdisc->ops->requeue(skb, q->class.qdisc) != NET_XMIT_SUCCESS) { /* When requeue fails skb is dropped */ - qdisc_tree_decrease_qlen(q->qdisc, 1); + qdisc_tree_decrease_qlen(q->class.qdisc, 1); sch->qstats.drops++; } @@ -237,7 +238,7 @@ static void tbf_reset(struct Qdisc* sch) { struct tbf_sched_data *q = qdisc_priv(sch); - qdisc_reset(q->qdisc); + qdisc_reset(q->class.qdisc); sch->q.qlen = 0; q->t_c = psched_get_time(); q->tokens = q->buffer; @@ -295,8 +296,8 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt) sch_tree_lock(sch); if (child) { - qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); - qdisc_destroy(xchg(&q->qdisc, child)); + qdisc_tree_decrease_qlen(q->class.qdisc, q->class.qdisc->q.qlen); + qdisc_destroy(xchg(&q->class.qdisc, child)); } q->limit = qopt->limit; q->mtu = qopt->mtu; @@ -325,7 +326,7 @@ static int tbf_init(struct Qdisc* sch, struct rtattr *opt) q->t_c = psched_get_time(); qdisc_watchdog_init(&q->watchdog, sch); - q->qdisc = &noop_qdisc; + q->class.qdisc = &noop_qdisc; return tbf_change(sch, opt); } @@ -341,7 +342,7 @@ static void tbf_destroy(struct Qdisc *sch) if (q->R_tab) qdisc_put_rtab(q->R_tab); - qdisc_destroy(q->qdisc); + qdisc_destroy(q->class.qdisc); } static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb) @@ -372,96 +373,8 @@ rtattr_failure: return -1; } -static int tbf_dump_class(struct Qdisc *sch, unsigned long cl, - struct sk_buff *skb, struct tcmsg *tcm) -{ - struct tbf_sched_data *q = qdisc_priv(sch); - - if (cl != 1) /* only one class */ - return -ENOENT; - - tcm->tcm_handle |= TC_H_MIN(1); - tcm->tcm_info = q->qdisc->handle; - - return 0; -} - -static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) -{ - struct tbf_sched_data *q = qdisc_priv(sch); - - if (new == NULL) - new = &noop_qdisc; - - sch_tree_lock(sch); - *old = xchg(&q->qdisc, new); - qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); - qdisc_reset(*old); - sch_tree_unlock(sch); - - return 0; -} - -static struct Qdisc *tbf_leaf(struct Qdisc *sch, unsigned long arg) -{ - struct tbf_sched_data *q = qdisc_priv(sch); - return q->qdisc; -} - -static unsigned long tbf_get(struct Qdisc *sch, u32 classid) -{ - return 1; -} - -static void tbf_put(struct Qdisc *sch, unsigned long arg) -{ -} - -static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct rtattr **tca, unsigned long *arg) -{ - return -ENOSYS; -} - -static int tbf_delete(struct Qdisc *sch, unsigned long arg) -{ - return -ENOSYS; -} - -static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker) -{ - if (!walker->stop) { - if (walker->count >= walker->skip) - if (walker->fn(sch, 1, walker) < 0) { - walker->stop = 1; - return; - } - walker->count++; - } -} - -static struct tcf_proto **tbf_find_tcf(struct Qdisc *sch, unsigned long cl) -{ - return NULL; -} - -static const struct Qdisc_class_ops tbf_class_ops = -{ - .graft = tbf_graft, - .leaf = tbf_leaf, - .get = tbf_get, - .put = tbf_put, - .change = tbf_change_class, - .delete = tbf_delete, - .walk = tbf_walk, - .tcf_chain = tbf_find_tcf, - .dump = tbf_dump_class, -}; - static struct Qdisc_ops tbf_qdisc_ops __read_mostly = { - .next = NULL, - .cl_ops = &tbf_class_ops, + .cl_ops = &pseudo_classful_ops, .id = "tbf", .priv_size = sizeof(struct tbf_sched_data), .enqueue = tbf_enqueue,