日期:2014-05-16 浏览次数:20892 次
7.10 U32
Ugly (or Universal) 32bit key Packet Classifier,丑陋(或通用)的32位关键数据包分类器
U32和RSVP类似, 但能更详细清楚地定义各中协议的参数, 比较符合通常的使用习惯, 而且这些参数都看成U32数来进行匹配的, 目前使用得比较多, 其代码在net/sched/cls_u32.c中定义。
7.10.1 数据结构和过滤器操作结构
/* include/linux/pkt_cls.h */
// u32关键字匹配
struct tc_u32_key
{
// 数值和掩码
__u32 mask;
__u32 val;
// 偏移量和偏移掩码
int off;
int offmask;
};
// u32选择子结构
struct tc_u32_sel
{
// 标志
unsigned char flags;
// 偏移移动数
unsigned char offshift;
// key(匹配条件)的数量
unsigned char nkeys;
// 偏移掩码
__u16 offmask;
// 偏移值
__u16 off;
short offoff;
short hoff;
__u32 hmask;
// 具体的匹配key结构
struct tc_u32_key keys[0];
};
// u32标志结构
struct tc_u32_mark
{
// 值
__u32 val;
// 掩码
__u32 mask;
// 匹配成功的数据包数量
__u32 success;
};
struct tc_u32_pcnt
{
__u64 rcnt;
__u64 rhit;
__u64 kcnts[0];
};
/* net/sched/cls_u32.c */
// u32核心节点,用来定义一条tc filter规则中的U32匹配
struct tc_u_knode
{
// 下一项
struct tc_u_knode *next;
// 句柄
u32 handle;
// 指向上层的hnode
struct tc_u_hnode *ht_up;
// TCF扩展结构
struct tcf_exts exts;
#ifdef CONFIG_NET_CLS_IND
// 网卡设备名称
char indev[IFNAMSIZ];
#endif
u8 fshift;
// TCF分类结果
struct tcf_result res;
// 指向下层的hnode
struct tc_u_hnode *ht_down;
#ifdef CONFIG_CLS_U32_PERF
struct tc_u32_pcnt *pf;
#endif
#ifdef CONFIG_CLS_U32_MARK
// MARK标志
struct tc_u32_mark mark;
#endif
// 选择子, 也就是匹配条件
struct tc_u32_sel sel;
};
// u32的哈希节点, 相当于RSVP的会话节点
struct tc_u_hnode
{
// 下一项hnode
struct tc_u_hnode *next;
// 句柄
u32 handle;
// 优先权
u32 prio;
// 回指u_common结构
struct tc_u_common *tp_c;
// 引用数
int refcnt;
// 哈希链表数量
unsigned divisor;
// knode哈希链表, 这个参数应该取名kt好了
struct tc_u_knode *ht[1];
};
// u32通用节点,相当于RSVP的根节点
struct tc_u_common
{
// 下一项common节点
struct tc_u_common *next;
// 指向hnode的哈希表
struct tc_u_hnode *hlist;
// Qdisc结构
struct Qdisc *q;
// 引用值
int refcnt;
u32 hgenerator;
};
// u32根节点指针,作为全局变量, 用来链接所有的common节点, 每个节点是按Qdisc进行区分的
static struct tc_u_common *u32_list;
// u32扩展映射结构
static struct tcf_ext_map u32_ext_map = {
.action = TCA_U32_ACT,
.police = TCA_U32_POLICE
};
// 操作结构
static struct tcf_proto_ops cls_u32_ops = {
.next = NULL,
.kind = "u32",
.classify = u32_classify,
.init = u32_init,
.destroy = u32_destroy,
.get = u32_get,
.put = u32_put,
.change = u32_change,
.delete = u32_delete,
.walk = u32_walk,
.dump = u32_dump,
.owner = THIS_MODULE,
};
7.10.2 初始化
static int u32_init(struct tcf_proto *tp)
{
struct tc_u_hnode *root_ht;
struct tc_u_common *tp_c;
// 遍历u32链表, 查找是否已经有和该Qdisc相同的u32节点, 也就是说可以同时在不同的Qdisc
// 的数据包分类中使用u32
for (tp_c = u32_list; tp_c; tp_c = tp_c->next)
if (tp_c->q == tp->q)
break;
// 分配hnode结构作为根
root_ht = kzalloc(sizeof(*root_ht), GFP_KERNEL);
if (root_ht == NULL)
return -ENOBUFS;
// 初始化hnode参数
root_ht->divisor = 0;
// 节点索引值
root_ht->refcnt++;
// 句柄, 是hnode类型的, 低20位为0
root_ht->handle = tp_c ? gen_new_htid(tp_c) : 0x80000000;
// 优先权
root_ht->prio = tp->prio;
// 如果相应Qdisc的u32同样节点不存在
if (tp_c == NULL) {
// 新分配common节点空间
tp_c = kzalloc(sizeof(*tp_c), GFP_KERNEL);
if (tp_c == NULL) {
kfree(root_ht);
return -ENOBUFS;
}
// 设置Qdisc
tp_c->q = tp->q;
// 加到u32通用节点链表头位置
tp_c->next = u32_list;
u32_list = tp_c;
}
// 通用结构引用增加
tp_c->refcnt++;
// 将hnode添加到u_common结构的哈希链表头
root_ht->next = tp_c->hlist;
tp_c->hlist = root_ht;
root_ht->tp_c = tp_c;
// TCF过滤规则表的根节点设置为该hnode
tp->root = root_ht;
// TCF数据是hnode所在u_common结构
tp->data = tp_c;
return 0;
}
7.10.3 分类
static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res)
{
// 构造一个堆栈
struct {
struct tc_u_knode *knode;
u8 *ptr;
} stack[TC_U32_MAXDEPTH];
// u32根节点
struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root;
// IP头指针
u8 *ptr = skb->nh.raw;
struct tc_u_knode *n;
int sdepth = 0;
int off2