宏CONFIG_IP_MULTIPLE_TABLES表示路由策略,当定义了该宏,也即意味着内核配置了“路由策略”。产生的最大的不同就是内核可以使用多达256张FIB。其实,这256张FIB在内核中的表示是一个全局数组:
        struct fib_table *myfib_tables[RT_TABLE_MAX+1];
而宏RT_TABLE_MAX定义如下:
        enum rt_class_t
        {
            RT_TABLE_UNSPEC=0,
            RT_TABLE_DEFAULT=253,
            RT_TABLE_MAIN=254,
            RT_TABLE_LOCAL=255,
            __RT_TABLE_MAX
        };
        #define RT_TABLE_MAX (__RT_TABLE_MAX - 1)
    我们可以看到,虽然这张表多达256项,但枚举类型rt_class_t给出的表示最常用的也就三项,在系统初始化时,由内核配置生成的路由表只有RT_TABLE_MAIN,RT_TABLE_LOCAL两张。
    main表中存放的是路由类型为RTN_UNICAST的所有路由项,即网关或直接连接的路由。在myfib_add_ifaddr函数中是这样添加 main表项的:对于某个网络设备接口的一个IP地址,如果目的地址的网络号不是零网络(网络号与子网号全为零),并且它是primary地址,同时,它 不是D类地址(网络号与子网号占32位)。最后一个条件是:它不是一个环回地址(device上有flag IFF_LOOPBACK)。那么,就添加为main表项,如果是环回地址,则添加为local表的一个表项。
    在我们的系统中,有两个已开启的网络设备接口eth0和lo,eth0上配置的primary IP地址是172.16.48.2,所以,相应的,main表中就只有一项。为main表添加路由项的时候,该路由项的目的地址是子网内的所有主机(把主 机号部分字节清零),而对应于lo,在local表中也有一项,其类型为RTN_LOCAL(注:前一篇文章中的local表的hash 8中的路由项表述有误,类型应该是RTN_LOCAL,而不是RTN_BORADCAST)。
    而其它的路由项全部归入local表,主要是广播路由项和本地路由项。在我们的系统环境下,local表共有7项,每个网络设备接口占三项。分别是本地地 址(源跟目的地址一致),子网广播地址(主机号全为1),子网广播地址(主机号为零)。再加上一个lo的RTN_LOCAL项。
    现在我们再来看myfib_add_ifaddr函数的路由添加策略。对于一个传入的ip地址(结构struct in_ifaddr表示),如果它是secondary地址,首先要确保同一个网络设备接口上存在一个跟其同类型的primary地址(网络号与子网号完 全一致),因为,路由项的信息中的源地址全是primary的,secondary地址其实没有实际使用,它不会在路由表中产生路由项。然后,向 local表添加一项目的地址是它本身的,类型为RTN_LOCAL的路由项;如果该ip地址结构中存在广播地址,并且不是受限广播地址 (255.255.255.255),那么向local表添加一个广播路由项;然后,对符合加入main表的条件进行判断,如果符合,除了加入main 表,最后,如果不是D类地址,还要加入两个广播地址(其实,已经跟前面有重叠,很多情况下不会实际触发加入的动作,只要记住,一个ip地址项对应最多有两 个广播地址就可以了)。
    下面我们来看FIB的数据结构。一张FIB在内核中被表示为一个对象struct fib_table,之所以说它是一个对象,而不是一个结构,是因为它不仅仅是一组数据集合,它还包含了定义在该对象之上的方法,包括表项的插入,查找, 删除,刷新等等。下面是其定义:
        struct fib_table {
            unsigned char   tb_id;
            unsigned        tb_stamp;
            int (*tb_lookup)(struct fib_table *tb,
                    const struct flowi *flp, struct fib_result *res);
            int (*tb_insert)(struct fib_table *table, struct rtmsg *r,
                    struct kern_rta *rta, struct nlmsghdr *n,
                    struct netlink_skb_parms *req);
            int (*tb_delete)(struct fib_table *table, struct rtmsg *r,
                    struct kern_rta *rta, struct nlmsghdr *n,
                    struct netlink_skb_parms *req);
            int (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
                    struct netlink_callback *cb);
            int (*tb_flush)(struct fib_table *table);
            void (*tb_select_default)(struct fib_table *table,
                    const struct flowi *flp, struct fib_result *res);

unsigned char   tb_data[0];
        };
    这些成员函数我们在分析代码时都会提供其完整的实现,现在重点关注其数据成员。tb_id表明该表的用途(RT_TABLE_LOCAL, RT_TABLE_MAIN等),同时也表明它在全局数组myfib_tables中的位置(RT_TABLE_LOCAL==255, RT_TABLE_MAIN==254)。tb_data是一个很重要的数据成员,它包含了所在FIB的全部路由信息,可能会有点令人费>,因为它 的类型仅仅是一个unsigned char的数组而已,甚至更奇怪的是,它的长度是零,也就是说,根本不存在。看了下面的代码就可以明了:
    struct fib_table *tb = kmalloc( sizeof(struct fib_table)
                                + sizeof(struct fn_hash), GFP_KERNEL );
    memset( tb->tb_data, 0, sizeof(struct fn_hash) );
    所以,tb_data实际上是一个指向结构struct fn_hash的指针。下面是结构struct fn_hash的定义:
        struct fn_hash{
            struct fn_zone  *fn_zones[33];
            struct fn_zone  *fn_zone_list;
        };
    在解释struct fn_hash之前,先看一下strut fn_zone:
        struct fn_zone{
            struct fn_zone      *fz_next;
            struct hlist_head   *fz_hash;
            int         fz_nent;
            int         fz_divisor;
            u32         fz_hashmask;
            int         fz_order;
            u32         fz_mask;
        };
    这是一个区域,所有目的地址长度相同的路由项划入同一个区域,以链表的形式组织在fz_hash成员中,同时,fz_order记录目的地址长度, fz_mask为目的地址掩码(比如:fz_order为24,则fz_mask为ffffff)。比如,在我们的系统配置环境中,两个网络设备接口有共 七个路由项。其中的6项,其目的地址长度为6,归入同一个zone中,放在fz_hash成员中。成员fz_nent表明该zone中的路由项的数量,为 6。fz_hash其实是一个哈项数组,共有fz_divisor项(初始为16),fz_hashmask为数组的掩码(初始为f)。路由项以目的IP 地址为主键,定位到数组的某一项。
    对于ipv4来讲,目的地址不会超过32位,所以fz_order的取值范围是0-32。所以,struct fn_hash中fn_zones被定义为一个具有33项的数组,对应33个区域。在我们的配置系统中,fn_zones[32]和fn_zones [8]被用到了。同时,fn_zone_list把fn_zones中的已创建出来的zone按fz_order从大到小的顺序组织成一个链表。这些做法 都是出于效率的考虑。
    所以,fn_hash是一个组织路由域的数据结构,同一个域里的fn_zone通过fz_next组织成一个链表。
    同一个域中,所有的路由项组织在哈希表fz_hash中,一个路由项由结构struct fib_node表示。下面是该结构的定义:
        struct fib_node {
            struct hlist_node   fn_hash;
            struct list_head    fn_alias;
            u32         fn_key;
        };
    fn_hash用于在zone中组织链表,关于内核的一些基本数据结构,我们将专门进行分析,这里不再赘述。fn_key即目的地址IP, fn_alias指向一个结构体struct fib_alias的链表,下面是结构struct fib_alias的定义:
    struct fib_alias {
        struct list_head    fa_list;
        struct rcu_head rcu;
        struct fib_info     *fa_info;
        u8          fa_tos;
        u8          fa_type;
        u8          fa_scope;
        u8          fa_state;
    };
    fa_tos表示服务类型,一般为0,即一般服务;fa_type的值在我们的系统中为RTN_LOCAL, RTN_UNICAST和RTN_BORADCAST。fa_scope其实表示的是到目的地址的距离,对本地接收来说,就是 RT_SCOPE_HOST,对子网内广播和子网内其它地址来说,就是RT_SCOPE_LINK。fa_state只有在本地接收时,为 FA_S_ACCESSED,其它暂无定义。
    fa_info作为struct fib_alias的成员,含有更为详细的路由项信息。下面是其定义:
        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
        };
    fib_treeref表示本路由信息项在struct fib_table结构的整个树型结构中被引用的次数,而fib_clntref是另一个引用计数。fib_dead表示本项当前是否是活的。 fib_protocol表示该路由信息是通过什么途径建立起来的,其可能有取值有:
        #define RTPROT_UNSPEC   0
        #define RTPROT_REDIRECT 1   //该路由是由ICMP重定义安装的。
        #define RTPROT_KERNEL   2   //该路由是由内核安装的。
        #define RTPROT_BOOT 3   3   //该路由是在系统启动时安装的。
        #define RTPROT_STATIC   4   //该路由是由管理员安装的。
    除此之外,还有一些取值,不过是用于用户态的,我们当前在模块初始化过程中安装的路由都是RTPROT_KERNEL的。fib_prefsrc是我们的 local地址。最后,fib_nh是一个结构struct fib_nh的的数组,数组的大小由fib_nhs决定。该结构表示路由中的下一跳,下面是其定义:
        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;
        };
    关于这个结构体,我们在以后用到时再进行分析。

路由表(FIB)详解相关推荐

  1. Windows Route 路由表命令详解

    在本地 IP 路由表中显示和修改条目. 语法 route [-f] [-p] [Command [Destination] [mask Netmask] [Gateway] [metric Metri ...

  2. 18张图带你详解IP路由表七大要素:路由前缀、协议类型、优先级等

    IP 路由表 上次有写过一篇<20张图深度详解MAC地址表.ARP表.路由表 >的文章,里面有提到路由表,那么什么是IP路由.什么又是IP路由表呢? 路由:路由是网络中的基本概念,网络的基 ...

  3. ubuntu系统写路由指令_在Ubuntu中如何查看网络路由表详解,

    在Ubuntu中如何查看网络路由表详解, 什么是Linux中的路由和路由表? 路由的过程意味着IP包在网络上从一点传输到另一点.当你向某人发送电子邮件时,你实际上是在将一系列IP数据包或数据报从你的系 ...

  4. 思科ccna认证路由器路由表详解-ielab

    思科ccna认证路由器路由表详解-ielab互联网络将世界上各种类型的计算机以及其他终端设备连接在了一起,使得这些设备能够协同工作,使得能够进行相互通信.在IP网络中,数据遵循IP协议所定义的格式,设 ...

  5. 还觉得linux命令难吗,看这篇2w多字的linux命令详解,通俗易懂

    序言  本篇文章主要讲解了一些linux常用命令,主要讲解模式是,命令介绍.命令参数格式.命令参数.命令常用参数示例.由于linux命令较多,我还特意选了一些日常使用较为频繁的命令进行讲解,但还是免不 ...

  6. 【实战】MPLS单域通信过程详解

    一.背景说明 本文专门从路由传输与数据传输两个维度详细讲解传输的过程,上文实验拓扑如下图所示,为了简单起见,只已客户A为例(紫色)进行描述 二.路由传输层面 R5与R1之间通过ospf 1学习到5.5 ...

  7. 最全 VxLAN 知识详解

    什么是VXLAN VXLAN(Virtual eXtensible Local Area Network,虚拟扩展局域网),是由IETF定义的NVO3(Network Virtualization o ...

  8. linux中常用的60个命令及作用详解

    Linux 必学的 60 个命令 Linux 提供了大量的命令,利用它可以有效地完成大量的工作,如磁盘操作.文件存 取.目录操作.进程管理.文件权限设定等.所以,在 Linux 系统上工作离不开使用系 ...

  9. 华为模拟器ENSP router设备上display ip routing-table详解

    display ip routing-table 详解: 以下为环境拓扑 此处路由协议为OSPF协议 在AR1路由器上使用display ip routing-table命令后显示如下 对上述图片中的 ...

最新文章

  1. error: No resource identifier found for attribute 'showAsAction' in package 'com.ymeng.项目名字'
  2. linux c remove 删除文件或目录函数
  3. 2d绘制 c# dx_C# DX 编程
  4. Apache基础安装(一)
  5. String常用函数
  6. 远程协同TeamViewer
  7. SitePoint播客#115:直播在WordCamp Raleigh第2部分
  8. bootstrap-fileinput插件获取图片文件并展示,不进行上传
  9. 打开IIS管理器命令cmd
  10. IP属地靠谱吗?或是一把双刃剑
  11. dismiss和remove_你真的了解iOS中控制器的present和dismiss吗?
  12. 电脑卡顿反应慢怎么办?这几招教给你!
  13. 亚马逊 kindle ebook 大合集资源多真的好吗?
  14. settimeout一定要清除么?
  15. GPS时钟源(GPS时间同步服务器)的概述
  16. MATLAB聚类分析(Cluster Analysis)
  17. 计算机专业相关的职业技术证书有哪些,你知道吗?
  18. 雾霾环保主题动态网站设计作业
  19. 公众号接口消息推送+VB+WebService实战
  20. C++鼠标连点小程序

热门文章

  1. linux根据进程的运行路径,停止进程
  2. 解决seaborn绘制热力图使用科学记数法
  3. BlackArch 创建软件包
  4. 【HBase】学习笔记
  5. SQL Server 将某一列的值拼接成字符串
  6. 《C++ Primer Plus》16.2 智能指针模板类
  7. WordPress程序伪静态规则(Nginx/Apache)及二级目录规则
  8. Hibernate框架之HQL查询与Criteria 查询的区别
  9. 查看一个进程对应的端口号
  10. mysql创建数据库与表_PHP MySQL 创建数据库和表 之 Create