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;
}