kernel IPv6 路由学习笔记(1)原理.

内核版本:v3.0
IPv6 route tree 原理.
IPv6路由采用二叉树的形式进行存储, 查找任意路由最多需要128次(说法不太严格,不包含从底部的反向查)比较,
因此其算法复杂度为常数,因此IPv6里没有像IPv4那样的cache。

树的节点: fib6_node
fib6_node 代表一条路由, 如XXXX:YYYY:TTTT::0/n
 53 struct fib6_node {
 54         struct fib6_node        *parent;
 55         struct fib6_node        *left;
 56         struct fib6_node        *right;
 60         struct rt6_info         *leaf;
...
 62         __u16                   fn_bit;         /* bit key */
 66 };

每个节点有:
指针parent: 指向父节点。
左右两个孩子指针(left,right)。

fn_bit:掩码长度,
leaf指针: 指向该路由的下一跳。下一跳可能有一个, 也可能有多个。
    如果有多个下一跳就按照metric值递增的顺序组成一个单向链表, leaf指向链表头。
网络地址则保存在leaf指针指向的节点(rt6_info)中。

 86 struct rt6_info {
...
108         struct rt6key                   rt6i_src;
123 };

树的概述:
1. 随着树的深度增加,其掩码长度(fn_bit)也在增加。
    树的深度每增加1, 掩码长度fn_bit至少增加n(n>=1).
2. 子节点一定是父节点的子网段。(子节点的代表的网段一定是父节点代表的网段的子网段)。
3. fib6_node只是保存了掩码长度fn_bit(和subtree),具体的下一跳信息存放在leaf所指向的链表的节点里。

路由查找:
查找目的地址IPa,
从根节点开始遍历:
    fib6_node*p =root_node;
    while(p!=NULL)
    {
        获取当前节点p(fib6_node*)的fn_bit和网络地址IP_XXXX(从p->leaf里取得)
        如果当前地址属于ip_XXXX/fn_bit这个网段。GOOD! Got it.

        否则fib6_node转向下一个节点。

        下一个节点是right还是left?
        根据IPa的第fn_bit位的值是0(right) 还是1(left)决定.
        注:这里的第fn_bit位是从1开始的序列而不是0。
        即: 没有掩码后面的第一位bit_X

        if bit_x == 1
            p= p->right;
        else
            p=p->left;
    }
   
IPa:XXXXXXXXXXXXXXXXXXXX
       ^
                 ^ 
                        ^--->
相当于目的地IPa地址下有个浮标,随着遍历深度的增加。浮标不停的往后移动。
直到找到相应的路由为止,或者浮标到末尾, 路由查找失败。

本文描述的只是原理。
1. 在实现中为了寻找到最佳路由,遍历时是首先沉到树的最低部的节点,
然后再向树根方向反推。
2. 为了实现按源地址作路由,每个fib6_node下还有个指向子树的指针subtree。

    子树的实现几乎没有变化只是对源IP地址进行类似的操作。

在增加或者删除一个节点的时候都保持这这个原则。即上一层的节点比下一层的节点的掩码长度要大(至少大1)。

如果增加的节点a和原有的节点b掩码长度相同。则还要临时引入一个新的节点p。 a 和b作为p的左右孩子。

p的掩码长度为a和b的前缀相同部分的长度

你可能感兴趣的:(linux网络开发)