0.0.1. Qdisc_ops is the core of a Qdisc. All kinds of the Qdisc_ops are linked in a list by qdisc_base. The key item of different Qdisc_ops is id[IFNAMSIZ].
Note: the list is a Singly-linked list, not a common list of kernel.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 158 struct Qdisc_ops {159 struct Qdisc_ops *next ;160 const struct Qdisc_class_ops *cl_ops ;161 char id[IFNAMSIZ];162 int priv_size;163 164 int (*enqueue)(struct sk_buff *, struct Qdisc *);165 struct sk_buff * (*dequeue )(struct Qdisc *);166 struct sk_buff * (*peek )(struct Qdisc *);167 unsigned int (*drop) (struct Qdisc *) ;168 169 int (*init)(struct Qdisc *, struct nlattr *arg);170 void (*reset)(struct Qdisc *);171 void (*destroy)(struct Qdisc *);172 int (*change)(struct Qdisc *, struct nlattr *arg);173 void (*attach)(struct Qdisc *);174 175 int (*dump)(struct Qdisc *, struct sk_buff *);176 int (*dump_stats)(struct Qdisc *, struct gnet_dump *);177 178 struct module *owner ;179 };
0.0.2. qdisc_base 1 2 3 134 135 136 static struct Qdisc_ops *qdisc_base ;
0.0.3. the default Qdisc_ops is default_qdisc_ops. 1 2 3 33 34 const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;35 EXPORT_SYMBOL(default_qdisc_ops);
1 2 3 4 5 6 7 8 9 10 11 526 struct Qdisc_ops pfifo_fast_ops __read_mostly = {527 .id = "pfifo_fast" ,528 .priv_size = sizeof (struct pfifo_fast_priv),529 .enqueue = pfifo_fast_enqueue,530 .dequeue = pfifo_fast_dequeue,531 .peek = pfifo_fast_peek,532 .init = pfifo_fast_init,533 .reset = pfifo_fast_reset,534 .dump = pfifo_fast_dump,535 .owner = THIS_MODULE,536 };
0.0.4. register_qdisc The list is not a sorted list, it would be better with sorted list, but these reg/unreg functions are rarely used. do some basic check for the methods of Qdisc_ops, and set some default values.
for example, method peek must be empty if method dequeue is empty.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 138 139 140 int register_qdisc (struct Qdisc_ops *qops) 141 {142 struct Qdisc_ops *q , **qp ;143 int rc = -EEXIST;144 145 write_lock(&qdisc_mod_lock);146 for (qp = &qdisc_base; (q = *qp) != NULL ; qp = &q->next)147 if (!strcmp (qops->id, q->id))148 goto out;149 150 if (qops->enqueue == NULL )151 qops->enqueue = noop_qdisc_ops.enqueue;152 if (qops->peek == NULL ) {153 if (qops->dequeue == NULL )154 qops->peek = noop_qdisc_ops.peek;155 else 156 goto out_einval;157 }158 if (qops->dequeue == NULL )159 qops->dequeue = noop_qdisc_ops.dequeue;160 161 if (qops->cl_ops) {162 const struct Qdisc_class_ops *cops = qops->cl_ops;163 164 if (!(cops->get && cops->put && cops->walk && cops->leaf))165 goto out_einval;166 167 if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))168 goto out_einval;169 }170 171 qops->next = NULL ;172 *qp = qops;173 rc = 0 ;174 out:175 write_unlock(&qdisc_mod_lock);176 return rc;177 178 out_einval:179 rc = -EINVAL;180 goto out;181 }182 EXPORT_SYMBOL(register_qdisc);
0.0.5. unregister_qdisc 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 184 int unregister_qdisc (struct Qdisc_ops *qops) 185 {186 struct Qdisc_ops *q , **qp ;187 int err = -ENOENT;188 189 write_lock(&qdisc_mod_lock);190 for (qp = &qdisc_base; (q = *qp) != NULL ; qp = &q->next)191 if (q == qops)192 break ;193 if (q) {194 *qp = q->next;195 q->next = NULL ;196 err = 0 ;197 }198 write_unlock(&qdisc_mod_lock);199 return err;200 }201 EXPORT_SYMBOL(unregister_qdisc);
0.0.6. all Qdisc_ops 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 junwei@localhost:~/git/linux$ grep register_qdisc net/ -Rw net/sched/sch_sfb.c: return register_qdisc(&sfb_qdisc_ops); net/sched/sch_fq.c: ret = register_qdisc(&fq_qdisc_ops); net/sched/sch_choke.c: return register_qdisc(&choke_qdisc_ops); net/sched/sch_codel.c: return register_qdisc(&codel_qdisc_ops); net/sched/sch_qfq.c: return register_qdisc(&qfq_qdisc_ops); net/sched/sch_atm.c: return register_qdisc(&atm_qdisc_ops); net/sched/sch_multiq.c: return register_qdisc(&multiq_qdisc_ops); net/sched/sch_cbq.c: return register_qdisc(&cbq_qdisc_ops); net/sched/sch_fq_codel.c: return register_qdisc(&fq_codel_qdisc_ops); net/sched/sch_dsmark.c: return register_qdisc(&dsmark_qdisc_ops); net/sched/sch_hfsc.c: return register_qdisc(&hfsc_qdisc_ops); net/sched/sch_htb.c: return register_qdisc(&htb_qdisc_ops); net/sched/sch_api.c:int register_qdisc (struct Qdisc_ops *qops) net/sched/sch_api.c:EXPORT_SYMBOL (register_qdisc) ; net/sched/sch_api.c: register_qdisc(&pfifo_fast_ops); net/sched/sch_api.c: register_qdisc(&pfifo_qdisc_ops); net/sched/sch_api.c: register_qdisc(&bfifo_qdisc_ops); net/sched/sch_api.c: register_qdisc(&pfifo_head_drop_qdisc_ops); net/sched/sch_api.c: register_qdisc(&mq_qdisc_ops); net/sched/sch_blackhole.c: return register_qdisc(&blackhole_qdisc_ops); net/sched/sch_drr.c: return register_qdisc(&drr_qdisc_ops); net/sched/sch_netem.c: return register_qdisc(&netem_qdisc_ops); net/sched/sch_prio.c: return register_qdisc(&prio_qdisc_ops); net/sched/sch_gred.c: return register_qdisc(&gred_qdisc_ops); net/sched/sch_ingress.c: return register_qdisc(&ingress_qdisc_ops); net/sched/sch_mqprio.c: return register_qdisc(&mqprio_qdisc_ops); net/sched/sch_sfq.c: return register_qdisc(&sfq_qdisc_ops); net/sched/sch_tbf.c: return register_qdisc(&tbf_qdisc_ops); net/sched/sch_red.c: return register_qdisc(&red_qdisc_ops); net/sched/sch_plug.c: return register_qdisc(&plug_qdisc_ops); net/sched/sch_teql.c: err = register_qdisc(&master->qops); junwei@localhost:~/git/linux$