Linux内核中游量控制(13)

Linux内核中流量控制(13)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn

5.11.9 入队

static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
int ret;
// HTB私有数据结构
struct htb_sched *q = qdisc_priv(sch);
// 对数据包进行分类
struct htb_class *cl = htb_classify(skb, sch, &ret);
if (cl == HTB_DIRECT) {
// 分类结果是直接发送
/* enqueue to helper queue */
// 如果直接发送队列中的数据包长度小于队列限制值, 将数据包添加到队列末尾
if (q->direct_queue.qlen < q->direct_qlen) {
__skb_queue_tail(&q->direct_queue, skb);
q->direct_pkts++;
} else {
// 否则丢弃数据包
kfree_skb(skb);
sch->qstats.drops++;
return NET_XMIT_DROP;
}
#ifdef CONFIG_NET_CLS_ACT
// 定义了NET_CLS_ACT的情况(支持分类动作)
} else if (!cl) {
// 分类没有结果, 丢包
if (ret == NET_XMIT_BYPASS)
sch->qstats.drops++;
kfree_skb(skb);
return ret;
#endif
// 有分类结果, 进行分类相关的叶子节点流控结构的入队操作
} else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) !=
NET_XMIT_SUCCESS) {
// 入队不成功的话丢包
sch->qstats.drops++;
cl->qstats.drops++;
return NET_XMIT_DROP;
} else {
// 入队成功, 分类结构的包数字节数的统计数增加
cl->bstats.packets++;
cl->bstats.bytes += skb->len;
// 激活HTB类别, 建立该类别的数据提供树, 这样dequeue时可以从中取数据包
// 只有类别节点的模式是可发送和可租借的情况下才会激活, 如果节点是阻塞
// 模式, 则不会被激活
htb_activate(q, cl);
}
// HTB流控结构统计数更新, 入队成功
sch->q.qlen++;
sch->bstats.packets++;
sch->bstats.bytes += skb->len;
return NET_XMIT_SUCCESS;
}

大部分情况下数据包都不会进入直接处理队列, 而是进入各类别叶子节点, 因此入队的成功与否就在于叶子节点使用何种流控算法, 大都应该可以入队成功的, 入队不涉及类别节点模式的调整。

5.11.10 重入队

/* TODO: requeuing packet charges it to policers again !! */
static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
{
// HTB私有数据结构
struct htb_sched *q = qdisc_priv(sch);
int ret = NET_XMIT_SUCCESS;
// 对数据包进行HTB分类
struct htb_class *cl = htb_classify(skb, sch, &ret);
struct sk_buff *tskb;
// 是直接处理或无类别数据包
if (cl == HTB_DIRECT || !cl) {
// 如果当前直接队列没满而且是直接处理包, 就添加在直接处理队列表头
/* enqueue to helper queue */
if (q->direct_queue.qlen < q->direct_qlen && cl) {
__skb_queue_head(&q->direct_queue, skb);
} else {
// 队列慢或者无类别包
// 添加到队列头
__skb_queue_head(&q->direct_queue, skb);
// 从队列尾取一个数据包丢弃
tskb = __skb_dequeue_tail(&q->direct_queue);
kfree_skb(tskb);
sch->qstats.drops++;
return NET_XMIT_CN;
}
// 分类成功, 使用类别结构对应叶子流控节点的重入队操作
} else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) !=
NET_XMIT_SUCCESS) {
// 重入队失败, 丢包
sch->qstats.drops++;
cl->qstats.drops++;
return NET_XMIT_DROP;
} else
// 重入队成功, 激活类别结构, 构造数据包提供树
htb_activate(q, cl);
// 队列统计信息更新
sch->q.qlen++;
sch->qstats.requeues++;
return NET_XMIT_SUCCESS;
}

5.11.11 出队

HTB的出队是个非常复杂的处理过程, 函数调用过程为:
htb_dequeue
-> __skb_dequeue
-> htb_do_events
-> htb_safe_rb_erase
-> htb_change_class_mode
-> htb_add_to_wait_tree
-> htb_dequeue_tree
-> htb_lookup_leaf
-> htb_deactivate
-> q->dequeue
-> htb_next_rb_node
-> htb_charge_class
-> htb_change_class_mode
-> htb_safe_rb_erase
-> htb_add_to_wait_tree
-> htb_delay_by

static struct sk_buff *htb_dequeue(struct Qdisc *sch)
{
struct sk_buff *skb = NULL;
// HTB私有数据结构
struct htb_sched *q = qdisc_priv(sch);
int level;
long min_delay;
// 保存当前时间滴答数
q->jiffies = jiffies;
/* try to dequeue direct packets as high prio (!) to minimize cpu work */
// 先从当前直接发送队列取数据包, 直接发送队列中的数据有最高优先级, 可以说没有流量限制
skb = __skb_dequeue(&q->direct_queue);
if (skb != NULL) {
// 取到数据包, 更新参数, 非阻塞, 返回
sch->flags &= ~TCQ_F_THROTTLED;
sch->q.qlen--;
return skb;
}
// 如果HTB流控结构队列长度为0, 返回空
if (!sch->q.qlen)
goto fin;
// 获取当前有效时间值
PSCHED_GET_TIME(q->now);
// 最小延迟值初始化为最大整数
min_delay = LONG_MAX;
q->nwc_hit = 0;
// 遍历树的所有层次, 从叶子节点开始
for (level = 0; level < TC_HTB_MAXDEPTH; level++) {
/* common case optimization - skip event handler quickly */
int m;

Linux内核中游量控制(13)

相关文章:

你感兴趣的文章:

标签云: