概述
测路路由介绍
关于策略路由是什么,为什么需要策略路由, man手册里写的这一段,我认为是最经典的一个解释。
清晰明了,这里借用并翻译下。
1 | Classic routing algorithms used in the Internet make routing |
尝试翻译下:
1 | 传统的路由方法,是基于报文的目的地地址做路由查找(理论上支持,但没啥卵用的 TOS 字段就不讨论了) |
对需求背景说的非常清楚,具体实现,后续我们展开讲解。
取代,我个人任务这里用replaced
不够严谨:
这里的RPDB取代传统路由,是在原有传统路由的基础上,增加新的模块,提供更多样的路由查找方式。也许原作想表达的是路由查找接口被取掉。
所以这里保留直译。
如何使用
假设一个场景:为了方便,这里使用一个容器做实验,容器有三个网口,veth0,veth2,veth4, 并配有/24掩码的IP地址。
veth0: 192.168.0.1/24
veth2: 192.168.2.1/24
veth4: 192.168.4.1/24
系统配置一条缺省路由指向veth4
添加rule
添加table
规则路由(rule route)
这部分详见ip rule命令帮助手册,
https://man7.org/linux/man-pages/man8/ip-rule.8.html
简要总结:
- 支持多种形式的路由查找,不再仅仅局限于传统路由,根据目的地址查找一种模式。
- 每条规则(rule) 都有一个优先级, 内核按照priority从高到底按顺序放到一个链表中。priority值越小,优先级越高,0对应优先级最高。
- rule route采用了类似match-action模式, 不过rule route称之为
SELECTOR
和ACTION
。 SELECTOR
支持多种形式,比如IP、PORT、进出网口、tos以及非操作(not
)ACTION
中几个重要的类型:- table:到指定的TABLE_ID对应的路由表里查找(所以这里要求必须支持多table)
- goto: 跳转到指定的rule。这里只能往链表中,当前节点后面的节点去跳,不能往前跳。
- nat: 支持IP地址nat(TODO nat 废弃?)
- 路由查找时候使用,按链表里顺序(优先级)依次比较每个节点的的match 条件,如果满足则执行对应的 action,否则跳到下一个节点,继续执行。如果满足
- ACTION 是跳转,则直接跳过中间节点,继续匹配链表剩余节点。
- action是table X,则使用目的地ip去路由表table X里查找最长匹配的路由,查找的路由结果即为最终路由查找结果。
说明:
- route里goto 可以反复多次嵌套多条rule,其他action均不能嵌套执行。比如lookup,table查找的结果就是最终结果,不会再有其他跳转和嵌套。
使用场景
差异化网络服务:比如内网的公网网关,有两个公网出口,有两类流量经过这个网关,流量1: 架设在内部的视频服务器,通过DNAT映射到外网的一个端口,并采用IP直通模式到服务器,出流量特定,固定的源IP/port。 其他内网设备访问公网的流量。
需求:希望视频流量走公网口A。其他流量走公网出口B。
这时候,可以通过一个策略路由,把源ip+port的流量指定走网口 A,缺省路由走公网B。
策略路由实例
1 | root@martin-Standard-PC-Q35-ICH9-2009:/home/martin# ip rule show |
没有嵌套
内核代码解析
根据内核v6.6代码整理
数据结构
每个netns下有个IPv4相关的路由信息变量struct netns_ipv4 ipv4
,
然后通过rules_ops
指向IPv4对应的struct fib_rules_ops
.
在这个ops下有一个rules_list
链表,串联了所有的rule route。
每个rule对应一个结构体struct fib_rule
- 每次增加rule规则时候,
struct netns_ipv4
里的变量fib_has_custom_rules
被更新为true,以记录规则路由被启用了。 - ops的初始化
系统初始化时候,在fib4_rules_init
里,通过复制模版创建一个ops,并把net信息记录到’ops’里。
这个新创建的’ops’又被挂到’net’下的rule_ops
链表里. 最后这个ops被保存到’IPv4’下的rules_ops
1
2
3
4
5
6fib4_rules_init
--> fib_rules_register(&fib4_rules_ops_template, net)
--> --> ops = kmemdup && ops->fro_net = net ;//复制模版创建一个ops,并把net信息记录到ops里。
--> --> __fib_rules_register
--> net->ipv4.rules_ops = ops;
--> net->ipv4.fib_has_custom_rules = false;
1 | 61 struct net { |
1 | 44 struct netns_ipv4 { |
1 | 60 struct fib_rules_ops { |
1 | 20 struct fib_rule { |
函数调用关系
IPv4路由查找的关键函数
+ ip_route_output_flow
:路由查找的入口函数
+ fib_table_lookup
: 在一个具体table里,查找路由
tcp/udp/icmp/raw等类型的socket发送数据时候, 先调用到函数ip_route_output_flow
,进而调用到fib_lookup
,在这里通过宏CONFIG_IP_MULTIPLE_TABLES
并分两种场景支持多table
和单table
- 单table:只有一个
main
路由table表,不支持多table。` - 多table: 支持多个table。这是支持规则路由的一起必要条件。