Linux 内核路由发现过程

    简单来讲fn_hash_lookup这个函数通过在一张路由表(struct fib_table)中,根据查询路由的目的IP地址(key)在其路由哈希表(struct fn_hash)中找到一个路由域(struct fn_zone),并在路由域中匹配到一个key相等的路由节点(struct fib_node),取其路由别名(struct fib_alias)和路由信息(struct fib_info),生成一个路由查询结果(struct fib_result)。 路由查询结果还不能直接供发送IP数据报使用,接下来,还必须根据这个查询结果生成一个路由目的入口(dst_entry),根据目的入口才可以发送IP数据报,目的入口用结构体struct dst_entry表示,在实际使用时,还在它的外面包装了一层,形成一个结构体struct rtable。

struct rtable的定义如下:
    struct rtable
    {
        union{
            struct dst_entry    dst;
            struct rtable       *rt_next;
        }u;
        struct in_device    *idev;
        unsigned    rt_flags;
        __u16       rt_type;
        __u16       rt_multipath_alg;
        __u32       rt_dst;
        __u32       rt_src;
        int         rt_iif;
        __u32           rt_gateway;
        struct flowi    fl;
        __u32           rt_spec_dst;
        struct inet_peer    *peer;
    };
rt_flags是一组标志位,按目的入口查询的执行顺序:如果路由使用本地环回接口,则rt_flags上加标志RTCF_LOCAL,如果路由结果类型是广播,则加标志RTCF_BROADCAST和RTCF_LOCAL,如果结果是组播,则加标志RTCF_MULTICAST和RTCF_LOCAL,该标志最终决定了目的入口使用哪一个IP数据报输入函数和输出函数,如果是RTCF_LOCAL,则使用输入函数ip_local_deliver,如果是RTCF_BROADCAST或RTCF_MULTICAST,并且带有RTCF_LOCAL标志,并且输出设备不是环回接口设备,则使用输出函数ip_mc_output,否则使用输出函数ip_output。
    rt_type是路由类型,如果路由是LOOPBACK,则置类型为RTN_LOCAL,单播路由类型为RTN_UNICAST,如果目的地址为0xFFFFFFFF,则路由类型为RTN_BROADCAST,如果目的地址是组播地址,则路由类型为RTN_MULTICAST。rt_type跟rt_flags关系比较密切。
    rt_multipath_alg跟路由多路径相关,暂时略过。rt_dst是路由的目的地址,rt_src是路由的源地址,rt_iif是路由的输入设备接口的索引号。rt_gateway是路由网关的IP地址。
    在试验环境中,网络设备接口mylo的IP地址是127.10.0.1,它在内核中的表示是struct net_device myloopback_dev,测试程序往IP地址127.10.0.1发送DUMMY协议的数据报,协议栈为其生成的路由目的入口如下:
    the dst_entry:
        the dev name: mylo
        the error: 0
        the obsolete: 0
        the flag: DST_HOST
        expires: 0, now: 110343
        header len: 0
    rt_flag: RTCF_LOCAL
    rt_type: RTN_LOCAL
    rt_dst: 127.10.0.1
    rt_src: 127.10.0.1
    rt_iif: 4
    rt_gateway: 127.10.0.1
    rt_spec_dst: 127.10.0.1
    试验环境中的网络设备接口eth0的IP地址是172.16.48.2,测试程序往该IP地址所在子网内的IP地址172.16.48.1发送DUMMY协议的数据报,协议栈为其生成的路由目的入口如下:
    the dst_entry:
        the dev name: eth0
        the error: 0
        the obsolete: 0
        the flag: DST_HOST
        expires: 0, now: 850858
        header len: 0
    rt_flag: 0
    rt_type: RTN_UNICAST
    rt_dst: 172.16.48.1
    rt_src: 172.16.48.2
    rt_iif: 2
    rt_gateway: 172.16.48.1
    rt_spec_dst: 172.16.48.2

查找到路由后,会调用 arp_bind_neighbour 绑定一个邻居项

int arp_bind_neighbour(struct dst_entry *dst)

{

         struct net_device *dev = dst->dev;

         struct neighbour *n = dst->neighbour;

 

         if (dev == NULL)

                return -EINVAL;

      

         // 如果这个邻居不存在,则执行 __neigh_lookup_errno

 

         if (n == NULL) {

                __be32 nexthop = ((struct rtable*)dst)->rt_gateway;

                if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))

                       nexthop = 0;

                n = __neigh_lookup_errno(

如果至时找到了路由,则根据路由信息分配个dst_entry,并调用arp_bind_neighbour为之绑定邻居output指针赋值为ip_output

转到执行ip_output

         //ATM 网络和以太网络调用了不同的 neigh_table, 作为以太网络将调用 &arp_tbl 作为 neigh_table 的入口

             #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)

                      dev->type == ARPHRD_ATM ? clip_tbl_hook :

              #endif

                      &arp_tbl, &nexthop, dev);

                if (IS_ERR(n))

                       return PTR_ERR(n);

                dst->neighbour = n;

         }

         return 0;

}

总之:如果至时找到了路由,则根据路由信息分配个dst_entry,并调用arp_bind_neighbour为之绑定邻居output指针赋值为ip_output

转到执行ip_output,现在就转至邻居项的出口函数了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值