linux网络协议栈(五)网络层 (4)路由表

5.3.3、路由表:

5.3.3.1、路由表的组成结构:

5.3.3.1.1、路由表基本组成:

路由表是一个很庞大的组织,导致关于它的相关操作也非常繁琐,所以必须深入理解路由表的组成结构。注意,基本上作为路由器网关编译的linux内核,默认都会支持策略路由,所以本文也已支持策略路由的方式描述。

Linux内核可以有最多256个路由表,一般情况下如2.10方案是2个路由表,一个用于发送给本机一个用于转发;

每个路由表首先根据子网掩码长度划分,所谓子网掩码长度就是子网掩码的二进制值中1的个数,子网掩码是多少和局域网划分相关,后面会举个例子,根据子网掩码这个32bit数可以划分为0-32共33个区,这是每个路由表的第一层划分,即按子网掩码长度划分为33个区(zone);

每个区还可以根据IP地址及其所处的子网划分为不同的网段,比如IP地址10.1.1.10/24,即掩码长度为24,对应的子网掩码为255.255.255.0,那么它的网段就是10.1.1网段,这样一来每个区可以被划分为不同的网段(node),这是对每个路由表的第二次划分;

这时就可以加入路由条目(alias)了,但还需要划分,当每个路由条目要加在路由表A的B区的C网段时,在每个网段,路由条目是按照tos大小依递增顺序排列,如果tos相同则按路由条目优先级(路由条目字段之一)的递增顺序再寻找位置,如果依然相同则把旧条目删除;注意这一步依然是一种划分,是按照tos和路由条目优先级的划分;

事实上上一步的路由条目依然是路由条目实质内容(info)的抽象,实质内容包括路由协议类型、路由标志、路由优先级、首选源IP、跃点设置、下一跳(出接口、网关、下一跳范围等,对于多路径路由会有多个下一跳),这是最终的路由条目了,强调一点一定理解这里的实质内容(info)才是真正有实质意义的路由信息,前面的一级一级的划分都是为了提高检索效率,先后根据子网掩码长度、网段、tos和路由条目优先级划分路由表,下图仅描述正常情况下路由表条目的创建,可以直观的感受下路由表的组成结构:


从数据结构来看,路由表的划分如下:


上面描述了路由表之下的组成关系,那么路由表自身是怎么回事?前面已提到在不考虑策略路由的情况下,linux内核会默认创建两个路由表,一个用于给本机,一个用于转发,若考虑策略路由,则会由用户创建路由表,不过路由表个数是编译时确定的(由宏FIB_TABLE_HASHSZ确定),最大可为256个,一般情况下为2个,2.10方案就是2个;对路由表的操作首先要明确是操作哪一个路由表。

5.3.3.1.2、路由条目详解:
了解了路由表基本的结构组成,现在要着重分析下路由表条目都包括什么内容,也就是实质内容,路由条目实际由用户配置,典型如zebra工具,通过把要配置的内容通过netlink告诉内核,涉及内容包括目的IP、下一跳网关、出接口、tos、路由协议、路由表id、路由条目优先级、路由条目控制标志、路由条目范围、多路径路由内容,在初始化时会加载内核的路由netlink的路由表操作接口,分别是添加一个路由条目(RTM_NEWROUTE)、删除一个路由条目(RTM_DELROUTE)、显示当前路由条目(RTM_GETROUTE),如下图:


典型观察路由条目的添加,首先解析用户的配置值,用户关于配置路由条目的数据结构为struct rtmsg,这是非常重要的一个数据结构,它里边就是路由条目的实质内容,在busybox和zebra工具中看到对它的使用,在内核中首先要解析它,并把它翻译成内核用于配置路由条目实质内容的数据结构struct fib_config,这些功能由函数rtm_to_fib_config完成,如下图:


现在就由用户配置值获知了要配置的包括目的IP、下一跳网关、出接口、tos、路由协议、路由表id、路由条目优先级、路由条目控制标志、路由条目范围、多路径路由内容的全部内容,下一步就是将该条目加入对应的路由表,在支持策略路由情况下,内核对路由表的操作包括定位、创建(fib_get_table函数、fib_new_table函数),这是因为用户有可能会新创建路由表,所以这里首先由获知的所操作的路由表确定内核里的路由表,如果存在定位即可,否则需创建,如下图:


接下来就是在这个路由表(tb)中加入新的路由条目了,这里就需要详细的描述下路由表自身的结构,它由结构体struct fib_table描述,它包括两方面内容,一方面是用于内核对它的操作,包括查找路由条目、插入路由条目、删除路由条目、显示(获取)路由条目、清除全部路由条目等等,路由表id范围是0-255,可标识最多的256个路由表,路由表和路由表之间以hash表链接;另一方面是它的路由条目内容(tb_data),实际上指向它底下33个区(zone)中第一个区,事实上相当于对于它底下的区(zone)的封装,如下图:

linux网络协议栈(五)网络层 (4)路由表_第1张图片

需要注意的是,路由条目在linux中可以有两种方式存储,一种是通过hash表的方式,另一种是trie方式,后者适用于特大型路由器效率更高,一般情况都使用hash表方式。

Linux内核对于插入路由条目的方法即路由表的tb_insert方法为函数fn_hash_insert,它首先根据用户配置的目的IP掩码长度(就是X.X.X.X/Y中的Y)确定区(zone),区(zone)在内核中由数据结构struct fn_zone模式,对于它无需细究,在这里首先要获取这个区,判断路由表的这个区是否创建过,如果没有需创建,如下图:


获得区之后(fz),再确定网段,一个区只能标识子网掩码长度,之下可以有很多不同的网段,如目的IP为3.4.5.6/24,那么网段值为3.4.5,再如目的IP为3.4.6.7/24,那么网段值为3.4.6,注意网段值是一个无符号整数,区(fz)的掩码和目的IP做与运算后的结果即网段,如下图:


定位到网段后,这里要先停下来,把实质内容的内核配置结构体struct fib_config翻译成路由子系统的实质内容描述结构体struct fib_info,由前面已经知道涉及内容包括路由协议类型、路由标志、路由优先级、首选源IP、跃点设置、下一跳(出接口、下一跳网关、下一跳范围等),如下图:


下一跳由结构体struct fib_nh描述,重点是下一跳网关、本地出接口、下一跳范围,还有一些路由算法相关内容可暂不关注,如下图:

linux网络协议栈(五)网络层 (4)路由表_第2张图片

可见对于路由表,其路由条目真正关注的实质内容是出接口、下一跳网关、下一跳范围,因为它们决定了报文应该从哪个接口出去并且发向何方;

这里需要注意的是多路径路由的情况,所谓多路径路由是指这个路由条目中,含有多个去向的选择(fib_nhs值大于1),每个去向的出接口、下一跳网关、跃点是可以不同的,其他字段相同;

多路径路由的意义,实现了报文在同一个路由表的同一个路由条目下,可以有不止一种路由结果,可以有不同的出接口、下一跳网关、下一跳范围;

一定注意多路径路由和策略路由的区别,策略路由给予报文走向不同路由表的相关条目的选择,但多路径路由是在同一路由表的同一路由条目中可以有不同的路由结果,这是本质上的不同。

至此,涵盖下一跳的路由条目实质内存fib_info翻译完毕,涉及内容包括路由协议类型、路由标志、路由优先级、首选源IP、跃点设置、下一跳(出接口、下一跳网关、下一跳范围等),接下来依据之前计算而得的网段值确定该网段(fib_node)是否创建,如下图:


如果网段已存在,则进一步查看该网段下的路由条目(fib_alias)创建情况,由之前已知网段下的每个路由条目(fib_alias)按tos字段递增排列,如tos相同则按照路由条目优先级(fib_priority)字段递增排列,若也相同则删除旧条目;如果还没有创建路由条目则必须创建路由条目(fib_alias);

如果网段不存在,则说明之前一直没有过该网段的路由条目内容,所以网段下也不存在任何路由条目,同样需要创建,网段和路由条目的创建都是由slab分配,在初始化时就已把它们各自的结构体大小注册进slab分配器;创建后分别插入各自的上一层结构体,需要注意对于路由条目fib_alias,它不仅要挂接路由实质内容fib_info(包含下一跳内容),自身也记录路由条目的tos、路由类型、下一跳范围。

至此,完成了一个路由条目在一个路由表的注册,每个路由表根据子网掩码长度划分为33个区(fz_zone),每个区(fz_zone)可以有很多的网段(fib_node),每个网段下有一个个的路由条目(fib_alias),每个路由条目(fib_alias)包含了路由实质内容(fib_info),路由实质内容(fib_info)中记录了路由条目的tos、路由类型、下一跳范围和下一跳(fib_nh),下一跳(fib_nh)是路由实质内容的核心,记录了出接口、下一跳网关、下一跳范围,需要注意不同的路由条目(fib_alias)可以共用一个路由实质内容fib_info),如路由条目(fib_alias)的tos不同,但它们都指向同一个路由实质内容fib_info);下图是一个细致的描述图:



你可能感兴趣的:(路由表,下一跳,路由表分级,fib_table,路由条目配置)