Linux内核中游量控制(12)

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

5.11.3  HTB一些操作函数

5.11.3.1 转换函数

/* TODO: maybe compute rate when size is too large .. or drop ? */
// 将长度转换为令牌数
static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate,
int size)
{
// 根据大小计算合适的槽位
int slot = size >> rate->rate.cell_log;
// 如果超过了255, 限制为255
if (slot > 255) {
cl->xstats.giants++;
slot = 255;
}
return rate->data[slot];
}

// HTB哈希计算, 限制哈希结果小于16, 因为只有16个HASH表, 这个大小是定死的
static inline int htb_hash(u32 h)
{
#if HTB_HSIZE != 16
#error "Declare new hash for your HTB_HSIZE"
#endif
h ^= h >> 8; /* stolen from cbq_hash */
h ^= h >> 4;
return h & 0xf;
}

5.11.3.2 查询函数

/* find class in global hash table using given handle */
// 根据句柄handle查找HTB节点
static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
{
// HTB私有数据结构
struct htb_sched *q = qdisc_priv(sch);
struct hlist_node *p;
struct htb_class *cl;
if (TC_H_MAJ(handle) != sch->handle)
return NULL;
// 根据句柄计算哈希值, 然后遍历该哈希链表
hlist_for_each_entry(cl, p, q->hash + htb_hash(handle), hlist) {
// 查找类别ID和句柄handle相等的HTB节点返回
if (cl->classid == handle)
return cl;
}
return NULL;
}

5.11.3.3 分类函数

/**
* htb_classify - classify a packet into class
*
* It returns NULL if the packet should be dropped or -1 if the packet
* should be passed directly thru. In all other cases leaf class is returned.
* We allow direct class selection by classid in priority. The we examine
* filters in qdisc and in inner nodes (if higher filter points to the inner
* node). If we end up with classid MAJOR:0 we enqueue the skb into special
* internal fifo (direct). These packets then go directly thru. If we still
* have no valid leaf we try to use MAJOR:default leaf. It still unsuccessfull
* then finish and return direct queue.
*/
#define HTB_DIRECT (struct htb_class*)-1
// 获取HTB类别结构的ID
static inline u32 htb_classid(struct htb_class *cl)
{
// 如果类别结构有效(非空而且不是直接通过), 返回其类别ID, 否则返回TC_H_UNSPEC
// 表示没指定类别ID
return (cl && cl != HTB_DIRECT) ? cl->classid : TC_H_UNSPEC;
}

// HTB分类操作, 对数据包进行分类, 然后根据类别进行相关操作
// 返回NULL表示没找到, 返回-1表示是直接通过(不分类)的数据包
static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
int *qerr)
{
// HTB私有结构
struct htb_sched *q = qdisc_priv(sch);
struct htb_class *cl;
// 分类规则处理结果
struct tcf_result res;
// 分类过滤规则表
struct tcf_proto *tcf;
int result;
/* allow to select class by setting skb->priority to valid classid;
note that nfmark can be used too by attaching filter fw with no
rules in it */
// 如果数据包优先权值就等于流控节点和句柄handle, 属于根节点操作, 直接处理
if (skb->priority == sch->handle)
return HTB_DIRECT; /* X:0 (direct flow) selected */

// 查找和数据包优先权值对应的HTB叶子节点, 找到则返回
if ((cl = htb_find(skb->priority, sch)) != NULL && cl->level == 0)
return cl;

// 以下处理是没有找到和skb->priority直接对应的HTB叶子节点, 应该说实际应用中大部分
// 都是skb->priority为0的, 所以一般都会运行到这里
*qerr = NET_XMIT_BYPASS;
tcf = q->filter_list;
// 进行标准TC分类, 分类方法由TC命令定义的规则来实现
while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
#ifdef CONFIG_NET_CLS_ACT
// 定义了可对分类结果进行动作的内核选项的情况
switch (result) {
case TC_ACT_QUEUED:
case TC_ACT_STOLEN:
// 发送成功
*qerr = NET_XMIT_SUCCESS;
// 丢包
case TC_ACT_SHOT:
return NULL;
}
#elif defined(CONFIG_NET_CLS_POLICE)
// 没定义NET_CLS_ACT而定义了NET_CLS_POLICE的情况
// 如果分类结果是TC_POLICE_SHOT, 属于HTB直接处理
if (result == TC_POLICE_SHOT)
return HTB_DIRECT;
#endif
// 如果分类结果为空
if ((cl = (void *)res.class) == NULL) {
// 如果分类结果的ID等于流控句柄, 直接处理
if (res.classid == sch->handle)
return HTB_DIRECT; /* X:0 (direct flow) */
// 再根据结果的类别ID查找HTB叶子节点, 找不到的话退出循环
if ((cl = htb_find(res.classid, sch)) == NULL)
break; /* filter selected invalid classid */
}
// 分类找到的情况, 如果是叶子节点, 直接返回
if (!cl->level)
return cl; /* we hit leaf; re

Linux内核中游量控制(12)

相关文章:

你感兴趣的文章:

标签云: