IPv6路由节点查找
路由表查找函数首先调用fib6_node_lookup查找路由节点,由指定路由表的根节点开始,根据数据流的目的和源地址进行。
static struct fib6_node *fib6_lookup_1(struct fib6_node *root, struct lookup_args *args) { struct fib6_node *fn; __be32 dir; if (unlikely(args->offset == 0)) return NULL; /* * Descend on a tree 以下遍历由根节点开始,如果遍历节点的前缀长度,在所查找地址中对应的位为1,向右子树继续查找, 如果为零,向左子树继续查找。一直到节点为空为止。 */ fn = root; for (;;) { struct fib6_node *next; dir = addr_bit_set(args->addr, fn->fn_bit); next = dir ? fn->right : fn->left; if (next) { fn = next; continue; } break; } /* 如果以上找到了匹配的节点,检查此节点是否具有合法的路由信息(RTN_RTINFO),并且其叶子节点存在,按照叶子节点中保存的地址和前缀长度, 与待查找地址进行比较(ipv6_prefix_equal),如果相等,即为要找的路由节点。 */ while (fn) { if (FIB6_SUBTREE(fn) || fn->fn_flags & RTN_RTINFO) { struct rt6key *key; key = (struct rt6key *) ((u8 *) fn->leaf + args->offset); if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) { #ifdef CONFIG_IPV6_SUBTREES /* 否则,检查节点树的父节点,向树根方向(backtrack),此方向节点的前缀长度(fn_bit)在减小。此函数遵循LPM最长匹配算法, 如果存在最长匹配的路由节点,优先选择。 */ if (fn->subtree) { struct fib6_node *sfn; sfn = fib6_lookup_1(fn->subtree, args + 1); if (!sfn) goto backtrack; fn = sfn; } #endif if (fn->fn_flags & RTN_RTINFO) return fn; } } #ifdef CONFIG_IPV6_SUBTREES backtrack: #endif if (fn->fn_flags & RTN_ROOT) break; fn = fn->parent; } return NULL; }
static __be32 addr_bit_set(const void *token, int fn_bit) {//t确定地址中的第fn_bit位的值 const __be32 *addr = token; /* * Here, * 1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f) * is optimized version of * htonl(1 << ((~fn_bit)&0x1F)) * See include/asm-generic/bitops/le.h. 首先将IPv6地址分成4个32位的数组,由运算[fn_bit>>5]确定数组的索引值; 其次,确定fn_bit在此32位中的具体位置,此值不能大于32(由0x1f与操作保证), 由于fn_bit是由高位向低位表示的,需要取反操作将此顺序反过来。 */ return (__force __be32)(1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)) & addr[fn_bit >> 5]; }
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子

浙公网安备 33010602011771号