日期:2014-05-16 浏览次数:20790 次
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