CN2 GIA、CMI与9929按ASN分流不生效,如何检查路由表与回程路径?
客户端访问海外物理机时,电信、移动、联通的连接都能建立,但回包集中从同一张网卡出去;或者分流规则已经添加,ip route get 仍然显示主路由表的默认出口。这类现象首先要检查“目标地址是否进入分流集合、策略规则是否命中、专用路由表能否完成查找”,再通过抓包确认实际出口,而不是先修改默认网关。
CN2 GIA、CMI、9929 按 ASN 分流不生效,还可能发生在主机之外:Linux 已经选对出口,但上游不接受该源地址,或者该出口后面的实际路径与预期不符。排查必须把主机选路、上游转发、客户端到服务器的去程分开验证;服务器上的策略路由只能直接控制本机发出的流量,不能单方面决定客户端的去程。
一、先确认“不生效”发生在哪一层
把线路名称、目标 ASN 和出口对应关系分开
Linux 常规策略路由并不能直接识别“这个 IP 属于哪个 ASN”。实际配置通常是:
目标 ASN → IP 前缀集合 → 目标地址匹配或报文标记 → 策略规则 → 专用路由表 → 网卡与网关。

CN2 网络通常关联 AS4809,CMI 国际骨干通常关联 AS58453,联通相关的 9929 网络关联 AS9929。但这些是线路或网络身份线索,不能直接当成全部国内用户的目标 ASN。
例如,电信客户端地址可能来自 AS4134,移动客户端地址可能来自 AS9808,联通客户端地址可能来自 AS4837,也可能涉及其他接入网络。把 AS4809 的前缀全部送入 CN2 出口,并不等于“所有电信用户都走 CN2”。
应先核对以下对应关系:
| 核对对象 | 要确认的内容 | 不正确时的表现 |
|---|---|---|
| 客户端地址 | 服务器实际看到的源 IP | 匹配了用户地址,但实际对端是 CDN 或负载均衡节点 |
| ASN 数据 | 使用地址前缀的起源 ASN,而非路径中任意 ASN | 前缀集合过大、遗漏或归类错误 |
| 出口对应 | 哪个网关实际连接哪条线路 | 表名叫 CN2,实际默认网关却连到其他上游 |
| 源地址权限 | 该出口允许发送哪些源 IP | 本机抓到出包,对端却收不到 |
| 策略范围 | IPv4、IPv6、本机业务还是转发业务 | IPv4 测试成功,实际业务走 IPv6 |
按 ASN 分流的关键不是规则里出现了 ASN 名称,而是业务对端 IP 能否命中正确的前缀集合。
固定一个可复现的测试连接
不要同时拿不同客户端、不同协议和不同源地址比较。先记录一组固定条件:
- 客户端公网 IP、地址族和所属网络。
- 服务器被访问的公网 IP及监听端口。
- 预期出口、实际出口和故障时间。
- 使用直连业务,还是经过 CDN、负载均衡或容器转发。
检查监听与连接:
ss -lntp
ss -ntp
如果服务器看到的连接对端不是用户公网地址,分流对象就应改为实际对端,或者重新评估架构。主机无法根据一个已经被上游替换的源地址,恢复原始客户端的路由归属。
后文命令以 Debian 12、Ubuntu 22.04/24.04 常见的 Linux、iproute2、nftables 环境为例,重点检查物理机本地服务的 IPv4 回包。容器转发、IPv6 和策略持久化需要分别核验。
二、从外部路径和物理出口开始,只做观察
先保存现场,不刷新规则
修改前准备带外控制台,并保持一个管理会话。尤其不要通过唯一的 SSH 连接直接替换默认路由或清空防火墙。
以下命令只保存配置,不修改转发行为:
umask 077
BACKUP_DIR=$(mktemp -d /tmp/a5-route-check.XXXXXX)
ip -4 addr show > "$BACKUP_DIR/addr-v4.txt"
ip -4 rule show > "$BACKUP_DIR/rule-v4.txt"
ip -4 route show table all > "$BACKUP_DIR/route-v4.txt"
sudo nft list ruleset > "$BACKUP_DIR/nft-ruleset.txt"
printf '现场记录目录:%s\n' "$BACKUP_DIR"
这些文件是排查记录,并不意味着可以直接作为完整恢复脚本执行。路由恢复应针对本次改动逐条回退;防火墙也优先删除本次新增对象,避免覆盖其他业务规则。
同时核验系统与工具:
cat /etc/os-release
uname -r
ip -V
nft --version
ip -br link
ip -br -4 addr
若系统实际采用其他防火墙管理器,应沿用现有管理方式,不要临时引入另一套规则形成冲突。
从两端分别测路径
在国内客户端测试到服务器的路径,得到的是去程。在服务器测试到客户端的路径,观察的是服务器发起探测时的出站路径,不能直接当成原有业务回包的证据。
有 mtr 的环境可执行:
mtr -4 -r -w -c 20 -T -P 443 SERVER_IP
服务器侧可固定源地址:
mtr -4 -r -w -c 20 -T -P 443 -a SERVER_SOURCE_IP CLIENT_IP
将占位符替换为实际地址。TCP 端口应选择允许测试的业务端口;若客户端不接受入站连接,终点不响应不能单独证明线路故障。
结果要这样解释:

- 中间节点不回应,但后续节点和终点正常,不代表该跳存在真实业务丢包。
- 仅从主机名、少量 ASN 标签或单次探测,不能完整确认线路产品属性。
- 去程与回程可以不同,不能用国内客户端的一张路由图证明服务器回程已经分流。
- 固定源地址的探测也未必命中业务使用的标记规则,因此必须结合真实业务抓包。
确认三条线路是否真的有主机侧选择入口
多线路物理机不一定有三张网卡,也可能通过 VLAN、多个网关或服务商侧策略区分出口。检查:
ip -4 route show table main
ip -d link show
ip neigh show
如果主机只有一个可达网关,且服务商并未提供可选择的其他下一跳,那么增加三个路由表不会凭空产生三条线路。此时应先向服务商确认线路交付方式、网关和源地址授权范围。
邻居状态 REACHABLE、STALE 通常不属于故障;持续 INCOMPLETE 或 FAILED 才需要检查网关地址、VLAN、掩码及二层连通性。
三、进入主机:依次查前缀、规则和路由表
检查前缀集合,而不只检查更新脚本
如果按 ASN 生成地址集合,需要同时检查“生成结果”和“内核实际加载结果”。
常见问题包括:
- ASN 数据更新成功,但加载脚本失败。
- 只更新了磁盘文件,内核里仍是旧集合。
- IPv4 与 IPv6 混用。
- 集合只包含少量骨干前缀,遗漏实际接入用户地址。
- 集合更新期间出现空窗,部分连接落到默认出口。
使用 nftables 时,先查看实际规则与集合:
sudo nft -a list ruleset
sudo nft list sets
找到分类集合后,再查看具体内容:
sudo nft list set inet a5_asn_test cn2_v4
上述表名、集合名只是后文示例;已有配置应使用实际名称。核验重点是测试客户端 IP 是否被某个前缀覆盖,不能用“文件中有这个 ASN”替代地址匹配检查。
查看策略规则的优先级
ip -4 rule show
Linux 策略规则的 priority 数值越小,越先检查。常见的默认规则中,local 表优先于 main 表。
需要重点寻找:
- 分流规则是否排在
main查询之后。 - 是否存在更早的源地址规则,把流量送入另一张表。
fwmark的值和掩码是否与打标规则一致。- 是否有
blackhole、unreachable、prohibit或 VRF 相关规则。 - 相同优先级或重复规则是否让行为难以判断。
一个容易漏掉的区别是:规则匹配了,不代表这张表一定返回有效路由。 表里没有匹配路由时,通常还会继续查询后续规则;若表里存在默认路由,则可能直接结束本次查找。
对指定目的地址做完整路由查询
以下使用文档地址和实验地址展示逻辑,不应原样部署到公网:
| 出口示例 | 网卡 | 本机地址 | 网关 | 路由表 |
|---|---|---|---|---|
| CN2 | eno1 | 192.0.2.10/24 | 192.0.2.1 | 100 |
| CMI | eno2 | 198.51.100.10/24 | 198.51.100.1 | 200 |
| 9929 | eno3 | 203.0.113.10/24 | 203.0.113.1 | 300 |
测试目的地址用 198.18.0.10 代表 CN2 分类中的某个对端。执行:
ip -4 route show table 100
ip -4 route show table 200
ip -4 route show table 300
ip -4 route get 198.18.0.10
ip -4 route get 198.18.0.10 from 192.0.2.10
ip -4 route get 198.18.0.10 from 192.0.2.10 mark 0x100
这三个查询分别回答:
- 未指定源地址和标记时,内核如何选路。
- 已有连接以指定源地址回包时,如何选路。
- 报文带指定标记时,策略规则能否选择目标表。
ip route get 不会执行 nftables 规则。第三条显示正确,只能证明“已有这个标记时可以选对路”,不能证明真实报文被打上了标记。
如果带标记查询仍落入 main,先查规则和掩码;如果已经选中目标表,但出现不可达错误,则查表内路由、网关与接口状态。

四、按结果分支修复,先隔离再扩大
分支一:目标表缺路由,或网关不可达
以下仅适用于表 100、200、300 尚未被其他业务使用,且三个接口地址已经正确配置的测试环境。正式环境应先替换为真实接口、地址和网关。
每张表同时放入网关所在网段和默认路由:
sudo ip -4 route add table 100 192.0.2.0/24 dev eno1 src 192.0.2.10
sudo ip -4 route add table 100 default via 192.0.2.1 dev eno1 src 192.0.2.10
sudo ip -4 route add table 200 198.51.100.0/24 dev eno2 src 198.51.100.10
sudo ip -4 route add table 200 default via 198.51.100.1 dev eno2 src 198.51.100.10
sudo ip -4 route add table 300 203.0.113.0/24 dev eno3 src 203.0.113.10
sudo ip -4 route add table 300 default via 203.0.113.1 dev eno3 src 203.0.113.10
采用 add 而不是直接 replace,是为了让已有配置冲突显式报错。出现 File exists 时应核对现有条目,不要直接覆盖。
这里的 src 是首选源地址,不会把已有 TCP 连接的回包源地址改成另一张网卡的 IP。客户端访问 192.0.2.10,业务回包仍可能以该地址为源,从 eno2 发出;如果 CMI 上游不允许这个源地址,主机选路正确也会失败。
需要回退时,只删除本次成功添加的默认路由和网段路由,例如:
sudo ip -4 route del table 100 default via 192.0.2.1 dev eno1
sudo ip -4 route del table 100 192.0.2.0/24 dev eno1
表 200、300 按对应条目回退,不要清空整张已被使用的表。
分支二:怀疑打标,先用单地址规则隔离
在确认优先级 10100 未被占用、且应位于相关主路由查询之前后,只对一个测试对端添加规则:
sudo ip -4 rule add priority 10100 to 198.18.0.10/32 lookup 100
ip -4 route get 198.18.0.10 from 192.0.2.10
随后建立一条新的测试连接并抓包。
- 单地址规则有效,原来的 ASN 分流无效:重点检查集合、打标链和标记掩码。
- 单地址规则也无效:继续检查更早规则、表内路由和上游源地址限制。
- 只有指定源地址的查询异常:检查源地址规则或业务绑定方式。
测试完删除该规则,避免它长期绕过正常分类逻辑:
sudo ip -4 rule del priority 10100 to 198.18.0.10/32 lookup 100
这个方法比立即重写整套防火墙风险低,也更容易判断责任层。
分支三:规则存在,但本机回包没有被打标
物理机本地服务的回包经过 OUTPUT,不是转发业务的 FORWARD。如果只在入站 PREROUTING 设置报文标记,而没有适当保存、恢复连接标记,回复报文不会自动继承入站标记。
对“按回包目标 IP 分类”的本机服务,可以在 nftables 的 route 类型 output 链打标,使内核在标记变化后重新进行路由选择。
下面是独立测试配置。三组 198.18.* 前缀仅用于实验,不代表任何真实 ASN。部署前必须替换为审核后的前缀,并确认保留的标记位没有被其他组件使用。
table inet a5_asn_test {
set cn2_v4 {
type ipv4_addr
flags interval
elements = { 198.18.0.0/24 }
}
set cmi_v4 {
type ipv4_addr
flags interval
elements = { 198.18.1.0/24 }
}
set unicom9929_v4 {
type ipv4_addr
flags interval
elements = { 198.18.2.0/24 }
}
chain mark_local_reply {
type route hook output priority mangle; policy accept;
ip daddr @cn2_v4 counter meta mark set (meta mark & 0xfffff0ff) | 0x100
ip daddr @cmi_v4 counter meta mark set (meta mark & 0xfffff0ff) | 0x200
ip daddr @unicom9929_v4 counter meta mark set (meta mark & 0xfffff0ff) | 0x300
}
}
将其保存为独立文件,先做语法检查:
sudo nft -c -f /root/a5-asn-test.nft
-c 仅检查,不应用。确认表名不存在、前缀互不冲突、已有规则不会覆盖这些标记后,再加载并添加规则:
sudo nft -f /root/a5-asn-test.nft
sudo ip -4 rule add priority 11000 fwmark 0x100/0xf00 lookup 100
sudo ip -4 rule add priority 11010 fwmark 0x200/0xf00 lookup 200
sudo ip -4 rule add priority 11020 fwmark 0x300/0xf00 lookup 300
这里仅修改 0xf00 对应的标记位,保留其他位。三个集合必须互斥,否则后匹配的规则可能覆盖前面的线路标记。
本例不实现“从哪条线进就从哪条线出”,也不覆盖容器转发。若需求是按入站线路保持回程,需要连接标记保存与恢复方案,不能把本例直接套用。
发生异常时,先撤销策略规则,再删除本次专用表:
sudo ip -4 rule del priority 11000 fwmark 0x100/0xf00 lookup 100
sudo ip -4 rule del priority 11010 fwmark 0x200/0xf00 lookup 200
sudo ip -4 rule del priority 11020 fwmark 0x300/0xf00 lookup 300
sudo nft delete table inet a5_asn_test
该回滚只适用于本次新建、无其他业务共用的测试表,不应使用 flush ruleset 清空全局规则。
五、出口正确仍失败:查源地址、反向校验和实际回程
用抓包确认真实报文,而不是只看查询结果
在预期出口和错误出口分别观察:
sudo tcpdump -ni eno1 'host 198.18.0.10 and tcp port 443'
sudo tcpdump -ni eno2 'host 198.18.0.10 and tcp port 443'
抓包需要权限,也可能包含业务信息,应缩小过滤范围和采集时间。
重点看四件事:
- 请求从哪张接口进入。
- 回复是否生成。
- 回复从哪张接口离开。
- 离开时的源 IP 是否属于上游允许的范围。
同时查看计数器:
sudo nft list chain inet a5_asn_test mark_local_reply
ip -s link show dev eno1
ip -s link show dev eno2
只有总网卡计数增长不足以证明测试流量命中,必须结合对端地址、端口和规则计数。
检查反向路径过滤,但不要直接关闭全部保护
多出口环境中,严格反向路径校验可能认为某个入站源地址应从另一张网卡到达,从而丢弃报文:
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.eno1.rp_filter
sysctl net.ipv4.conf.eno2.rp_filter
sysctl net.ipv4.conf.eno3.rp_filter
常见值为:0 关闭、1 严格模式、2 宽松模式。Linux 会结合 all 和对应接口的值判断,不能只修改一个值便认定检查已关闭。
确认严格校验与合法非对称流量冲突后,可以在维护窗口仅对相关接口测试宽松模式。先记录原值,再修改:
OLD_RPF_ENO2=$(sysctl -n net.ipv4.conf.eno2.rp_filter)
sudo sysctl -w net.ipv4.conf.eno2.rp_filter=2
测试结束按原值回退:
sudo sysctl -w "net.ipv4.conf.eno2.rp_filter=$OLD_RPF_ENO2"
放宽校验会改变源地址检查行为,应配合现有入口过滤评估。若反向查找依赖标记,还应核验 src_valid_mark 及入站标记是否实际存在,不能认为只在 OUTPUT 打标就解决了所有入站校验。
依据观测结果定位责任层
| 观测结果 | 优先排查位置 | 后续动作 |
|---|---|---|
| 分类计数不增长 | 对端地址、前缀集合、链位置 | 核对实际连接与集合覆盖 |
| 计数增长,仍走错误接口 | 标记覆盖、掩码、规则优先级 | 带 mark 查询并检查后续规则 |
| 查询选对表,真实报文走错 | 网络命名空间、转发路径、已有连接 | 确认业务是否真在主机 OUTPUT |
| 入包可见,但无回复 | 监听、应用、防火墙、反向校验 | 先判断报文是否到达协议栈 |
| 回复从正确接口离开,对端收不到 | 上游源地址限制、出口 ACL、下游路径 | 提交五元组、时间与双端抓包 |
| IPv4 正常,业务仍异常 | IPv6、DNS、连接复用 | 分地址族测试并检查真实连接 |
本机选择正确网关,不等于端到端一定经过预期网络。 如果服务商统一接入后再做上游调度,主机路由表只能证明选择了交付的下一跳,后续路径还需要服务商侧和对端观测支持。

六、修复后复测,并观察配置是否再次漂移
验证至少包括三类客户端:分别选取实际属于电信、移动、联通接入网络的测试地址,核对其当前前缀分类,而不是只凭客户端名称分组。
每类都按相同顺序执行:
- 建立新连接,记录源地址、目的地址、协议和端口。
- 查看对应分类计数器是否增长。
- 检查带源地址、带标记的路由查询。
- 抓包确认实际出口和源 IP。
- 从客户端确认业务响应,再补充双向路径测试。
还要测试一个未归类地址,确认它仍走预期的默认出口;测试管理地址、内网和健康检查目标,确认没有被错误分流。不要为了让单个测试成功,把所有目标都划入某条线路。
运行验证通过后,再把配置交给现有网络管理工具持久化。先确认系统采用 Netplan、systemd-networkd、NetworkManager 还是其他方式,避免启动脚本和网络管理服务重复添加规则。网卡重连、服务重启与系统重启后的行为,都应安排带外条件下复测。
持续观察可围绕几项具体信号展开:ASN 前缀更新时间、每类规则计数、默认出口流量占比、接口错误、网关邻居状态,以及客户端网络变化后的路径差异。前缀更新应先校验非空、格式与重叠,再以事务方式更新集合,避免逐条删除再添加造成匹配空窗。
当三类测试连接都能证明“对端分类正确、标记正确、路由表正确、实际出口正确”,并且对端能够收到回包,才算完成主机侧闭环。此后若线路路径仍与预期不符,就应携带明确的测试时间、五元组、源地址和双向证据交由上游继续排查,而不是反复修改已经验证正确的本机规则。



