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