路由,本质上是解决计算机网络中数据包传输路径选择的问题。随着 Linux 操作系统的不断发展,Linux 主机的路由技术也经历了由传统的“单一路由表”向“多路由表”的策略路由(Policy Routing)转变的过程。策略路由,是现代 Linux 网络栈的重要概念。其核心理念摒弃了传统路由的“单一路由表”模式,让一个 Linux 系统可以拥有多个路由表。对网络数据包进行路由时,先是根据规则(rule)选择具体的路由表,然后在确定的某个路由表中进行具体路由路径的选择。
传统路由 — 单表时代
传统路由在工作方式上,有如下几个典型的特点,
- 只有一个路由表:所有数据包都必须得查询同一张表;
- 决策依据单一:只看目标 IP 地址;
如果以城市的交通打个比方,传统的路由就只有一个交通指示牌,它只会告诉你:“所有要去‘北京’的车,都必须且只能走 G1 高速。”
老派的 route 指令集即是针对单表方式进行路由表管理的典型工具。
策略路由 — 多表时代的“智能交通系统”
传统的单表路由方式解决了计算机网络数据包路径选择的基础性问题,简单且直接。在计算机网络发展初期,这种路由方式发挥了其作为指路明灯应有的作用;但是,随着网络不断发展,其粗糙、缺乏灵活性的路由方式已无法适应现在复杂网络环境中的各类新路由需求:除了按照传统方式关注目标 IP 以外,现代路由往往需要根据“谁发出的车”(源 IP)、“车上拉的什么货”(协议/端口)等信息来安排不同路由路线,以实现更为复杂的路由策略,如:
- 来自财务部的访问外国网站的流量,必须走经过审计的代理出口;
- 视频会议的流量优先走延迟低的线路;
- 个人的 VPN 流量不能影响服务器的生产流量;
对于上述的精细化需求,传统的单表路由是无法满足的,更加先进的路由技术 — 策略路由应运而生。
整体设计上,策略路由(Policy Routing)不再依赖单一的路由表,而是引入了一个“裁判员”(路由策略规则)和多个“专用地图”(多张路由表)。路由判定分为两个核心步骤:
- 先策略,即根据一系列“条件”判断应该选择哪一张地图(即选择哪一个路由表);
- 再路由,即查询地图中的具体行进路线(路由表中的具体路由路径)。
传统路由 VS. 策略路由
典型场景一:来自财务部的访问外国网站的流量,必须走经过审计的代理出口
传统路由(出租车司机)的视角:
- 乘客上车说:“我去 google.com(假设 IP 是 8.8.8.8)。”
- 司机看了一眼他唯一的地图(主路由表),发现去 8.8.8.8 的路线只有一条:默认网关 -> 电信出口。
- 司机毫不犹豫地开向了电信出口。
问题分析:
- 致命缺陷:缺乏“来源”信息。司机的决策流程里,完全忽略了“乘客是谁”、“他从哪里上车”。无论是CEO、财务部员工还是访客,只要目的地是 google.com,走的都是完全相同的路线。
- 传统路由表只记录
目标网络 -> 下一跳的映射。没有字段来记录“当数据包来自某网络时,该如何走”。
策略路由的解决方案:
策略路由司机会有一本“高级规则手册”(ip rule list):
- 规则1:如果乘客从“财务部大楼”(源 IP 段
192.168.10.0/24)上车,无论去哪,都使用“地图A”(路由表A)。而地图A里规定,所有目的地都指向“审计代理服务器”。 - 规则2:其他乘客,使用默认地图(主路由表)。
这样,通过源 IP 地址这个关键条件,完美实现了流量区分。
典型场景二:视频会议的流量优先走延迟低的线路
传统路由(出租车司机)的视角:
- 乘客上车说:“我去 Zoom 服务器(假设 IP 是
203.0.113.10)。” - 司机看了一眼地图,发现去这个地址也只有一条路:
默认网关 -> 联通出口。这条路可能很拥堵,延迟很高。 - 司机别无选择,只能开上这条拥堵的路。
问题分析:
- 致命缺陷:缺乏“服务类型”信息。司机不知道你是要去进行紧急的视频会议,还是仅仅在后台下载一个更新包。他对所有“去往 203.0.113.10”的流量一视同仁。
- 传统路由无法识别数据包内部的协议(TCP/UDP) 或端口号(如视频会议常用的特定端口范围)。
策略路由的解决方案:
策略路由的规则手册可以更加智能:
- 规则:如果数据包的目标端口是 UDP 50000-60000(假设是视频会议端口),则使用“地图B”(路由表B)。地图B里,默认路由指向一条优质的“CN2 GIA线路”。
这样,通过协议和端口号,实现了基于应用的流量调度。
典型场景三:个人的 VPN 流量不能影响服务器的生产流量
传统路由(出租车司机)的视角:
- 笔记本电脑(IP
192.168.1.100)上启动了 VPN,VPN 客户端通常会修改默认路由,让所有流量(包括生产流量)都经过 VPN 隧道。 - 这就好比司机突然收到命令:“以后所有客人,不管去哪,都先开到 VPN 这个中转站!”
- 结果,你访问公司内网服务器的生产流量,也得莫名其妙地绕道VPN出去再回来,增加延迟和不稳定性。
问题分析:
- 致命缺陷:“贪婪”的默认路由。传统 VPN 为了确保流量保密,往往采取最简单粗暴的方式——劫持默认路由(
0.0.0.0/0)。它无法做到“只让一部分流量走VPN,另一部分直连”。 - 因为传统路由表里,一条
0.0.0.0/0的路由会匹配所有未知目标,无法设置例外:“除了访问公司网段10.0.0.0/8的流量之外,其他都走VPN”。
策略路由的解决方案(Tailscale 做法):
策略路由可以优雅地解决这个问题:
- 规则1:如果目标 IP 是 公司内网网段(
10.0.0.0/8),不查询 VPN 的路由表,直接查主路由表,从而直连。 - 规则2:如果目标 IP 是其他地址,则查询 VPN 的路由表,走 VPN 隧道。
这种方法是“按需路由”,而非“全盘劫持”,完美实现了流量分流。
场景对比总结
| 需求 | 传统路由的缺陷 | 策略路由的解决方案 |
|---|---|---|
| 根据来源 IP 分流 | 决策仅依赖目标 IP,忽略源 IP | 使用 ip rule add from [IP段] … 将源IP作为匹配条件 |
| 根据应用类型分流 | 无法识别数据包内的协议/端口 | 使用 fwmark(防火墙标记)或 匹配目标端口 作为条件 |
| 实现流量分离 | 修改默认路由会导致所有流量转向 | 使用精确的规则有选择地将特定流量导入特定路由表 |
上述分析不难看出,传统路由是一种“一刀切”的简单模型,而策略路由则引入了一个强大的“流量分类器”(规则集)。这使得路由决策能够基于源、目的、协议、端口、标记等多个维度的信息,在主流通路依旧持续运行的基础上(不改变主路由表),将特定需求的流量从主流通路(原有默认路由路径)中分流出来,另辟路由蹊径(走新路由表),从而实现了网络流量的精细化、智能化管理。这对于现代复杂的网络环境(尤其是多云、混合云、SD-WAN、零信任网络等场景)是不可或缺的。
策略路由的实现
实现机制上,策略路由也并不复杂。在具体的路由表查询中,策略路由的运行实现机制与传统单表路由一致;核心的区别在于多了一道“选表”的动作,为此,策略路由在“选表”机制上设计了如下核心要素:
- 选择器(Selector):定义匹配网络数据包的“条件”;
- 优先级(Priority):确定各种规则执行的顺序;
- 动作(Action):匹配后执行的操作,通常是 “lookup 表名/编号”;
具体运行上,按照优先级的由高到底的顺序,将网络数据包与选择器逐一进行比对,
- 比对成功,执行该选择器对应的动作;
- 比对不成功,比对下一个选择器;
新式的 iproute2 软件包对策略路由功能的实现提供了有力的工具支持。
策略规则的管理 – ip rule
策略规则的查看
指令如下,
ip rule [show | list]
## 策略规则字段的显示格式如下
Priority: Selector Action
典型示例分析,
$ ip rule show
0: from all lookup local
1000: from 192.168.1.100 lookup 100
2000: from 192.168.2.0/24 lookup 200
5210: from all fwmark 0x80000/0xff0000 lookup main
5230: from all fwmark 0x80000/0xff0000 lookup default
5250: from all fwmark 0x80000/0xff0000 unreachable
32766: from all lookup main
32767: from all lookup default
1、Priority (优先级)
示例:0, 1000, 32766
含义:数值越小,优先级越高。
工作流程:
- 当内核需要为一个数据包决定发送路径时,它会从优先级最高的规则(数字最小) 开始依次检查。
- 一旦数据包匹配了某条规则的选择器(如下面的 from),就会使用该规则指定的路由表进行查询,并停止后续规则的匹配。
- 如果都不匹配,最终会落到优先级最低的规则(如 32766 和 32767)。
2、Selector (选择器)
含义:用于匹配数据包的条件。只有满足条件的数据包才会应用此规则。常见的选择器:
- from <IP地址/范围>
- 示例:from 192.168.1.100, from 192.168.2.0/24, from all
- 含义:匹配源 IP 地址。all 是关键字,表示匹配任何源 IP
- to <IP地址/范围>
- 含义:匹配目标 IP 地址
- iif <网络接口名>
- 含义:匹配数据包进入的接口(输入接口)。通常用于处理接收到的数据包。
- oif <网络接口名>
- 含义:匹配数据包发出的接口(输出接口)。通常用于处理本机产生的数据包。
- fwmark <防火墙标记>
- 含义:匹配被 iptables 或 nftables 等防火墙打了标记的数据包。可以实现基于应用、端口等更复杂的分流。
3、Action (动作)
含义:当数据包匹配选择器后,要执行的动作。最常见的动作:
- lookup <路由表>:
- 示例:
lookup local,lookup main,lookup 100,lookup default - 含义:指示内核去查询指定的路由表,以确定数据包的下一跳。路由表可以用数字ID(如 100)或名称(如 main)
- 示例:
- 其他可选动词
- prohibit:拒绝路由并返回 通信被禁止 的 ICMP 消息
- reject:拒绝路由
- unreachable:拒绝路由并返回 网络不可达 的 ICMP 消息
- nat <IP地址>:对数据包进行网络地址转换
策略规则的增减
指令如下,
ip rule add/del/flush
典型示例,
sudo ip rule add from 192.168.1.100 table 100 priority 1000
sudo ip rule del priority 1000
sudo ip rule flush
sudo ip rule flush table 100
系统预设情况下,一般包含 3 条默认的策略规则,信息如下,
0: from all lookup local (必须存在且优先级最高)
32766: from all lookup main (主默认规则)
32767: from all lookup default (default 表通常为空,后备机制)
新增策略规则在 0: from all lookup local 和 32766: from all lookup main 之间添加。
路由表的管理 – ip route
系统预定义路由表集合
安装 iproute2 软件包,系统默认预定义路由表集合在 /etc/iproute2/rt_tables 文件中,
cat /etc/iproute2/rt_tables
# 典型输出:
#
# reserved values
#
255 local
254 main
253 default
0 unspec
每一个路由表,有一个数值与其对应。
查看路由表
使用 ip rule 可以在策略规则里查看到系统当前使用了几个路由表,使用 ip route 则可以查看每张路由表中的选项,
指令如下,
ip route [show] [table number/name]
- 查看系统主路由表
ip route
ip route show
ip route show table main
老派的 route -n 也是查看系统的主路由表。
- 查看特定的路由表
# 查看 local 表
ip route show table local
# 查看编号为 100 的表
ip route show table 100
- 查看所有路由表的路由项
ip route show table all
查看特定目标数据包传送接口
指令如下,
ip route get xx.xx.xx.xx
该指令可直接查看访问特定目标 IP 时,数据包从本机的哪个网络接口发出,
# 访问 111.63.65.103 地址时,数据包如何路由
ip route get 111.63.65.103
# 数据包从 wlp0s20f3 接口送出
111.63.65.103 via 192.168.16.1 dev wlp0s20f3 src 192.168.16.245 uid 1000
Reference
- man ip rule
- man ip route