在协议栈的FIB(Forwarding Information Base)模块中,结构体struct fib_info是一个很基本的单位,它表示一个路由信息,一个路由信息可以被多个路由共享。下面是其完整的定义:
    struct fib_info {
        struct hlist_node   fib_hash;
        struct hlist_node   fib_lhash;
        int             fib_treeref;
        atomic_t        fib_clntref;
        int             fib_dead;
        unsigned        fib_flags;
        int             fib_protocol;
        u32             fib_prefsrc;
        u32             fib_priority;
        u32             fib_metrics[RTAX_MAX];
#define fib_mtu fib_metrics[RTAX_MTU-1]
#define fib_window fib_metrics[RTAX_WINDOW-1]
#define fib_rtt fib_metrics[RTAX_RTT-1]
#define fib_advmss fib_metrics[RTAX_ADVMSS-1]
        int             fib_nhs;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
        int             fib_power;
#endif
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
        u32             fib_mp_alg;
#endif
        struct fib_nh   fib_nh[0];
#define fib_dev         fib_nh[0].nh_dev
    };
    现在就结合模块加载并初始化过程中为一个本地网络接口生成路由信息的实例,分析路由信息的创建过程。本地主机的网络设备接口eth0上配置的ip地址是 172.16.48.2。协议栈的fib_add_ifaddr函数会在模块被加载的时候主动往FIB表中插入五条路由相关信息,下面是一个完整列表:
    类型                            目的地址        地址长度
    RTN_LOCAL             172.16.48.2         32
    RTN_BROADCAST  172.16.48.255       32
    RTN_UNICAST         172.16.48.0         24
    RTN_BROADCAST   172.16.48.0         32
    RTN_BROADCAST   172.16.48.255       32
    其中第二条跟第五条完全相同,所以实际插入的是四条。第一条是本地接收,第二条是本地接收的广播,第三条是子网内的直接路由或者网关路由。第四条是子网广播。
        首先看第一条会产生怎么样的路由信息struct fib_info。在这之前,fib_magic函数要为它产生三个结构体信息,用于传递给路由信息创建函数:
    struct nlmsghdr
    {
        __u32       nlmsg_len = sizeof( struct nlmsghdr + struct rtmsg );
        __u16       nlmsg_type = RTM_NEWROUTE;
        __u16       nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
        __u32       nlmsg_seq = 0;
        __u32       nlmsg_pid = 0;
    };
    这是一个消息头结构,表示本条消息的内容是创建一个新的路由(RTM_NEWROUTE),这是一个请求消息(NLM_F_REQUEST),如果新的路 由不存在,则要求创建(NLM_F_CREATE),并且新创建的路由加到列表尾部(NLM_F_APPEND)。由于这是内核发出的请求命令,所以序列 号跟进程号都为0。
    struct rtmsg
    {
        unsigned char       rtm_family;
        unsigned char       rtm_dst_len = 32;
        unsigned char       rtm_src_len;
        unsigned char       rtm_tos;
        unsigned char       rtm_table = RT_TABLE_LOCAL;
        unsigned char       rtm_protocol = RTPROT_KERNEL;
        unsigned char       rtm_scope = RT_SCOPE_HOST;
        unsigned char       rtm_type = RTN_LOCAL;
        unsigned                rtm_flags;
    };
    这是消息体,表示这一条由内核发起的消息(RTPROT_KERNEL),因为路由类型是本地接收(RTN_LOCAL),所以操作对象是本地路由表 (RT_TABLE_LOCAL),同时目的地址也就是本地地址(RT_SCOPE_HOST),目的地址长度是32位。
    struct kern_rta {
        void        *rta_dst = 172.16.48.2;
        void        *rta_src;
        int         *rta_iif;
        int         *rta_oif = indexof(eth0);
        void        *rta_gw;
        u32         *rta_priority;
        void        *rta_prefsrc = 172.16.48.2  //接口上的primary地址。
        struct rtattr   *rta_mx;
        struct rtattr   *rta_mp;
        unsigned char   *rta_protoinfo;
        u32             *rta_flow;
        struct rta_cacheinfo    *rta_ci;
        struct rta_session  *rta_sess;
        u32                 *rta_mp_alg;
    };
    该结构体提供该路由的属性,即本地地址,目的地址,输出接口。
    函数fib_create_info用于创建路由信息,它首先要对请求信息的scope的有效性作一个判断,关于scope,内核定义了如下的枚举量:
    enum rt_scope_t
    {
        RT_SCOPE_UNIVERSE=0,
        /* User defined values  */
        RT_SCOPE_SITE=200,
        RT_SCOPE_LINK=253,
        RT_SCOPE_HOST=254,
        RT_SCOPE_NOWHERE=255
    };
    当前路由请求信息的type为RTN_LOCAL,它对应的scope应该是RT_SCOPE_HOST,如果scope小于这个值,则错误。
    新创建的struct fib_info结构都会维护在一个哈希表struct hlist_head *fib_info_hash中备用。该哈项表的长度由变量fib_hash_size记录,变量fib_info_cnt记录哈希表中当前的路由信息数 量。函数fib_create_info总是确保fib_hash_size>fib_info_cnt,如果不够了,就把哈希表扩大一倍。
    结构体struct fib_info的最后一个成员是struct fib_nh fib_nh[0],它是一个路由的下一跳信息,目前还没看到它的实际用途。缺省struct fib_nh的数量为1,如果不为1,则由struct kern_rta的rta_mp传入具体信息。下面是该结构体的定义:
    struct fib_nh {
        struct net_device   *nh_dev;
        struct hlist_node   nh_hash;
        struct fib_info     *nh_parent;
        unsigned            nh_flags;
        unsigned char       nh_scope;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
        int                 nh_weight;
        int                 nh_power;
#endif
#ifdef CONFIG_NET_CLS_ROUTE
        __u32           nh_tclassid;
#endif
        int             nh_oif;
        u32             nh_gw;
    };
    新创建的struct fib_info需要进行部分值的初始化,下面是被初始化的内容:
    struct fib_info{
        .fib_protocol   = RTPROT_KERNEL;
        .fib_nhs        = 1;
        .fib_flags      = 0;
        .fib_prefsrc    = 172.16.48.2;
        struct fib_nh{
            .nh_oif     = indexof(eth0);
            .nh_flags   = 0;
            .nh_weight  = 1;
            .nh_scope   = RT_SCOPE_NOWHERE;
            .nh_dev     = eth0;
        }
    }
    由于创建完成的struct fib_info,还要拿到哈项表fib_info_hash中去匹配,因为有可能哈希表中已存在同样的一个路由信息了,如果存在,则要删掉刚刚创建的 struct fib_info,把表中已有的那项的成员fib_treeref加1即可。判断两个路由信息相同的依据 是:fib_protocol,fib_prefsrc,fib_priority,fib_metrics,fib_flags全部相同,并且 fib_nh的数量和内容全部相同。
    如果哈希表中还不存在,则把新创建的fib_info添加到哈项表中。并且,如果成员fib_prefsrc不为0,则同时把fib_info添加到哈希 表fib_info_laddrhash中,fib_info_laddrhash是一个跟fib_info_hash同步维护的哈希表。
    最后,还要把fib_info的所有struct fib_nh成员放到哈希表fib_info_devhash中,nh_dev相同的放到同一项中。
    同理,第二项创建的struct fib_info如下:
    struct fib_info{
        .fib_protocol   = RTPROT_KERNEL;
        .fib_nhs        = 1;
        .fib_flags      = 0;
        .fib_prefsrc    = 172.16.48.2;
        struct fib_nh{
            .nh_oif     = indexof(eth0);
            .nh_flags   = 0;
            .nh_weight  = 1;
            .nh_scope   = RT_SCOPE_HOST;
            .nh_dev     = eth0;
        }
    }
    依次类推,第三,第四项创建的struct fib_info与第二项完全相同,所以,最后,为网络设备接口eth0创建的struct fib_info共有两个,第一个的fib_treeref为1,第二个为3。

创建struct fib_info相关推荐

  1. 创建struct fib_info函数分析

    在协议栈的FIB(Forwarding Information Base)模块中,结构体struct fib_info是一个很基本的单位,它表示一个路由信息,一个路由信息可以被多个路由共享.下面是其完 ...

  2. 创建一个路由节点struct fib_node

    在为一个网络设备接口的IP地址创建四个路由项(本地接收,子网广播,子网单播,本地接收的广播)的时候,需要为每个路由项创建一个路由节点,struct fib_node结构体表示一个路由节点,下面是其定义 ...

  3. struct timeval结构体

    struct timeval结构体在time.h中的定义为: struct timeval { __time_t tv_sec;        /* Seconds. */ __suseconds_t ...

  4. linux sock结构体,struct socket结构体详解

    在内核中为什么要有struct socket结构体呢? struct socket结构体的作用是什么? 下面这个图,我觉得可以回答以上两个问题.  由这个图可知,内核中的进程可以通过使用struct ...

  5. linux内核字符设备文件的自动创建

    手动创建:mknod   自动创建设备文件的步骤:   1.保证根文件系统支持mdev可执行程序     mdev将来是创建设备文件的真正的人!     which is mdev //查看mdev的 ...

  6. C#中struct和class的区别详解

    本文详细分析了C#中struct和class的区别,对于C#初学者来说是有必要加以了解并掌握的. 简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上.class是引用类型,创建 ...

  7. C语言 结构体 struct Cat cat1;

    引入 使用传统技术解决 需要定义多个变量或数组 结构体与结构体变量的关系示意图 类似Java类中的对象(结构体)与属性(结构体变量) 一切物体都可以看作对象(结构体) 补充:C语言数据类型 简单使用案 ...

  8. C# struct 装箱拆箱例子

    值类型:拆箱.装箱 struct是值类型 struct和class的区别 类是引用类型,struct是值类型 在托管堆上创建类的实例,在栈上创建struct实例 类实例的赋值,赋的是引用地址,stru ...

  9. c#中struct和class的区别

    简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上.class是引用类型,创建一个class类型实例被分配在托管堆上.但struct和class的区别远不止这么简单.本篇主要包 ...

最新文章

  1. ['1','2','3'].map(parseInt)
  2. java基础笔试_java基础笔试题
  3. 几种方法来实现scp拷贝时无需输入密码
  4. html将边框向下移的代码,设置margin-left实现div右移
  5. 开发指南专题十八:Navicat 数据库转换操作
  6. linux的日志系统,Linux上的日志系统
  7. PRML-系列二之2.2
  8. Windows下打开Url 代码封装 C++
  9. 如何抓住软件测试的主线及确定主要功能?
  10. android 点击通知栏打开activity,Android实现点击通知栏后,先启动应用再打开目标Activity...
  11. Pandas基础学习
  12. 计算机用户密码最长使用期限,电脑Win10系统强制用户定期更新密码的方法
  13. 【禁止重复造轮子Day01】省市级连的递归
  14. [转]Windows服务“允许服务与桌面交互”的使用和修改方法
  15. 华三模拟器:IPV6路由实验
  16. Excel如何将文本中间的数值提取出来
  17. python十六进制转换成二进制_python - 将十六进制转换为二进制
  18. 黑帽SEO的常见操作手法解析
  19. 高通平台Linux kernel死机解题心得-trace32的使用
  20. 实现页面刷新(全局刷新)

热门文章

  1. maven导出Java方法_eclipse导出maven工程的可执行jar包
  2. 小学教师计算机说课,浙江温州小学计算机教师资格认证说课稿
  3. MATLAB在运筹学背包问题的应用,运筹学论文之二维背包问题.docx
  4. redis并发锁 thinkphp5_资深架构师经典总结:Redis分布式锁实现理解
  5. prim算法_图的生成树之最小生成树(Prim)
  6. 红旗linux怎么更新,红旗linux7.0下自动更新firefox
  7. Leetcode 118 杨辉三角
  8. PCIe的事务传输层的处理(TLP)
  9. CF788E:New task
  10. getParameter