一次BGP双线接入因AS-PATH策略错误导致业务流量全部走错运营商的排查实录

问题背景

总部机房采用”电信+联通”双线BGP接入架构,核心交换机与两家运营商建立eBGP邻居,通过AS-PATH属性和route-map实现流量调度——默认走电信、联通作为备份,特定网段走联通做负载。某周一下午14:30左右,研发同事反映访问部署在阿里云华东节点的多个API接口(用户中心、订单查询、支付回调)出现持续性卡顿,单次请求从正常的80ms飙升到500ms以上,短信网关、第三方支付回调更是出现间歇性超时。客服部门同步反馈多名用户投诉”支付完成但订单状态未更新”。

故障现象

通过Zabbix监控看到关键业务指标异常:

1
2
3
4
5
14:32:01  Gateway-IP-Monitor  WARN  核心交换机到阿里云华东(47.110.x.x)延迟 412ms (基线 35ms)
14:32:01 BGP-Session-Monitor INFO eBGP 电信邻居 10.10.1.1 Established (Up 87d 4h)
14:32:01 BGP-Session-Monitor INFO eBGP 联通邻居 10.10.2.1 Established (Up 87d 4h)
14:32:15 Zabbix-Trapper CRIT HTTP 业务探测 api.example.com 5xx 告警 (连续3次)
14:32:30 Zabbix-Trapper CRIT 支付回调响应时间 > 5s (SLA违约)

在核心交换机上查看路由表:

1
2
3
4
5
6
<Switch> display bgp routing-table ipv4 unicast brief
Total Number of Routes: 412,387
Network NextHop MED LocPrf PrefVal Path/Ogn

* 47.110.0.0/16 10.10.2.1 0 100 0 4134 ?
* 47.110.0.0/16 10.10.1.1 0 100 0 4134 100 200 ?

诡异的事情出现了:阿里云华东段(47.110.0.0/16)的两条路由都被打上了”无效标记”(问号?),其中电信链路(AS4134 → AS100 → AS200)多了一段莫名其妙的AS-PATH”100 200”,而正常情况下电信学到该网段的AS-PATH应该只显示”4134”或”4134 100”。

排查过程

第一步:确认BGP邻居状态正常

两条eBGP邻居均显示Established,消息收发计数没有异常抖动,说明TCP连接、Keepalive、BGP Open报文一切正常,问题出在路由策略层。

第二步:检查入方向route-map

display current-configuration | include route-map 找到关键策略段:

1
2
3
4
5
6
7
8
9
10
route-map FROM-TELECOM-IN permit 10
description Accept legitimate telecom routes
match as-path 10
!
route-map FROM-TELECOM-IN deny 20
description Reject transit routes
match as-path 20
!
ip as-path 10 permit ^(4134_)+$
ip as-path 20 permit _100_200_

看到as-path 20那行瞬间明白问题所在——正则_100_200_会匹配任何包含”100 200”两个相邻AS的路径,包括电信运营商内部传递过来的真实路由。当时我们调度的逻辑是”拒绝任何包含私有AS号100、200的路径”,但忘记了一个事实:电信骨干网在传递某些跨网段路由时,会在AS-PATH中插入”100 200”作为内部标记(这是中国电信AS4134的私有AS号,用于内部选路标记)。

第三步:验证猜想

在核心交换机上抓取近期BGP Update报文,过滤AS-PATH含”100 200”的路由前缀数量:

1
2
3
<Switch> display bgp update-peer-group 10.10.1.1 statistics
...
Prefix count with AS-PATH matched _100_200_: 287,341

近30万条合法路由被这条正则误杀,全部进了BGP RIB-in的”待丢弃”队列,对端却还以为邻居都正常、路由都通告了。

第四步:检查本地注入的BGP路由

为防止出现路由黑洞,运维A同事把核心交换机的LoopBack0(10.255.0.1/32)通过network命令注入BGP,这条命令的下一跳指向10.10.1.1(电信),触发了一段被错误拒绝的AS-PATH。

1
2
3
4
5
6
7
<Switch> display bgp routing-table 10.255.0.1
BGP local router ID is 10.255.0.1
Status codes: * - valid, > - best, d - damped, h - history,
s - suppressed, S - stale, i - internal, b - backup
Origin: i - IGP, e - EGP, ? - incomplete

Total Number of Routes: 0

连自己的LoopBack都没被优选——所有从电信学到的路由都被route-map打上”无效”标记,对端联通的路由因为local-preference默认100而进入主表,但很多明细网段联通链路延迟本来就高,导致从核心出去的流量”全跑联通”。

第五步:与运营商侧核对

拨通电信大客户经理电话,对方工程师确认他们在上周末升级了AS4134的出口策略,会在AS-PATH中插入”100 200”作为新引入的BGP选路标记。也就是说不止我们这端,所有走电信BGP接入的企业客户都受到了影响——只是我们这条正则写得太严格。

第六步:临时止血

先把误杀的AS-PATH正则屏蔽掉,恢复路由:

1
no ip as-path 20

60秒后,路由表刷新,47.110.0.0/16的两条路由恢复正常选路,业务延迟从412ms回到35ms基线。

解决方案

长期方案:改用AS-PATH长度作为判定标准

“100 200”只是运营商内部标记,不能简单粗暴作为业务流的甄别依据。改为基于AS-PATH长度做拒绝:

1
2
3
ip as-path 10 permit ^(4134_)+$
ip as-path 20 permit _(6451[2-9]|6553[0-5])_
ip as-path 30 permit ^[0-9]+$ ! 只允许单一AS的路由(对端直连段)

只拒绝真正属于RFC 6996保留私有AS号的路径,避免误伤。

给route-map加日志计数

1
2
3
4
route-map FROM-TELECOM-IN deny 20
description Reject private AS
match as-path 20
set traffic-index 99

配合流量监控,一旦被拒绝的路由条目激增立即告警。

增加BGP邻居级监控

在Zabbix上对每个BGP邻居的关键指标做模板化:

指标 告警阈值
收到的BGP路由前缀数 ±20% baseline
AS-PATH 拒绝计数 > 0
Update 报文频率 > 1000/分钟
BGP邻居翻动次数 > 0/小时

关键配置变更走代码评审

这条ip as-path 20 permit _100_200_是去年一个临时调试遗留的命令,没有走严格的code review,从那之后就一直在线上跑了——是典型的”运行久了就以为是正确的”陷阱。

根因分析

直接原因:去年临时调试写的ip as-path 20 permit _100_200_正则没有清理,该正则的本意是拒绝经过某些对等AS的路由,但因为AS-PATH正则下划线表示”任意字符串边界”,_100_200_实际匹配的是”含100和200这两个相邻AS号的所有路径”。

深层原因:电信AS4134骨干网升级后,在跨网传递路由时会在AS-PATH中追加”100 200”作为内部标记,这本来是合法的BGP属性,但与我们的策略冲突,导致近30万条路由被误判无效。

运营原因:路由策略类变更缺乏变更评审、回归测试、监控告警机制,”上线即正确”的惯性思维让这条命令在线上跑了8个多月,直到电信骨干网升级才暴露出问题。

预防措施

1. 路由策略变更必须走变更窗口

所有涉及route-mapip as-pathip community-listip prefix-list的变更,必须在业务低峰期执行,且必须经过至少一名网络架构师评审,并保留前后配置对比。

2. 部署”路由沙盒”

搭建一个隔离的BGP测试环境,使用Bird或FRRouting跑一个真实环境的镜像,配置变更先在沙盒里跑24小时观察,再上生产。

3. 完善BGP监控体系

  • 每分钟采集BGP邻居的Received/Active Routes数量
  • 对AS-PATH regex匹配做计数器
  • 任何route-map的deny规则都应配WELF/Syslog上报

4. 与运营商建立常态化沟通机制

每次运营商侧骨干网升级、AS号调整、出口策略变化,都应在第一时间拿到变更通知单,评估对自有路由策略的影响。

5. 路由策略配置文件纳入Git管理

把核心交换机的配置按以下目录结构纳入Git:

1
2
3
4
5
6
7
network-config/
├── core-sw-01/
│ ├── bgp.conf
│ ├── route-map.conf
│ └── changelog.md
├── core-sw-02/
└── README.md

每次配置变更都走commit-msg规范,”为什么要这样配”的业务背景要写在commit信息里,避免半年后回看一脸懵。

总结

这次故障给我们最深的教训是:网络策略的”误拒绝”比”误允许”更隐蔽。误允许会立刻有告警(被拒绝的路由完全消失、流量中断),而误拒绝会让路由”看起来还在”(实际被打上无效标记),却悄悄把流量引到错误的路径上,影响业务却难以第一时间定位。

后续我们把”路由策略变更必须配监控”写进了运维SOP:任何新增的deny规则、任何修改的正则表达式、任何调整的local-preference,都必须配套一条监控项,且这条监控的告警接收人是这次变更的提交人本人——谁改的,谁兜底。

BGP是互联网的”神经系统”,容不得半点马虎。