读书人

Linux内核中游量控制(19)

发布时间: 2012-08-03 00:12:14 作者: rapoo

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

7.10 U32Ugly (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 = 0;// 选择参数初始化为0 int sel = 0;#ifdef CONFIG_CLS_U32_PERF int j;#endif int i, r;next_ht:// 通过选择参数指定的knode哈希表头 n = ht->ht[sel];next_knode:// 如果链表非空 if (n) {  struct tc_u32_key *key = n->sel.keys;#ifdef CONFIG_CLS_U32_PERF  n->pf->rcnt +=1;  j = 0;#endif#ifdef CONFIG_CLS_U32_MARK// 比较数据包中的nfmark值是否匹配  if ((skb->nfmark & n->mark.mask) != n->mark.val) {// 不匹配, 找下一个knode   n = n->next;   goto next_knode;  } else {// mark匹配成功, 计数增加   n->mark.success++;  }#endif// 遍历所有的U32匹配条件, 可包括地址,端口,ICMP类型/CODE,AH/ESP的SPI等  for (i = n->sel.nkeys; i>0; i--, key++) {// 所有U32匹配条件都是通过参数偏移量定义参数的位置// 匹配方法是取从数据包IP头开始的指定偏移量的32位数据, 然后和指定的值和掩码进行匹配计算// 如果匹配, 计算结果为0// 但完全使用偏移值来定义数据是有问题的, 比如TCP/UDP的端口, 都是固定偏移为20, 也就是// 普通最小IP包长的情况, 但如果该数据包带有IP选项使IP头长超过20时, 匹配就会失败   if ((*(u32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) {// 匹配失败, 找下一个knode节点    n = n->next;    goto next_knode;   }#ifdef CONFIG_CLS_U32_PERF   n->pf->kcnts[j] +=1;   j++;#endif  }//  if (n->ht_down == NULL) {check_terminal:// 如果带TERMINAL标志, 可以准备返回了   if (n->sel.flags&TC_U32_TERMINAL) {// 为分类结果结构赋值    *res = n->res;#ifdef CONFIG_NET_CLS_IND// 最后比较一下网卡参数    if (!tcf_match_indev(skb, n->indev)) {// 如果比较失败, 转下一个knode     n = n->next;     goto next_knode;    }#endif#ifdef CONFIG_CLS_U32_PERF    n->pf->rhit +=1;#endif// TCf扩展处理    r = tcf_exts_exec(skb, &n->exts, res);    if (r < 0) {// 失败的话转下一个knode     n = n->next;     goto next_knode;    }// 返回成功    return r;   }// 没TERMINAL标志, 转下一knode   n = n->next;   goto next_knode;  }// ht_down非空,转下一层  /* PUSH */// 检查层次数, 过大的话返回失败  if (sdepth >= TC_U32_MAXDEPTH)   goto deadloop;// 将knode节点n推入堆栈, 也保存当前的IP头指针值  stack[sdepth].knode = n;  stack[sdepth].ptr = ptr;  sdepth++;// ht_down非空的清空// 当前的hnode更新为ht_down  ht = n->ht_down;  sel = 0;// 该hnode匹配条件非空, 计算选择参数  if (ht->divisor)   sel = ht->divisor&u32_hash_fold(*(u32*)(ptr+n->sel.hoff), &n->sel,n->fshift);// 以下检查选择结构参数是否可用, 暂时不可用的话进行一些处理使之可用// 检查一下选择结构标志, 不带这些标志的话可以直接使用了  if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT)))   goto next_ht;// 至少带了这3个标志之一的情况// 设置了TC_U32_OFFSET或TC_U32_VAROFFSET, 计算偏移off2  if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) {   off2 = n->sel.off + 3;   if (n->sel.flags&TC_U32_VAROFFSET)    off2 += ntohs(n->sel.offmask & *(u16*)(ptr+n->sel.offoff)) >>n->sel.offshift;   off2 &= ~3;  }// 如果设置了EAT标志, 更新IP头指针位置  if (n->sel.flags&TC_U32_EAT) {   ptr += off2;   off2 = 0;  }// ptr指针还在合法范围内, 可以继续循环了  if (ptr < skb->tail)   goto next_ht;// 否则进行出堆栈操作了 } /* POP */// knode节点n为空, 到底了, sdepth如果非0, 进行出堆栈操作 if (sdepth--) {// 弹出堆栈底的knode节点  n = stack[sdepth].knode;// hnode更新为ht_up  ht = n->ht_up;// 恢复IP头指针  ptr = stack[sdepth].ptr;// 跳转到检查是否可以终止了  goto check_terminal; }// 堆栈空的, 分类失败 return -1;deadloop: if (net_ratelimit())  printk("cls_u32: dead loop\n"); return -1;} 7.10.4 释放 static void u32_destroy(struct tcf_proto *tp){// u32_common节点 struct tc_u_common *tp_c = tp->data;// 将tcf_proto的根节点交换为NULL, 准备将原来的节点保存到root_ht进行释放操作 struct tc_u_hnode *root_ht = xchg(&tp->root, NULL); BUG_TRAP(root_ht != NULL);// rooh_ht非空的话, 释放root_ht if (root_ht && --root_ht->refcnt == 0)  u32_destroy_hnode(tp, root_ht);// 减少common节点的引用数, 到0的话进行删除 if (--tp_c->refcnt == 0) {  struct tc_u_hnode *ht;  struct tc_u_common **tp_cp;// 遍历u32链表  for (tp_cp = &u32_list; *tp_cp; tp_cp = &(*tp_cp)->next) {// 查找匹配的common节点   if (*tp_cp == tp_c) {// 将该节点从链表中断开    *tp_cp = tp_c->next;    break;   }  }// 遍历hnode链表删除每个hnode内部参数  for (ht=tp_c->hlist; ht; ht = ht->next)   u32_clear_hnode(tp, ht);// 释放hnode链表本身元素  while ((ht = tp_c->hlist) != NULL) {   tp_c->hlist = ht->next;   BUG_TRAP(ht->refcnt == 0);   kfree(ht);  };// 释放common节点空间  kfree(tp_c); }// TCF_PROTO结构中的data参数清空 tp->data = NULL;}// 释放hnodestatic int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht){// u32的common节点 struct tc_u_common *tp_c = tp->data; struct tc_u_hnode **hn; BUG_TRAP(!ht->refcnt);// 清除hnode u32_clear_hnode(tp, ht);// 遍历u32_common的hnode链表 for (hn = &tp_c->hlist; *hn; hn = &(*hn)->next) {// 查找hnode节点  if (*hn == ht) {// 找到的话从链表中断开   *hn = ht->next;// 释放空间   kfree(ht);   return 0;  } } BUG_TRAP(0); return -ENOENT;}// 清除hnode内部参数static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht){ struct tc_u_knode *n; unsigned h;// 遍历所有链表 for (h=0; h<=ht->divisor; h++) {// 遍历链表所有knode节点  while ((n = ht->ht[h]) != NULL) {// 将knode节点从链表中断开   ht->ht[h] = n->next;// 释放knode   u32_destroy_key(tp, n);  } }}// 释放knodestatic int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n){// 和过滤器解除绑定 tcf_unbind_filter(tp, &n->res);// 释放TCF扩展结构 tcf_exts_destroy(tp, &n->exts);// 减少ht_down的引用数 if (n->ht_down)  n->ht_down->refcnt--;// 释放实际knode空间#ifdef CONFIG_CLS_U32_PERF kfree(n->pf);#endif kfree(n); return 0;} 7.10.5 获取// 根据handle查找hnode结构static unsigned long u32_get(struct tcf_proto *tp, u32 handle){ struct tc_u_hnode *ht; struct tc_u_common *tp_c = tp->data;// handle的高12位 if (TC_U32_HTID(handle) == TC_U32_ROOT)// 如果handle是根的话, 返回tcf_proto的  ht = tp->root; else// 根据handle值查找hnode  ht = u32_lookup_ht(tp_c, TC_U32_HTID(handle));// 找不到的话返回0 if (!ht)  return 0;// handle的低20位为0的话直接返回 if (TC_U32_KEY(handle) == 0)  return (unsigned long)ht;// 否则查找knode return (unsigned long)u32_lookup_key(ht, handle);}// 查找hnodestatic __inline__ struct tc_u_hnode *u32_lookup_ht(struct tc_u_common *tp_c, u32 handle){ struct tc_u_hnode *ht;// 遍历common节点的hnode链表, 查找和handle值匹配的hnode for (ht = tp_c->hlist; ht; ht = ht->next)  if (ht->handle == handle)   break; return ht;}// 查找knodestatic __inline__ struct tc_u_knode *u32_lookup_key(struct tc_u_hnode *ht, u32 handle){ unsigned sel; struct tc_u_knode *n = NULL;// handle的第12~19位作为选择值 sel = TC_U32_HASH(handle);// 过大的话返回失败 if (sel > ht->divisor)  goto out;// 遍历hnode的第sel个哈希表, 查找和handle值匹配的hnode for (n = ht->ht[sel]; n; n = n->next)  if (n->handle == handle)   break;out: return n;}7.10.6 放下// 空函数static void u32_put(struct tcf_proto *tp, unsigned long f){} 7.10.7 修改// 增加和修改tc filter规则时调用static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle,        struct rtattr **tca,        unsigned long *arg){// U32的common结构 struct tc_u_common *tp_c = tp->data; struct tc_u_hnode *ht; struct tc_u_knode *n; struct tc_u32_sel *s;// 配置参数 struct rtattr *opt = tca[TCA_OPTIONS-1]; struct rtattr *tb[TCA_U32_MAX]; u32 htid; int err;// 参数为空, 返回 if (opt == NULL)  return handle ? -EINVAL : 0;// 对参数进行解析, 解析结果返回到tb数组中, 解析失败返回 if (rtattr_parse_nested(tb, TCA_U32_MAX, opt) < 0)  return -EINVAL;// 如果knode非空, 是修改操作 if ((n = (struct tc_u_knode*)*arg) != NULL) {// 如果knode节点的handle的低20位为0, 是hnode, 返回错误  if (TC_U32_KEY(n->handle) == 0)   return -EINVAL;// 设置参数  return u32_set_parms(tp, base, n->ht_up, n, tb, tca[TCA_RATE-1]); }// knode为空// DIVISOR参数非空, 表示要建立hnode if (tb[TCA_U32_DIVISOR-1]) {// 获取DIVISOR参数  unsigned divisor = *(unsigned*)RTA_DATA(tb[TCA_U32_DIVISOR-1]);// 该参数不能大于256  if (--divisor > 0x100)   return -EINVAL;// 检查输入的handle如果表示knode的handle, 返回失败  if (TC_U32_KEY(handle))   return -EINVAL;// 如果handle为0, 重新生成一个hnode类型的handle, 该handle低20位为0  if (handle == 0) {   handle = gen_new_htid(tp->data);   if (handle == 0)    return -ENOMEM;  }// 分配hnode节点  ht = kzalloc(sizeof(*ht) + divisor*sizeof(void*), GFP_KERNEL);  if (ht == NULL)   return -ENOBUFS;// 填充hnode基本参数  ht->tp_c = tp_c;  ht->refcnt = 0;  ht->divisor = divisor;  ht->handle = handle;  ht->prio = tp->prio;  ht->next = tp_c->hlist;// 将hnode和common结构挂钩  tp_c->hlist = ht;// hnode地址作为返回结果  *arg = (unsigned long)ht;  return 0; }// 如果U32的哈希参数存在 if (tb[TCA_U32_HASH-1]) {// 读取hnodeID  htid = *(unsigned*)RTA_DATA(tb[TCA_U32_HASH-1]);// HTID是高12位  if (TC_U32_HTID(htid) == TC_U32_ROOT) {// 如果为U32的根ID// hnode取值为TCF_PROTO结构的根   ht = tp->root;   htid = ht->handle;  } else {// 否则根据此hnodeID查找hnode   ht = u32_lookup_ht(tp->data, TC_U32_HTID(htid));// 没找到, 返回错误   if (ht == NULL)    return -EINVAL;  } } else {// 哈希参数不存在, 按根节点处理  ht = tp->root;  htid = ht->handle; }// U32_HASH是取第12~19位 if (ht->divisor < TC_U32_HASH(htid))  return -EINVAL; if (handle) {// 输入handle非0时  if (TC_U32_HTID(handle) && TC_U32_HTID(handle^htid))   return -EINVAL;// 确保handle是knode类型的handle, 低12位非0  handle = htid | TC_U32_NODE(handle); } else// 重新分配knode类型的handle, 低12位非0  handle = gen_new_kid(ht, htid);// 必须有选择结构参数 if (tb[TCA_U32_SEL-1] == 0 ||     RTA_PAYLOAD(tb[TCA_U32_SEL-1]) < sizeof(struct tc_u32_sel))  return -EINVAL;// 提取选择结构 s = RTA_DATA(tb[TCA_U32_SEL-1]);// 分配knode和nkeys个key结构 n = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); if (n == NULL)  return -ENOBUFS;#ifdef CONFIG_CLS_U32_PERF// 分配PERF结构和nkeys个64位数 n->pf = kzalloc(sizeof(struct tc_u32_pcnt) + s->nkeys*sizeof(u64), GFP_KERNEL); if (n->pf == NULL) {  kfree(n);  return -ENOBUFS; }#endif// 拷贝选择结构 memcpy(&n->sel, s, sizeof(*s) + s->nkeys*sizeof(struct tc_u32_key));// knode的上层hnode n->ht_up = ht;// 基本 n->handle = handle;{// 计算fshift参数, 也去保证mask最低位为1, fshift就是原来mask中为1的最低位的位置 u8 i = 0; u32 mask = s->hmask; if (mask) {  while (!(mask & 1)) {   i++;   mask>>=1;  } } n->fshift = i;}#ifdef CONFIG_CLS_U32_MARK// 处理U32的mark参数 if (tb[TCA_U32_MARK-1]) {  struct tc_u32_mark *mark;// 如果mark参数非法, 返回失败  if (RTA_PAYLOAD(tb[TCA_U32_MARK-1]) < sizeof(struct tc_u32_mark)) {#ifdef CONFIG_CLS_U32_PERF   kfree(n->pf);#endif   kfree(n);   return -EINVAL;  }// 读取mark结构  mark = RTA_DATA(tb[TCA_U32_MARK-1]);// 拷贝到knode中  memcpy(&n->mark, mark, sizeof(struct tc_u32_mark));  n->mark.success = 0; }#endif// 设置新knode的参数 err = u32_set_parms(tp, base, ht, n, tb, tca[TCA_RATE-1]); if (err == 0) {// 命令成功  struct tc_u_knode **ins;// 遍历和handle相应的哈希链表找插入位置, 链表是按handle的低12位值排序,// 小的在前, 大的在后  for (ins = &ht->ht[TC_U32_HASH(handle)]; *ins; ins = &(*ins)->next)   if (TC_U32_NODE(handle) < TC_U32_NODE((*ins)->handle))    break;// 将新knode插入链表  n->next = *ins;  wmb();  *ins = n;// knode地址作为结果返回  *arg = (unsigned long)n;  return 0; }// 修改参数失败, 释放分配的空间#ifdef CONFIG_CLS_U32_PERF kfree(n->pf);#endif kfree(n); return err;}// 设置U32参数static int u32_set_parms(struct tcf_proto *tp, unsigned long base,    struct tc_u_hnode *ht,    struct tc_u_knode *n, struct rtattr **tb,    struct rtattr *est){ int err; struct tcf_exts e;// TCF扩展参数合法性处理 err = tcf_exts_validate(tp, tb, est, &e, &u32_ext_map); if (err < 0)  return err; err = -EINVAL;// 如果设置了U32_LINK参数 if (tb[TCA_U32_LINK-1]) {// 以LINK参数作为handle  u32 handle = *(u32*)RTA_DATA(tb[TCA_U32_LINK-1]);  struct tc_u_hnode *ht_down = NULL;// 如果handle的低20位为空, 错误  if (TC_U32_KEY(handle))   goto errout;  if (handle) {// handle非0的话, 根据此handle查找hnode准备作为knode的下层hnode   ht_down = u32_lookup_ht(ht->tp_c, handle);// 找不到, 返回错误   if (ht_down == NULL)    goto errout;   ht_down->refcnt++;  }  tcf_tree_lock(tp);// 设置knode节点的下层hnode,  ht_down = xchg(&n->ht_down, ht_down);  tcf_tree_unlock(tp);// 减少原来的下层hnode的引用数  if (ht_down)   ht_down->refcnt--; }// 如果设置了类别ID的话 if (tb[TCA_U32_CLASSID-1]) {// 设置返回结果的类别ID, 绑定过滤器  n->res.classid = *(u32*)RTA_DATA(tb[TCA_U32_CLASSID-1]);  tcf_bind_filter(tp, &n->res, base); }#ifdef CONFIG_NET_CLS_IND// 如果设置了网卡参数 if (tb[TCA_U32_INDEV-1]) {// 设置网卡  int err = tcf_change_indev(tp, n->indev, tb[TCA_U32_INDEV-1]);  if (err < 0)   goto errout; }#endif// TCF扩展部分的修改 tcf_exts_change(tp, &n->exts, &e); return 0;errout: tcf_exts_destroy(tp, &e); return err;}7.10.8 删除static int u32_delete(struct tcf_proto *tp, unsigned long arg){// 要删除的hnode struct tc_u_hnode *ht = (struct tc_u_hnode*)arg;// 为空的话直接返回成功 if (ht == NULL)  return 0;// handle低20位非空, 删除相应的knode if (TC_U32_KEY(ht->handle))  return u32_delete_key(tp, (struct tc_u_knode*)ht);// 否则如果是根节点的返回错误, 根节点不能删除 if (tp->root == ht)  return -EINVAL;// 释放hnode if (--ht->refcnt == 0)  u32_destroy_hnode(tp, ht); return 0;}// 删除knodestatic int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode* key){ struct tc_u_knode **kp;// hnode通过key的ht_up获取 struct tc_u_hnode *ht = key->ht_up; if (ht) {// 哈希号是key的handle的12~19位确定// 遍历链表  for (kp = &ht->ht[TC_U32_HASH(key->handle)]; *kp; kp = &(*kp)->next) {   if (*kp == key) {// key匹配, 找到    tcf_tree_lock(tp);// 从链表中断开    *kp = key->next;    tcf_tree_unlock(tp);// 释放key    u32_destroy_key(tp, key);    return 0;   }  } } BUG_TRAP(0); return 0;} 7.10.9 遍历static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg){ struct tc_u_common *tp_c = tp->data; struct tc_u_hnode *ht; struct tc_u_knode *n; unsigned h; if (arg->stop)  return; for (ht = tp_c->hlist; ht; ht = ht->next) {  if (ht->prio != tp->prio)   continue;  if (arg->count >= arg->skip) {   if (arg->fn(tp, (unsigned long)ht, arg) < 0) {    arg->stop = 1;    return;   }  }  arg->count++;  for (h = 0; h <= ht->divisor; h++) {   for (n = ht->ht[h]; n; n = n->next) {    if (arg->count < arg->skip) {     arg->count++;     continue;    }    if (arg->fn(tp, (unsigned long)n, arg) < 0) {     arg->stop = 1;     return;    }    arg->count++;   }  } }}7.10.10 输出static int u32_dump(struct tcf_proto *tp, unsigned long fh,       struct sk_buff *skb, struct tcmsg *t){// 输出knode节点(U32匹配规则)的参数 struct tc_u_knode *n = (struct tc_u_knode*)fh;// 缓冲区定位 unsigned char  *b = skb->tail; struct rtattr *rta;// 为空, 返回 if (n == NULL)  return skb->len;// 句柄 t->tcm_handle = n->handle; rta = (struct rtattr*)b;// 选项标志 RTA_PUT(skb, TCA_OPTIONS, 0, NULL);// U32_KEY是低20位 if (TC_U32_KEY(n->handle) == 0) {// 低20位为0, 表示是参数是hnode节点, 不是knode  struct tc_u_hnode *ht = (struct tc_u_hnode*)fh;  u32 divisor = ht->divisor+1;// 输出DIVISOR  RTA_PUT(skb, TCA_U32_DIVISOR, 4, &divisor); } else {// 低20位非0, 表示确实是knode// 输出选择子结构和匹配的key结构  RTA_PUT(skb, TCA_U32_SEL,   sizeof(n->sel) + n->sel.nkeys*sizeof(struct tc_u32_key),   &n->sel);// 输出上层hnode的ID值  if (n->ht_up) {   u32 htid = n->handle & 0xFFFFF000;   RTA_PUT(skb, TCA_U32_HASH, 4, &htid);  }// 输出类别ID  if (n->res.classid)   RTA_PUT(skb, TCA_U32_CLASSID, 4, &n->res.classid);// 输出下层hnode的handle值  if (n->ht_down)   RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle);#ifdef CONFIG_CLS_U32_MARK// 输出U32的mark值  if (n->mark.val || n->mark.mask)   RTA_PUT(skb, TCA_U32_MARK, sizeof(n->mark), &n->mark);#endif// 输出TCF扩展, 动作或策略  if (tcf_exts_dump(skb, &n->exts, &u32_ext_map) < 0)   goto rtattr_failure;#ifdef CONFIG_NET_CLS_IND// 输出网卡设备名称  if(strlen(n->indev))   RTA_PUT(skb, TCA_U32_INDEV, IFNAMSIZ, n->indev);#endif#ifdef CONFIG_CLS_U32_PERF  RTA_PUT(skb, TCA_U32_PCNT,  sizeof(struct tc_u32_pcnt) + n->sel.nkeys*sizeof(u64),   n->pf);#endif } rta->rta_len = skb->tail - b;// 如果是knode, 输出统计参数 if (TC_U32_KEY(n->handle))  if (tcf_exts_dump_stats(skb, &n->exts, &u32_ext_map) < 0)   goto rtattr_failure; return skb->len;rtattr_failure: skb_trim(skb, b - skb->data); return -1;}...... 待续 ......

读书人网 >UNIXLINUX

热点推荐