static struct Qdisc * qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, struct Qdisc *p, u32 parent, u32 handle, struct nlattr **tca, int *errp) { /* *dev:创建的qdisc最终会关联到这个设备上 *tca:是找到想要的Qdisc_ops的关键 *handle:qdisc_id *parent:parent_id *p:parent */ int err; struct nlattr *kind = tca[TCA_KIND]; struct Qdisc *sch;//要创建的qdisc struct Qdisc_ops *ops; struct qdisc_size_table *stab; /* *首要的事情是找到想要的Qdisc_ops *函数qdiscc_lookup_ops通过kind来搜索qdisc_base中注册的所有qdisc_ops *直到找到为止,它会通过Qdisc_ops中的id来判断是否找到 */ ops = qdisc_lookup_ops(kind); #ifdef CONFIG_MODULES if (ops == NULL && kind != NULL) { /** *如果没有找到,但是确实存在,那么重新注册,安装这个moduel模块实现 */ char name[IFNAMSIZ]; if (nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { /* We dropped the RTNL semaphore in order to * perform the module load. So, even if we * succeeded in loading the module we have to * tell the caller to replay the request. We * indicate this using -EAGAIN. * We replay the request because the device may * go away in the mean time. */ rtnl_unlock(); request_module("sch_%s", name); rtnl_lock(); //ok, 安装这个moduel后,从新查找需要的Qdisc_ops ops = qdisc_lookup_ops(kind); if (ops != NULL) { /* We will try again qdisc_lookup_ops, * so don't keep a reference. */ module_put(ops->owner); err = -EAGAIN; goto err_out; } } } #endif
err = -ENOENT; if (ops == NULL) goto err_out; /** *到这里,找到了相应的Qdisc_ops, 那么就开始创建Qdisc了 *函数会将ops赋值给Qdisc中的ops *Qdisc的enqueue和dequeue函数也是ops中的enqueue和dequeue函数 *同时dev_queue也会赋值给Qdisc中的dev_queue,注意dev_queue包含了 *Qdisc所在的dev信息,即通过dev_queue就知道Qdisc的dev */ sch = qdisc_alloc(dev_queue, ops); if (IS_ERR(sch)) { err = PTR_ERR(sch); goto err_out2; } /** *初始化parent_id */ sch->parent = parent; /** * #define TC_H_UNSPEC (0U) *#define TC_H_ROOT (0xFFFFFFFFU) *#define TC_H_INGRESS (0xFFFFFFF1U) *0 4294967295 4294967281 *对于handle,要比parent要弹性些。Parent需要用户指定其正确性, *而handler系统会检查handle的值的有效性,当handle等于TC_H_INGRESS *或者为0时, 系统会数据分配一个handle:即qdisc_id *例如: Add:tc qdisc add dev eth0 root handle 1: htb default 12 Dump: tc qdisc ls dev eth0 Result: qdisc htb 1: r2q 10 default 12 direct_packets_stat 5
ADD: tc qdisc add dev eth0 root handle 0: htb default 12 DUMP: tc qdisc ls dev eth0 RESULT: qdisc htb 8002: r2q 10 default 12 direct_packets_stat 34 */ if (handle == TC_H_INGRESS) { sch->flags |= TCQ_F_INGRESS; handle = TC_H_MAKE(TC_H_INGRESS, 0); lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock); } else { if (handle == 0) { handle = qdisc_alloc_handle(dev); err = -ENOMEM; if (handle == 0) goto err_out3; } lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock); }
//将合法的handle赋值给Qdisc-> handle sch->handle = handle; /** *如果opt中不存在init函数,或者存在并且初始化的成功时 *然后做进一步的初始化,如果创建的是HTB, *那么init函数就是htb_init *最后返回创建的Qdisc */ if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { if (tca[TCA_STAB]) { stab = qdisc_get_stab(tca[TCA_STAB]); if (IS_ERR(stab)) { err = PTR_ERR(stab); goto err_out4; } sch->stab = stab; } if (tca[TCA_RATE]) { spinlock_t *root_lock;
err = -EOPNOTSUPP; if (sch->flags & TCQ_F_MQROOT) goto err_out4;
if ((sch->parent != TC_H_ROOT) && !(sch->flags & TCQ_F_INGRESS) && (!p || !(p->flags & TCQ_F_MQROOT))) root_lock = qdisc_root_sleeping_lock(sch); else root_lock = qdisc_lock(sch);
err = gen_new_estimator(&sch->bstats, &sch->rate_est, root_lock, tca[TCA_RATE]); if (err) goto err_out4; }
qdisc_list_add(sch);
return sch; } err_out3: dev_put(dev); kfree((char *) sch - sch->padded); err_out2: module_put(ops->owner); err_out: *errp = err; return NULL;
err_out4: /* * Any broken qdiscs that would require a ops->reset() here? * The qdisc was never in action so it shouldn't be necessary. */ qdisc_put_stab(sch->stab); if (ops->destroy) ops->destroy(sch); goto err_out3; } |
|