路由表基本概念
1、路由是由多个不同的数据结构的组合来描述的,每个数据结构代表路由信息的不同部分。例如,一个fib_node对应一个单独的子网,一个fib_alias对应一条路由。这样做的原因是只需通过部分字段可以区分多条路由。路由子系统不是维护一个庞大而臃肿的结构而是将路由分散为多个片段,这样更容易在相似的路由间共享通用的信息,因而就可以分离出不同的函数,并在这些函数之间定义更加清晰的接口。
数据结构之间的关系如下所示:fib_table结构包含一个由33个指针组成的向量,每个指针对应一个网络掩码并指向一个类型为fn_zone的数据结构。fn_zone结构将路由组成hash表,每个单独的子网对应一个fib_node实例,用变量fn_key识别,例如对于子网10.1.1.0/24,fn_key为10.1.1。目的子网相同的不同路由共享同一个fib_node,每条路由都有自己的fib_alias结构,而每个fib_alias实例都与一个fib_info结构相关联,该结构中保存着真实路由信息。需要注意的是,fib_alias和fib_info之间不是一对一的关联,多个fib_alias结构可能共享同一个fib_info结构。例如,有五条到不同目的网络的路由碰巧使用同一个下一跳网关,那么对所有这五条路由来说下一跳信息都是相同的,因而就可以共享相同的下一跳信息。所以这种情况下就有五个fib_node结构和五个fib_alias结构,但只有一个fib_info结构。
每个fib_info结构可以包含一个或多个fib_nh结构,每个fib_nh结构表示下一跳路由器,一个下一跳路由器的信息中包括通过哪个设备能到达该路由器。
2、向路由表中插入一条新的路由是通过fn_hash_insert函数实现的,事实上,调用此函数的还有处理路由的尾部追加(append)、首部追加(prepend)、改变(change)和替换(replace)操作,这些不同的操作是由传入的NLM_F_XXX标识参数来区分的。路由的删除由fn_hash_delete完成,删除路由要比添加路由简单,因为删除路由只有一种操作
3、垃圾回收:在一定条件下,fib_sync_down会变量路由表,设置RTNH_F_DEAD标识来标记满足删除条件的路由项。之后,调用fib_flush再次遍历路由表并删除设置了该标志的路由项。注意:没有周期性的函数来清理路由表。
4、对于路由的查找,总是首先搜索路由缓存,当路由缓存没有查找到时,通过ip_route_input_slow和ip_route_output_slow函数来查找路由表
5、不论是哪个方向的流量,都是利用fib_lookup来查找路由表,fib_lookup函数是对每一个路由表所提供的一个包含查找函数的包裹函数,当不支持策略路由时,查找函数版本是针对local表和main表,当支持策略路由时,逻辑更为复杂,需要查找由策略路由提供的路由表。
6、所有的路由表查找,不论路由表是否由策略路由提供,也不论流量方向如何,都是利用fn_hash_lookup来查找。fn_hash_lookup搜索一个能够将封包路由到特定目的地的fib_node实例。遍历上图中的fn_zone,再通过fn_key为关键字,查找到fn_zone中hash表中对应的fib_node。之后,它还需要检查每一个潜在的路由项,来查找与输入参数struct flowi *flp中其他字段相匹配的路由,这个检查由fib_semantic_match完成
fib_semantic_match被调用以发现在与给定的fib_node相关的路由(fib_alias结构)中,是否存在与搜索关键字所有字段都匹配的路由项。
7、dst->input和dst->output的可能的组合如下图所示:
输入路由
ip_route_input_slow的调用过程如下所示:
1、ip_route_input在调用fib_lookup查找路由成功时,会将封包发往本地或者转发,但两者都需要执行一些共同的任务,例如对于源地址的合理性检查,通过fib_validate_source检查欺骗企图,之后再创建和初始化一条新缓存表项