分享

LINUX TC:HTB相关源码

 北漂之邬 2014-11-07

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

*Qdiscenqueuedequeue函数也是ops中的enqueuedequeue函数

*同时dev_queue也会赋值给Qdisc中的dev_queue,注意dev_queue包含了

*Qdisc所在的dev信息,即通过dev_queue就知道Qdiscdev

*/

       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;

}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多