tc qdisc add dev eth0 handle 2 root tbf burst 200kb rate 200kbps mtu 1540 latency 10
int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
{
struct qdisc_util *q = NULL;
struct tc_estimator est;
struct {
struct tc_sizespec szopts;
__u16 *data;
} stab;
char d[16];
char k[16];
struct {
struct nlmsghdr n;
struct tcmsg t;
char buf[TCA_BUF_MAX];
} req;
memset(&req, 0, sizeof(req));
memset(&stab, 0, sizeof(stab));
memset(&est, 0, sizeof(est));
memset(&d, 0, sizeof(d));
memset(&k, 0, sizeof(k));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
req.n.nlmsg_flags = NLM_F_REQUEST|flags;
req.n.nlmsg_type = cmd;
req.t.tcm_family = AF_UNSPEC;
while (argc > 0) {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
if (d[0])
duparg("dev", *argv);
strncpy(d, *argv, sizeof(d)-1);//获取操作的设备eth0
} else if (strcmp(*argv, "handle") == 0) {
__u32 handle;
if (req.t.tcm_handle)
duparg("handle", *argv);
NEXT_ARG();
if (get_qdisc_handle(&handle, *argv))
invarg(*argv, "invalid qdisc ID");
req.t.tcm_handle = handle;//获取操作的句柄
} else if (strcmp(*argv, "root") == 0) {
if (req.t.tcm_parent) {
fprintf(stderr, "Error: \"root\" is duplicate parent ID\n");
return -1;
}
req.t.tcm_parent = TC_H_ROOT;//如果是根
#ifdef TC_H_INGRESS
} else if (strcmp(*argv, "ingress") == 0) {
if (req.t.tcm_parent) {
fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n");
return -1;
}
req.t.tcm_parent = TC_H_INGRESS;//设置入口句柄
strncpy(k, "ingress", sizeof(k)-1);
q = get_qdisc_kind(k);
req.t.tcm_handle = 0xffff0000;
argc--; argv++;
break;
#endif
} else if (strcmp(*argv, "parent") == 0) {
__u32 handle;
NEXT_ARG();
if (req.t.tcm_parent)
duparg("parent", *argv);
if (get_tc_classid(&handle, *argv))
invarg(*argv, "invalid parent ID");
req.t.tcm_parent = handle;//获取操作的父句柄
} else if (matches(*argv, "estimator") == 0) {
if (parse_estimator(&argc, &argv, &est))
return -1;
} else if (matches(*argv, "stab") == 0) {
if (parse_size_table(&argc, &argv, &stab.szopts) < 0)
return -1;
continue;
} else if (matches(*argv, "help") == 0) {
usage();
} else {
strncpy(k, *argv, sizeof(k)-1);//获取操作的qdisc名称tbf
q = get_qdisc_kind(k);
argc--; argv++;
break;//退出循环,然后把余下的选项交由相应的模块分析
}
argc--; argv++;
}
if (k[0])
addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);//把qdisc名称放入TCA_KIND属性
if (est.ewma_log)
addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
if (q) {
if (!q->parse_qopt) {
fprintf(stderr, "qdisc '%s' does not support option parsing\n", k);
return -1;
}
if (q->parse_qopt(q, argc, argv, &req.n))
return 1;
} else {
if (argc) {
if (matches(*argv, "help") == 0)
usage();
fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv);
return -1;
}
}
if (check_size_table_opts(&stab.szopts)) {
struct rtattr *tail;
if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) {
fprintf(stderr, "failed to calculate size table.\n");
return -1;
}
tail = NLMSG_TAIL(&req.n);
addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0);
addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts,
sizeof(stab.szopts));
if (stab.data)
addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data,
stab.szopts.tsize * sizeof(__u16));
tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
if (stab.data)
free(stab.data);
}
if (d[0]) {
int idx;
ll_init_map(&rth);
if ((idx = ll_name_to_index(d)) == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", d);
return 1;
}
req.t.tcm_ifindex = idx;//获取操作设备的ifindex
}
//把操作信息通过rtnetlink发给内核进行
if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
return 2;
return 0;
}
内核收到后调用下面函数
static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
{
struct tcmsg *tcm;
struct rtattr **tca;
struct net_device *dev;
u32 clid;
struct Qdisc *q, *p;
int err;
replay:
/* Reinit, just in case something touches this. */
tcm = NLMSG_DATA(n);
tca = arg;
clid = tcm->tcm_parent;//获取操作的父句柄
q = p = NULL;
if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL)//根据ifindex取得操作的设备
return -ENODEV;
if (clid) {
if (clid != TC_H_ROOT) {//如果不是root
if (clid != TC_H_INGRESS) {//如果不是NGRESS,查找对于的qdisc
if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)
return -ENOENT;
q = qdisc_leaf(p, clid);//获取操作的qdisc
} else { /*ingress */
q = dev->qdisc_ingress;
}
} else {
q = dev->qdisc_sleeping;//如果是根,则把qdisc_sleeping复制给q
}
/* It may be default qdisc, ignore it */
if (q && q->handle == 0)如果是默认的pfifo_fast
q = NULL;
//如果q为空,tcm->tcm_handle为0没有设置,或者,q->handle != tcm->tcm_handle
if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) {
if (tcm->tcm_handle) {//如果设置了handle
if (q && !(n->nlmsg_flags&NLM_F_REPLACE))//如果q非空且不是替换
return -EEXIST;
if (TC_H_MIN(tcm->tcm_handle))//判断handle合法性
return -EINVAL;
if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL)//查找对应handle,不存在创建
goto create_n_graft;
if (n->nlmsg_flags&NLM_F_EXCL)//找到但设置了NLM_F_EXCL排斥标志, 返回对象存在错误
return -EEXIST;
//比较TC命令中的算法名称和Qdisc名称算法相同
if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))
return -EINVAL;
if (q == p ||
(p && check_loop(q, p, 0)))
return -ELOOP;
atomic_inc(&q->refcnt);
goto graft;
} else {
if (q == NULL)
goto create_n_graft;
/* This magic test requires explanation.
*
* We know, that some child q is already
* attached to this parent and have choice:
* either to change it or to create/graft new one.
*
* 1. We are allowed to create/graft only
* if CREATE and REPLACE flags are set.
*
* 2. If EXCL is set, requestor wanted to say,
* that qdisc tcm_handle is not expected
* to exist, so that we choose create/graft too.
*
* 3. The last case is when no flags are set.
* Alas, it is sort of hole in API, we
* cannot decide what to do unambiguously.
* For now we select create/graft, if
* user gave KIND, which does not match existing.
*/
if ((n->nlmsg_flags&NLM_F_CREATE) &&
(n->nlmsg_flags&NLM_F_REPLACE) &&
((n->nlmsg_flags&NLM_F_EXCL) ||
(tca[TCA_KIND-1] &&
rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))))
goto create_n_graft;
}
}
} else {//上面条件不成立,实际上是change命令
if (!tcm->tcm_handle)
return -EINVAL;
q = qdisc_lookup(dev, tcm->tcm_handle);
}
/* Change qdisc parameters */
if (q == NULL)
return -ENOENT;
if (n->nlmsg_flags&NLM_F_EXCL)
return -EEXIST;
if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))
return -EINVAL;
err = qdisc_change(q, tca);
if (err == 0)
qdisc_notify(skb, n, clid, NULL, q);
return err;
create_n_graft:
if (!(n->nlmsg_flags&NLM_F_CREATE))
return -ENOENT;
if (clid == TC_H_INGRESS)
q = qdisc_create(dev, tcm->tcm_parent, tca, &err);//创建qdisc
else
q = qdisc_create(dev, tcm->tcm_handle, tca, &err);
if (q == NULL) {
if (err == -EAGAIN)
goto replay;
return err;
}
graft:
if (1) {
struct Qdisc *old_q = NULL;
err = qdisc_graft(dev, p, clid, q, &old_q);//把创建的qdisc 移植相应节点
if (err) {
if (q) {
spin_lock_bh(&dev->queue_lock);
qdisc_destroy(q);
spin_unlock_bh(&dev->queue_lock);
}
return err;
}
qdisc_notify(skb, n, clid, old_q, q);
if (old_q) {
spin_lock_bh(&dev->queue_lock);
qdisc_destroy(old_q);
spin_unlock_bh(&dev->queue_lock);
}
}
return 0;
}
阅读(4393) | 评论(0) | 转发(1) |