第337篇:OSPF 与 BGP 路由重分发故障案例
关键词
OSPF、BGP、路由重分发、路由环路、次优路径、路由反馈、双点重分发、路由策略
一、案例背景
1.1 网络拓扑
某企业网络拓扑:
┌──────────────────────────────────────────┐
│ 核心层(OSPF Area 0) │
│ ┌────────────────────────────────────┐ │
│ │ Core-1 ───── OSPF ───── Core-2 │ │
│ │ │ │ │ │
│ │ 重分发 重分发 │ │
│ │ │ │ │ │
│ │ Border-1 ──── BGP ─── Border-2 │ │
│ │ │ │ │ │
│ │ [ISP-1] [ISP-2] │ │
│ └────────────────────────────────────┘ │
│ │
│ BGP AS: 65001 │
│ OSPF Process: 1, Area 0 │
│ │
│ 需求: │
│ └─ 内部使用 OSPF 路由 │
│ └─ 外部通过 BGP 从 ISP 学习 │
│ └─ BGP 路由重分发到 OSPF(给内部设备) │
│ └─ OSPF 默认路由重分发到 BGP(缺省路由) │
└──────────────────────────────────────────┘
1.2 故障现象
故障现象:
时间:周三上午 10:00
影响:内部网络访问 Internet 延迟高、不稳定
现象:
┌──────────────────────────────────────────┐
│ ping 外网(114.114.114.114): │
│ └─ Core-1 上 ping:延迟 5ms(正常) │
│ └─ Core-2 上 ping:延迟 5ms(正常) │
│ └─ 内部接入交换机 ping:延迟 200ms+ │
│ └─ 内部接入交换机 ping:间歇性超时 │
│ │
│ traceroute 外网: │
│ └─ 内部接入 → Border-1 → ISP-1 │
│ └─ 但 ping 的流量却走了: │
│ 内部接入 → Core-1 → Core-2 → │
│ Border-2 → ISP-2 → ISP-1 │
│ └─ 走了 5 跳,多绕了 4 跳! │
│ │
│ 路由表检查: │
│ └─ 内部接入交换机上: │
│ 0.0.0.0/0 via 10.0.1.254 (Core-1) │
│ 但 BGP 路由从 Core-2 学到的 │
│ 实际上 10.0.1.254 不是最优路径 │
└──────────────────────────────────────────┘
二、根因分析
2.1 配置回顾
问题配置:
Border-1 的重分发配置:
┌──────────────────────────────────────────┐
│ ospf 1 │
│ import-route bgp │
│ ↑ 将 BGP 路由全部重分发到 OSPF │
│ │
│ bgp 65001 │
│ import-route ospf 1 │
│ ↑ 将 OSPF 路由全部重分发到 BGP │
└──────────────────────────────────────────┘
Border-2 的重分发配置(完全一样):
┌──────────────────────────────────────────┐
│ ospf 1 │
│ import-route bgp │
│ │
│ bgp 65001 │
│ import-route ospf 1 │
└──────────────────────────────────────────┘
2.2 问题分析
路由反馈环路(Route Feedback Loop):
步骤 1:初始状态
┌──────────────────────────────────────────┐
│ ISP-1 发布 0.0.0.0/0 → Border-1 BGP │
│ ISP-2 发布 0.0.0.0/0 → Border-2 BGP │
│ │
│ Border-1: │
│ └─ BGP 路由:0.0.0.0/0 via ISP-1 │
│ └─ OSPF 路由:0.0.0.0/0 via ISP-1 │
│ (import-route bgp 注入到 OSPF) │
└──────────────────────────────────────────┘
步骤 2:Border-2 收到 OSPF 默认路由
┌──────────────────────────────────────────┐
│ Border-2 从 OSPF 学到: │
│ └─ 0.0.0.0/0 via Border-1 (OSPF) │
│ │
│ Border-2 的 BGP 从 ISP-2 也学到: │
│ └─ 0.0.0.0/0 via ISP-2 (BGP) │
│ │
│ Border-2 将 OSPF 路由重分发到 BGP: │
│ └─ import-route ospf │
│ └─ 0.0.0.0/0 via Border-1 注入到 BGP │
│ └─ 这就是"路由反馈" │
└──────────────────────────────────────────┘
步骤 3:Border-1 收到"被污染"的 BGP 路由
┌──────────────────────────────────────────┐
│ Border-1 从 BGP 学到: │
│ └─ 0.0.0.0/0 via ISP-1 (原始) │
│ └─ 0.0.0.0/0 via Border-2 (反馈) │
│ │
│ 比较: │
│ ┌─ ISP-1: AS_PATH = [100] │
│ ├─ Border-2: AS_PATH = [65001 100] │
│ └─ ISP-1 路径更短,优选 ISP-1 │
│ │
│ 但问题是:内部设备看到多条默认路由! │
└──────────────────────────────────────────┘
最终效果(次优路径):
┌──────────────────────────────────────────┐
│ 内部接入交换机看到 OSPF 默认路由: │
│ ┌─ 0.0.0.0/0 via Border-1 (Cost: 10) │
│ ├─ 0.0.0.0/0 via Border-2 (Cost: 8) │
│ └─ 选择 Cost 更小的 Border-2 │
│ │
│ 流量路径: │
│ └─ 接入交换机 → Core-2 → Border-2 │
│ └─ Border-2 有两条默认路由: │
│ └─ 优选 BGP 路由(AD 20 vs OSPF 110)│
│ └─ 通过 ISP-2 出网 │
│ │
│ 这不是次优路径,而是正确路径! │
│ │
│ 真正的问题在更复杂的场景: │
│ 当 ISP-1 的链路是 1G,ISP-2 是 100M │
│ 但内部设备选择了 ISP-2 路径 │
│ 导致出口带宽受限,延迟增大 │
└──────────────────────────────────────────┘
2.3 真正的问题
本案例的"真正故障"是路由环路风险:
潜在的路由环路场景:
当 ISP-1 链路断开时: 1. Border-1 的 BGP 默认路由消失 2. 但 Border-1 的 OSPF 默认路由还在 (从 Border-2 通过 OSPF 学到的) 3. Border-1 将 OSPF 默认路由再注入 BGP 4. Border-1 的 BGP 默认路由 via Border-2 5. Border-1 访问外网 → 发给 Border-2 6. Border-2 默认路由 via Border-1 (从 OSPF 学到的反馈路由) 7. Border-2 → 发给 Border-1 8. 形成路由环路! TTL 耗尽前,数据包在两个路由器间来回 导致大量丢包和高延迟
三、解决方案
3.1 正确的重分发配置
# correct_redistribution.py — 正确的路由重分发配置
def generate_correct_config():
"""生成正确的重分发配置 - 使用路由策略"""
border_1_config = """
sysname Border-1
# ========== 使用 Route-Policy 控制重分发 ==========
# 1. BGP → OSPF:只重分发来自 ISP 的外部路由
# 不重分发从 OSPF 学到的路由(防反馈)
route-policy BGP_TO_OSPF permit node 10
if-match route-type external # 只匹配 EBGP 路由
if-match as-path ^100$ # 只匹配来自 ISP-1 的
apply cost 10 # 设置 OSPF Cost
route-policy BGP_TO_OSPF deny node 100 # 拒绝所有其他
# 2. OSPF → BGP:只重分发内部网段(非默认路由)
route-policy OSPF_TO_BGP permit node 10
if-match ip-prefix INTERNAL_NET # 只匹配内部网段
route-policy OSPF_TO_BGP deny node 100
# 3. 内部网段前缀列表
ip ip-prefix INTERNAL_NET permit 10.0.0.0 8 greater-equal 8 less-equal 32
ip ip-prefix INTERNAL_NET deny 0.0.0.0 0 # 拒绝默认路由
# ========== 应用 Route-Policy ==========
ospf 1
import-route bgp route-policy BGP_TO_OSPF # 控制 BGP→OSPF
bgp 65001
import-route ospf 1 route-policy OSPF_TO_BGP # 控制 OSPF→BGP
"""
return border_1_config
def generate_tag_based_config():
"""使用 Tag 标记防止路由反馈"""
config = """
sysname Border-1
# ========== 使用 Tag 防止环路 ==========
route-policy SET_TAG permit node 10
apply tag 100 # 从 BGP 注入 OSPF 的路由打 Tag 100
route-policy FILTER_TAG deny node 10
if-match tag 100 # 拒绝带回 Tag 100 的路由
route-policy FILTER_TAG permit node 20 # 允许其他所有
# ========== 应用 ==========
ospf 1
import-route bgp route-policy SET_TAG # BGP→OSPF 打 Tag 100
import-route bgp route-policy FILTER_TAG # 但是这样不行
# 正确的做法:在 OSPF → BGP 时过滤
bgp 65001
import-route ospf 1 route-policy FILTER_TAG # 拒绝 OSPF 中 Tag=100 的路由
"""
return config
3.2 最佳实践方案
OSPF ↔ BGP 双点重分发最佳实践:
方案一:单向重分发 + 静态默认路由(推荐)
- BGP → OSPF:重分发默认路由 用 route-policy 严格控制 只重分发 0.0.0.0/0 不重分发其他 BGP 路由
- OSPF → BGP:不重分发 内部 OSPF 路由不需要进入 BGP BGP 只和 ISP 交换路由 防止路由反馈的根本方法
- 静态默认路由 + BFD 检测 如果 ISP 链路中断,BFD 检测到后 静态路由自动消失 不会产生黑洞
方案二:双向重分发 + 严格策略(如果必须)
- BGP → OSPF: └─ 使用 prefix-list 只放行 EBGP 路由 └─ 使用 as-path 过滤内部 AS 路由 └─ 设置管理距离(Distance)
- OSPF → BGP: └─ 使用 tag 标记 BGP 注入的路由 └─ OSPF→BGP 时过滤有 tag 的路由 └─ 只重分发内部接口路由(非 OSPF)
- 双点使用相同的策略 └─ Border-1 和 Border-2 配置一致
3.3 自动检测脚本
# detect_route_feedback.py — 路由反馈检测
from netmiko import ConnectHandler
import re
class RouteFeedbackDetector:
"""路由反馈检测器"""
def __init__(self, device_info: dict):
self.conn = ConnectHandler(**device_info)
self.conn.enable()
def check_dual_redistribution(self) -> dict:
"""检测是否存在双向重分发"""
config = self.conn.send_command(
"display current-configuration |"
" section ospf"
)
bgp_to_ospf = "import-route bgp" in config
config = self.conn.send_command(
"display current-configuration |"
" section bgp"
)
ospf_to_bgp = "import-route ospf" in config
return {
"bgp_to_ospf": bgp_to_ospf,
"ospf_to_bgp": ospf_to_bgp,
"dual_redistribution": bgp_to_ospf and ospf_to_bgp,
}
def check_route_feedback(self) -> list:
"""检测路由反馈"""
# 检查 OSPF 路由表中是否有 BGP 来源的路由
ospf_routes = self.conn.send_command(
"display ospf routing"
)
# 检查 BGP 路由表中是否有 OSPF 来源的路由
bgp_routes = self.conn.send_command(
"display bgp routing-table"
)
issues = []
# 关键:检查默认路由的来源
default_bgp = self.conn.send_command(
"display bgp routing-table 0.0.0.0/0"
)
default_ospf = self.conn.send_command(
"display ospf routing 0.0.0.0"
)
# 检查默认路由在 BGP 中的 AS_PATH
for line in default_bgp.splitlines():
if "0.0.0.0/0" in line and "65001" in line:
# 默认路由的 AS_PATH 中包含本 AS → 路由反馈!
issues.append({
"type": "ROUTE_FEEDBACK",
"detail": "默认路由的 AS_PATH 中包含本 AS 号",
"severity": "CRITICAL",
"evidence": line.strip(),
})
self.conn.disconnect()
return issues
def fix_redistribution(self) -> str:
"""修复重分发配置 - 添加过滤策略"""
config_changes = []
# 添加 prefix-list 过滤
config_changes.append(
"ip ip-prefix BGP_TO_OSPF permit 0.0.0.0/0"
)
config_changes.append(
"ip ip-prefix BGP_TO_OSPF deny 0.0.0.0 0 less-equal 32"
)
# 修改 OSPF 配置
config_changes.extend([
"ospf 1",
"import-route bgp route-policy BGP_TO_OSPF_ONLY_DEFAULT",
])
# 创建 route-policy
route_policy = [
"route-policy BGP_TO_OSPF_ONLY_DEFAULT permit node 10",
" if-match ip-prefix BGP_TO_OSPF",
" apply cost 10",
"route-policy BGP_TO_OSPF_ONLY_DEFAULT deny node 100",
]
config_changes.extend(route_policy)
return "\n".join(config_changes)
def close(self):
self.conn.disconnect()
四、验证与监控
4.1 验证方法
修复后的验证:
1. 确认 OSPF 路由表
┌──────────────────────────────────────────┐
│ display ospf routing │
│ │
│ 确认: │
│ └─ OSPF 只有一条默认路由(来自 Border-1)│
│ └─ 没有来自 Border-2 的重复默认路由 │
│ └─ 没有来自 BGP 重分发产生的内部路由 │
└──────────────────────────────────────────┘
2. 确认 BGP 路由表
┌──────────────────────────────────────────┐
│ display bgp routing-table 0.0.0.0/0 │
│ │
│ 确认: │
│ └─ 默认路由的 AS_PATH 不含本 AS 号 │
│ └─ BGP 路由数没有异常增长 │
└──────────────────────────────────────────┘
3. 环路测试
┌──────────────────────────────────────────┐
│ traceroute 外网 IP │
│ │
│ 确认: │
│ └─ 每跳 TTL 正常递增 │
│ └─ 路径不超过 5 跳 │
│ └─ 没有出现来回跳的现象 │
│ │
│ 模拟 ISP 链路断开: │
│ └─ 手动 shutdown 主 ISP 接口 │
│ └─ 确认不会产生路由环路 │
│ └─ 确认正确切换到备用链路 │
└──────────────────────────────────────────┘
五、经验总结
OSPF + BGP 双点重分发关键经验:
1. 避免双点双向重分发
┌─ 双点重分发 = 路由反馈风险
├─ 如果要双向重分发,必须用 route-policy 严格控制
├─ 使用 tag 标记 BGP 注入的路由
└─ 在 OSPF→BGP 时过滤带 tag 的路由
2. 推荐设计
┌─ BGP → OSPF:只注入默认路由
├─ OSPF → BGP:不重分发(或只重分内部接口路由)
├─ 内部路由通过 IGP 传播
└─ 外部路由通过 BGP + 默认路由访问
3. 路由策略检查清单
┌─ 是否配置了 route-policy 控制重分发?
├─ 是否使用了 prefix-list 限定路由范围?
├─ 是否使用了 tag 标记防反馈?
├─ 是否双点配置一致?
└─ 是否验证了 ISP 链路断开场景?
4. 监控建议
┌─ 监控 BGP 路由数量变化
├─ 监控 OSPF 重分发的外部路由数量
├─ 定期检查 AS_PATH 中是否出现本 AS
└─ 定期做故障模拟测试
下篇预告:第338篇《IS-IS微环路分析与解决方案》——深入IS-IS微环路的产生原理、检测方法和防制方案。
下篇预告:第338篇《IS-IS微环路分析与解决方案》——深入IS-IS微环路的产生原理、检测方法和防制方案。