OSPF 这个协议,我前后啃过三遍。第一遍在学校,背下八种邻居状态和五种 LSA 类型,考试能过,但一上设备就懵;第二遍在准备认证,把命令敲得滚瓜烂熟,可真让你说清楚"为什么这条路由选它不选另一条",还是答不上来;第三遍是现网里被一个邻居卡在 ExStart 折腾了半宿,回头翻自己的笔记才发现,当年记的全是结论,没有一条是"为什么"。所以这份 OSPF 复习笔记,我更愿意按"为什么这么设计"来重写一遍,而不是把手册抄一遍。
这篇东西适合谁看?如果你刚接触动态路由,能看懂网络段和掩码,但被 LSDB、ABR、Type3 这些词搞得头晕,那这里的顺序应该比教材友好;如果你已经有几年运维经验,日常配个 area 0 加几条 network 就完事,但遇到多区域汇总、特殊区域、重分发防环就开始翻文档,那第三、四部分大概能对上线;如果你是准备面试的,第五部分的排查表格可以直接当自查清单用。全文不绑定某一家的命令字面,配置片段只是"意思到了"的示意,逻辑是一致的,命令细节各家有差异,按自己设备的语法套即可。
1. OSPF整体设计思路拆解:为什么是链路状态而不是距离矢量
1.1 从"听别人说"到"自己画地图"的思维切换
理解 OSPF,第一步不是记命令,而是把脑子里那套"路由是邻居告诉我的"观念换掉。距离矢量协议(比如 RIP)的工作方式很像问路:我问邻居怎么去某个地方,邻居说"往那边走,六跳",我记下来,再把跳数加一告诉下一个问我的人。问题在于,邻居告诉我的信息是他从别人那里听来的,他自己并没有亲眼见过那条路,一旦网络里出现环路或者某条路断了,这种"传闻"要一圈一圈地传回来才能纠正,中间必然出现计数到无穷和收敛慢的问题。
链路状态协议换了个思路:每台路由器只负责描述自己亲眼看到的东西——我有哪些接口、这些接口连了谁、链路开销是多少,然后把这份"自我描述"泛洪给同一个区域里的所有路由器。所有人都收集齐了,各自手里就有一张完整的区域拓扑图,然后各自独立地跑一遍最短路径算法(SPF,也就是 Dijkstra 算法),算出以自己为根的一棵最短路径树。这个过程的关键差别在于:每个人算路依据的是同一份原始拓扑数据,而不是别人加工过的结论。所以链路状态协议对拓扑变化的反应更快,也不容易出现传闻式的环路,代价是要消耗内存存 LSDB、消耗 CPU 跑 SPF,泛洪本身也要占用带宽。
这就解释了一个常见的困惑:为什么 OSPF 的路由器重启后要等几十秒才能学到路由?因为邻居关系建立、LSDB 同步、SPF 计算,这一整套流程走完才算完事。而 RIP 只要收到一个更新包就能用。这个"慢"换来的是"准"和"稳",是设计上的取舍,不是缺陷。
1.2 区域划分真正在解决的三个问题
单区域 OSPF 在小网络里没问题,但网络一大就顶不住了。假设一个网络有八百台路由器全在 area 0,会发生什么?第一,任何一条链路抖动,产生的 Type1 LSA 要泛洪到全部八百台机器;第二,每台机器的 LSDB 里都存着八百条 Type1 加一堆 Type2,内存占用可观;第三,也是最要命的,任何一次拓扑变化都会让全部八百台机器重跑 SPF,CPU 瞬间打满。
区域划分就是把这一个大盘子切成几个小盘子。拓扑变化的泛洪被限制在本区域内,区域外的路由器根本不知道你这边抖了一下;每台路由器的 LSDB 只需要维护本区域的完整拓扑,其他区域的路由靠 ABR 用 Type3 摘要送进来,条目数从几百条压缩成几十条;SPF 重算的频率和规模都降下来了。
但这里有个很多人没意识到的关键点:OSPF 只在区域内部是纯链路状态,跨区域的部分其实是距离矢量式的行为。ABR 生成 Type3 LSA 的时候,它并不把别的区域的拓扑原样传过去,而是把自己路由表里"我到某个网段的开销是多少"打包成一条摘要发出去。也就是说,区域间的路由是"基于路由的路由",携带的是距离信息而不是拓扑信息。正是因为这个特性,OSPF 才强制规定:所有非骨干区域必须挂在 area 0 上,区域间的流量必须经过 area 0 中转。这条规则不是为了好看,它是靠 area 0 的星型结构来防止区域间路由环路的——如果允许区域两两直连,距离矢量那一套的环路问题就会在区域之间重现。
现实里还有一种情况:某个区域因为历史原因没有直连 area 0,怎么办?用虚链路临时打一条逻辑隧道穿过中转区域。这个我在第 3.6 节会细说,但态度很明确——虚链路是应急手段,不是设计手段,能改物理拓扑就别用虚链路。
1.3 SPF 的计算顺序决定了选路优先级
很多人背过"区域内路由优于区域间路由,区域间优于外部路由",但不知道为什么。答案就在 SPF 的计算顺序里。
路由器收到 LSA 后先放进 LSDB,然后分两步算。第一步,只用 Type1 和 Type2 LSA 构建本区域的拓扑图,以自己为根跑 Dijkstra,得到一棵最短路径树,树上的节点就是本区域的每台路由器和每个广播网段。这一步算出来的,是区域内路由(路由表里显示为 O 或者 OSPF)。
第二步,在这棵树的基础上挂"叶子":Type3 是 ABR 送来的其他区域网段,挂在"到那个 ABR 的最短路径"下面;Type5 是 ASBR 送来的外部网段,挂在"到那个 ASBR 的最短路径"下面(Type4 的作用就是先告诉你 ASBR 在哪)。因为第一步的树已经算完了,第二步只能往上加,不可能反过来覆盖第一步的结果。所以区域内路由天然优先于区域间,区域间天然优先于外部,这不是谁规定的优先级数值,而是算法结构的必然结果。
顺带说一个实操中经常被问的问题:为什么我配了两条等价路径,只有一条生效?先看开销是否真的相等,再看是不是一条区域内一条区域间——不同来源的路由,即使开销一样也不会做等价负载,因为它们的"可信度"不在一个层级上。
2. 核心机制细节解析:邻居、LSDB 与 LSA 家族
2.1 邻居建立的八个状态与各自的卡点
邻居关系是 OSPF 的地基,八个状态机必须背熟,但更重要的是知道每个状态"卡住"意味着什么。我按顺序拆一遍。
Down是初始状态,什么报文都没收到。Init表示收到了对方的 Hello,但对方发来的邻居列表里没有我的 Router ID——说明对方还没听见我,是单向通信。2-Way表示双方都在对方的邻居列表里了,双向通了。这里有个必须记住的细节:在广播型网络里,非 DR/BDR 的路由器之间会稳定停留在 2-Way,这是正常现象,不是故障。因为它们之间不需要交换 LSA,只需要和 DR/BDR 建立完全邻接就行。判断标准是看 DR/BDR 和其他路由器的关系是否到了 Full。
ExStart开始协商主从关系,用空的 DBD 报文比 Router ID,大的当主。这里卡住九成是MTU 不一致——DBD 报文里带了接口 MTU,两边对不上就不肯往下走。这种场景特别常见于一边是千兆口一边是百兆口,或者中间隔了隧道。Exchange是互相发送 DBD 描述自己的 LSDB 摘要。Loading是根据对方摘要发现自己缺哪些 LSA,发 LSR 去要。Full是双方 LSDB 完全同步。
我把常见卡点整理成一张表,排查的时候按这个顺序看就行:
| 卡住的状态 | 最常见原因 | 验证手段 |
|---|---|---|
| 一直 Down | 接口没起、没使能 OSPF、Hello 报文被 ACL 挡了、组播不通 | 看接口状态、抓包看有没有 224.0.0.5 的 Hello |
| Init | 单向通信,一方收到 Hello 但另一方没收到 | 检查单向链路、ACL、光模块收发光 |
| 2-Way(非 DR/BDR 之间) | 正常现象,无需处理 | 确认双方都不是 DR/BDR 即可 |
| 2-Way(应该建立邻接却卡住) | 优先级都是 0、或者 DR 选举被人为干预 | 看接口优先级配置 |
| ExStart | MTU 不一致、Router ID 冲突 | 比对两端接口 MTU、检查 Router ID 唯一性 |
| Exchange | MTU、LSA 头部异常、链路质量差导致丢包 | 看接口错误计数、CRC 增长 |
| Loading | LSR 发出去没回应,通常是单向丢包 | 抓包看 LSR/LSU 是否成对出现 |
邻居建立的前提条件一共六条,缺一条都起不来:Router ID 不能重复、区域 ID 必须一致、认证方式和密钥必须一致、Hello 和 Dead 定时器必须一致、接口 MTU 要匹配(部分实现在 DBD 阶段校验)、广播网络里掩码要一致。另外还有一条容易被忽略的:Stub 标志位。一个区域被配成 Stub,区域内的所有路由器都必须配成 Stub,只要有一台没配,它发出的 Hello 里 Stub 位是 0,其他路由器就会拒绝和它建邻居。
2.2 LSA 类型与区域边界的分工
LSA 是 OSPF 的"信息载体",五种常用类型各有明确的分工,理解了分工就理解了区域边界在哪。
| 类型 | 名称 | 谁产生 | 泛洪范围 | 描述内容 |
|---|---|---|---|---|
| Type1 | Router LSA | 每台路由器 | 本区域 | 自己的接口、链路、开销、邻居 |
| Type2 | Network LSA | DR | 本区域 | 广播网段上有哪些路由器 |
| Type3 | Summary LSA | ABR | 除本区域外的其他区域 | 我这边有个网段,从我这儿过去要多少开销 |
| Type4 | ASBR Summary | ABR | 除本区域外 | ASBR 在哪,怎么过去 |
| Type5 | External LSA | ASBR | 整个 AS(Stub/NSSA 除外) | 外部路由及其开销类型 |
| Type7 | NSSA External | NSSA 内的 ASBR | 只在 NSSA 内 | 外部路由,到 ABR 处可转成 Type5 |
一个容易混淆的点:Type3 里携带的"开销"到底是谁到谁的开销?是 ABR 到那个目标网段的开销,不是源路由器到目标的开销。所以源路由器算出来的总开销 = 自己到 ABR 的开销 + Type3 里携带的开销。这就解释了为什么区域间路由在 ABR 处会出现"开销跳变"——因为那是两段独立计算的结果相加。
Type4 的存在感最低,但少了它外部路由就算不出来。因为 Type5 只告诉你"外部网段在 ASBR 后面",你得先知道 ASBR 在哪才能算出到 ASBR 的最短路径,Type4 就是干这个的。如果 ASBR 就在本区域,Type4 不需要,因为 Type1 里已经有它了。
2.3 DR/BDR 选举的真相与常见误解
广播型网络(比如以太网)上如果五台路由器两两建邻接,需要十条邻接关系,每台机器的 LSDB 同步都要来一遍,效率极低。DR/BDR 机制就是选一个"代言人",所有路由器只和 DR/BDR 建 Full,彼此之间保持 2-Way,邻接数量从 n(n-1)/2 降到 n-1。
选举规则不复杂:先比接口优先级(0 到 255,默认 1),大的赢;优先级相同比 Router ID,大的赢。Router ID 的比法是先比数值,数值相同再比接口 IP。但有三条规则必须记牢,这三条是实际排障中最容易踩的:
第一,优先级为 0 表示不参与选举。这是排除某台设备当 DR 的标准做法,配置比记命令更重要的是记住这个语义。第二,选举是非抢占的。DR 一旦选出来,除非它挂了或者接口 down 了,新加入一台优先级更高的路由器也不会抢走 DR 身份。想让高优先级设备当 DR,只能重启 OSPF 进程或者把现有 DR 的接口先关再开。第三,选举发生在 2-Way 状态之后、ExStart 之前,等待时间等于 Dead 间隔,所以刚上电的那几十秒里看到的 DR/BDR 字段可能是临时的,别急着下结论。
还有一个常被忽略的细节:DR 使用 224.0.0.6 这个组播地址接收所有 DRother 发来的 LSA 更新,而 DRother 用 224.0.0.5 发送。抓包的时候如果只过滤 224.0.0.5,会看不到 DR 发出的部分流量,容易误判成"DR 不回应"。
2.4 开销计算与参考带宽那个绕不开的坑
OSPF 接口开销的公式很简单:开销 = 参考带宽 ÷ 接口带宽。参考带宽默认是 100Mbps。于是百兆口开销是 1,千兆口开销也是 1,万兆口还是 1——因为结果不足 1 的都取 1。这意味着在默认配置下,千兆链路和万兆链路在 OSPF 眼里完全没有区别,选路时无法体现带宽差异。这是实际项目里非常高频的一个坑:明明上了万兆链路,流量却还是走千兆,因为开销一样,最后按 Router ID 或者先到先得选了路径。
解决方法是在全区域所有路由器上统一修改参考带宽,比如改成 10000(单位 Mbps),那么万兆口开销 1、千兆口开销 10、百兆口开销 100,差异就出来了。注意"统一"两个字——如果只改了一部分设备,两边的开销基准不一样,算出来的路径会非常诡异,而且这种问题极难发现,因为每台设备自己看自己都是对的。
除了改参考带宽,还可以直接在接口上手工指定开销值。手工指定适合精细化控制场景,比如想让流量走某条链路做备份,就把主链路开销调小、备份链路开销调大。但手工值的可维护性差,我的建议是:全网统一改参考带宽做基础,个别链路需要特殊控制时再手工覆盖,并且在变更记录里写清楚原因,否则半年后没人记得为什么这个接口的开销是 5 而不是 10。
3. 实操过程:从单区域到多区域的完整落地
3.1 基础配置与 Router ID 的前置规划
配置 OSPF 之前,先做规划,别上来就敲命令。规划的第一件事是 Router ID。Router ID 是个 32 位数值,格式像 IP 地址,作用是在协议里唯一标识一台路由器。如果不手工指定,设备会自动从接口地址里选一个——通常是最大的 Loopback 地址,没有 Loopback 就选最大的物理接口地址。自动选举的问题是:接口一旦 down 或者地址变了,Router ID 可能跟着变,而 Router ID 变化会导致邻居关系重建,是一场无谓的震荡。
所以规范做法是:每台设备配一个 Loopback 接口作为管理地址,把这个地址手工指定为 Router ID,全网规划一个网段专门放 Loopback,保证唯一。这套规划在设备上线前就该定好,事后补救很麻烦。
基础配置示意如下(命令字面各厂商有差异,逻辑一致):
# 全局启动 OSPF 进程,进程号本地有效 ospf 1 router-id 10.255.0.1 # 创建 Loopback 接口作为 Router ID 来源 interface LoopBack0 ip address 10.255.0.1 255.255.255.255 # 进入区域 0,宣告本区域直连网段 area 0.0.0.0 network 10.0.0.0 0.0.0.255 network 10.255.0.1 0.0.0.0这里要强调一点:宣告网段用的是反掩码(或者叫通配符掩码),0 表示必须匹配,1 表示任意。0.0.0.255匹配整个 10.0.0.0/24 网段,0.0.0.0精确匹配单个地址。新手最容易犯的错是把子网掩码直接填进去,结果宣告了整个大网段出来,把不该放进去的接口也带进了 OSPF,路由表里多出一堆莫名其妙的条目。
还有一个实践细节:宣告范围尽量精确到接口,不要图省事写network 10.0.0.0 0.255.255.255一把梭。这种写法会把所有 10 开头的接口都塞进 OSPF,包括互联地址和业务地址,不仅产生大量无用 LSA,还会在重分发和汇总的时候出问题。
3.2 多区域划分与 ABR、ASBR 的角色落地
多区域的典型划分思路是按地理或者按业务。比如一个园区网,核心和汇聚跑 area 0,每个楼栋一个区域,办公区 area 1、生产区 area 2、访客区 area 3。划分粒度没有标准答案,经验值是单个区域的路由器数量控制在几十台以内,超过这个量级就考虑再切一刀。
ABR 是连接两个及以上区域的路由器,硬性要求是至少有一个接口在 area 0。这个要求不是形式主义,如果一个路由器连接了 area 1 和 area 2 但不在 area 0,它虽然也能学到两个区域的路由,但不会为对方区域生成 Type3,两个区域之间的路由就断了。配置上,ABR 就是把多个区域的 network 都宣告上去:
ospf 1 router-id 10.255.0.2 area 0.0.0.0 network 10.0.0.0 0.0.0.255 area 0.0.0.1 network 10.1.0.0 0.0.0.255ASBR 是把外部路由(静态路由、直连、其他协议的路由)引入 OSPF 的路由器。引入动作叫重分发,配置上通常在 ASBR 上做:
ospf 1 router-id 10.255.0.9 import-route static import-route direct default-route-advertise always重分发这块有个绕不开的坑:默认情况下,一些实现只重分发主类网络,不加subnets之类的参数,明细子网会被丢掉。不同实现的参数名不一样,但思路是一样的——一定要确认子网被完整引入了。验证方法很简单,去远端路由器上display ospf lsdb看 Type5 LSA 的条目数,和你预期引入的网段数对不上就是漏了。
3.3 路由汇总的两种玩法与汇总点选择
OSPF 有两种汇总,位置和作用都不一样,混起来就出错。
第一种是区域间路由汇总,在 ABR 上做,把某个区域的明细网段汇总成一条,用 Type3 送进其他区域。配置形如area 1 range 10.1.0.0 255.255.0.0。这条命令的意思是:对于 area 1 里的所有 10.1.x.x 网段,往其他区域宣告的时候合并成 10.1.0.0/16 一条。注意它只影响"往其他区域发",area 1 内部还是能看到明细。
第二种是外部路由汇总,在 ASBR 上做,把多条 Type5 合并,配置形如summary-address 10.2.0.0 255.255.0.0。这个动作发生在 ASBR 生成 Type5 的时候,合并后的 LSA 泛洪到整个 AS。
汇总点怎么选?原则是"离明细最近的地方汇总"。区域间汇总就在 ABR 上,外部汇总就在 ASBR 上。如果你在离明细很远的地方做汇总,明细 LSA 已经泛洪了一大圈才被合并,省下的资源有限。
汇总的经典副作用是黑洞路由。假设 area 1 有 10.1.1.0/24 到 10.1.200.0/24,你汇总成 10.1.0.0/16。如果 10.1.50.0/24 这个网段实际上不在 area 1,或者被删了,其他区域的路由器看到汇总路由还是会往 ABR 发,ABR 本区域没这条明细,只能丢包。所以汇总之前必须确认:汇总范围内的所有明细网段都真实存在,而且都在同一个区域内。不连续的网段千万别硬汇总,宁可多几条明细。
3.4 特殊区域:Stub、NSSA 与默认路由注入
特殊区域的存在目的只有一个:把 LSDB 里的外部 LSA 干掉,省内存省 CPU。但各种类型的取舍不同,得分清楚。
Stub 区域:拒绝 Type5 和 Type4,ABR 会向区域内注入一条 Type3 的默认路由。适用场景是末梢区域——只有一个出口、不需要外部路由,所有出区域流量走默认路由就行。配置上,区域内所有路由器都要配stub,只要有一台漏配,邻居就建不起来(Hello 里的 Stub 位不一致)。
Totally Stubby 区域:在 Stub 基础上进一步屏蔽 Type3,区域内只剩下默认路由和本区域明细。这个更进一步,但要注意它是 C 厂商的叫法,另一家的实现里是通过stub no-summary之类的参数达到同样效果。配置时只在本区域的 ABR 上做,区域内其他路由器配普通的 stub 就行。
NSSA 区域:允许 Type7 存在,也就是允许区域内部有 ASBR 引入外部路由,但仍然不接受 Type5。典型场景是区域需要一个本地出口(比如本地有一条专线要引进来),同时又不想让全网的 Type5 涌进来。NSSA 的 ABR 可以在 Type7 转 Type5 的时候做转换,还可以控制转换后的开销和转发地址。
Totally NSSA:NSSA 加上屏蔽 Type3,只保留默认路由和区域内部路由。
这四种类型的组合在生产网里非常常见,但有个细节必须提醒:骨干区域不能是任何特殊区域。area 0 必须保持普通类型,因为它要承载所有 Type3 和 Type5 的中转。我见过有人图省事把 area 0 配成 stub,结果全网外部路由瞬间消失,排查了半天才发现是这个原因。
3.5 认证、被动接口与基础安全加固
OSPF 本身没有加密能力,但认证能防止非法设备接入。认证分两种:明文认证和密文认证。明文认证的密码在报文里裸奔,抓包就能看到,只能防误接入,不能防恶意;密文认证用 MD5 或更强的哈希算法,相对可靠。
认证可以在区域层面配,也可以在接口层面配。区域认证的好处是一次配置覆盖整个区域,维护成本低;接口认证的好处是粒度细,可以对不同邻居用不同密钥。实际项目里我一般用接口认证配合密钥轮换,尤其是和第三方对接的链路,每一条单独配。
被动接口是个特别实用的小功能:配置之后,这个接口不发 Hello 报文,但它宣告的网段仍然会出现在 LSDB 里。这就完美解决了"用户接入网段要宣告,但不想让终端收到 Hello 报文"的问题。接入层的 VLAN 接口如果不配被动,每个 VLAN 都在往下面发组播 Hello,不仅浪费带宽,还会被某些终端的安全软件当成异常流量告警。
# 接入接口设为被动,只宣告不发 Hello ospf 1 silent-interface Vlanif10 silent-interface Vlanif11配置命令的字面各厂商不同,有的叫passive-interface,有的叫silent-interface,语义是一样的。
3.6 虚链路的应急用法与它的代价
虚链路是给"区域没有物理直连骨干"这个历史遗留问题开的后门。比如一个区域是早期规划时留下的,它的上联路由器所在区域没有直连 area 0,中间隔了一个中转区域。这时候可以在两台 ABR 之间穿过中转区域打一条逻辑链路,让那个区域"逻辑上"挂到 area 0 上。
配置方式是两端的 ABR 互相指定对方的 Router ID,并指定穿过哪个中转区域:
# 在 ABR-A 上 area 1 vlink-peer 10.255.0.22 # 在 ABR-B 上 area 1 vlink-peer 10.255.0.21几个约束必须记住。第一,虚链路穿过的中转区域必须有到对方的完整路由,而且这个区域不能是 Stub 或 NSSA,因为虚链路的报文是单播的,Stub 区域的路由能力受限。第二,虚链路两端的路由器必须都是 ABR,而且都要有接口在骨干区域。第三,虚链路的开销等于穿过中转区域的路径开销,选路时是算进去的。
我的态度很明确:虚链路能不用就不用。它是应急和过渡手段,长期保留会让网络拓扑变得难以理解,出故障时排查路径也会绕晕。正确做法是改造物理连接,让那个区域真正上联到骨干。
4. 收敛与性能调优:让 OSPF 在大网里跑得住
4.1 SPF 与 LSA 的节流参数
网络规模上去之后,最怕的是"震荡放大"。一条链路反复 up/down,每次抖动都触发一次 SPF 重算,几百台路由器同时算,CPU 直接跪。节流(throttling)机制就是给 SPF 计算加一个"冷却时间",避免短时间内反复计算。
节流参数一般有三个:首次等待时间、第二次等待时间、最大等待时间。逻辑是:第一次触发立刻算,但如果短时间内又来一次,就等一会儿再算;连续触发的话等待时间翻倍递增,直到上限。默认值不同实现有差异,常见的配法是 5 秒、1000 毫秒、10000 毫秒这个量级,意思是首次等 5 秒,后续从 1 秒开始翻倍,最多等 10 秒。
除了 SPF 节流,还有 LSA 生成节流。一条链路抖动,路由器会重新生成 Type1 LSA,如果抖得太快,LSA 生成也要限速,避免泛洪风暴。
这两个参数在中小网络里基本不用动,默认值够用。但在几百台规模、且链路质量不稳定的环境里(比如无线回传、电力线载波),调大节流参数能明显降低 CPU 峰值。代价是收敛变慢,所以要权衡。
4.2 大规模网络下的 LSA 数量控制
LSA 数量是 OSPF 性能的核心指标。一台路由器的 LSDB 里有几千条 LSA,SPF 计算时间会显著上升。控制手段有这么几个,按效果排序。
最有效的是汇总。一个区域如果有两百个 /24 网段,不汇总就是两百条 Type3 泛洪到所有区域;汇总成一条 /16,泛洪量直接降两个数量级。所以大规模网络里,ABR 上一定要做区域间汇总,ASBR 上一定要做外部汇总。
其次是合理划分区域。区域越小,单个区域内的 Type1/Type2 越少,SPF 计算越快。但区域划分太细又会导致 ABR 数量增多、Type3 数量上升,是个平衡问题。
第三是控制重分发范围。只把必要的路由引进来,不要图省事把整张路由表都 import。我见过把 BGP 全表引进 OSPF 的配置,几万条 Type5 泛洪下去,整个域内的路由器 LSDB 直接爆掉。外部路由该用 BGP 传的就用 BGP 传,OSPF 只承载域内和必要的少量外部。
第四是特殊区域,前面讲过,用 Stub 或 NSSA 把 Type5 挡在区域外面。末梢区域用这个手段最合适。
4.3 重分发的防环设计与路由标记
OSPF 和别的协议互相重分发,最怕的是"我引你的,你再引回来",形成路由环路或者次优路径。防环有几个手段,我一般组合使用。
路由标记(tag)是最常用的一招。在引入的时候给路由打上标记,在另一个方向引入的时候用策略匹配标记并拒绝。比如把静态路由引进 OSPF 时打 tag 100,那么从 OSPF 往别的协议引的时候,遇到 tag 100 的直接过滤掉,避免绕一圈回来。
双向重分发点收敛到一处。如果两个协议之间有两个重分发点,路由可能在两个点之间来回跳,形成次优路径。解决办法是用管理距离(优先级)做单向压制:让其中一个重分发点只做单向引入。不同实现的优先级数值不一样,主流的两套体系里,OSPF 的默认优先级分别是 110 和 10,静态路由分别是 1 和 60,需要根据实际情况调整,保证路由来源唯一。
用分发列表或者路由策略精确控制。只允许特定的前缀通过,白名单机制比黑名单可靠。黑名单的问题是新增网段容易漏掉,白名单则是"默认拒绝",安全得多。
外部路由的开销类型也要注意。E1 类型的开销是外部开销加内部路径开销累加,E2 类型默认只算外部开销(默认值 20),不随内部路径变化。默认是 E2。如果希望选路体现内部距离差异,应该用 E1;如果希望外部路由的开销固定、不受内部拓扑影响,用 E2。这个选择在多出口场景下直接决定流量走哪个出口,选错了就是次优路径。
5. 常见问题与排查技巧实录
5.1 邻居起不来的分层排查法
邻居起不来是最高频的问题,我的排查顺序是固定的,从下往上。
第一步看物理和二层。接口 up 了吗?光模块收发光正常吗?VLAN 通不通?这些问题看起来低级,但实际占比不低。有一次排查了半小时协议配置,最后发现是对端接口被 shutdown 了。
第二步看三层可达性。两端接口地址在不在同一个网段?掩码一致吗?有没有 ACL 挡了 224.0.0.5 和 224.0.0.6?组播不通的话 Hello 根本发不出去。用 ping 测试的时候注意,普通 ping 走的是单播,不能证明组播通,得实际抓包看有没有 Hello 报文。
第三步看参数匹配。区域 ID、认证、Hello/Dead 定时器、Stub 标志、MTU,这五项逐一比对。我习惯用两条命令快速比对:display ospf interface看本端参数,display ospf peer看邻居状态和失败原因。有些实现会直接显示"邻居因某某原因被拒绝",这个提示非常有用,别忽略。
第四步看 Router ID 冲突。两台设备 Router ID 相同,邻居关系会反复建立又断开,日志里会有明确的冲突提示。这种情况多是复制配置时忘了改。
5.2 路由学到了但业务不通的典型场景
OSPF 邻居 Full,路由表里也有条目,但业务不通,这个问题比邻居起不来更隐蔽。常见原因有四个。
单向路由。A 学到了去 B 的路由,B 没学到去 A 的。多出现在区域边界配置不对称,比如一边做了汇总一边没做,或者一边是 Stub 一边不是。验证方法是两端各自查路由表,对比是否对称。
汇总导致的黑洞。前面讲过,汇总范围里包含了实际不存在的网段,流量发过去就被丢了。排查方法是去 ABR 上display ospf lsdb看汇总路由,再对比本区域的明细路由,看是否有"汇总里有、明细里没有"的网段。
MTU 导致的转发异常。有些场景下邻居能建立,小包能通,大包不通。这是路径 MTU 不一致导致的,不是 OSPF 本身的问题,但表现上很像路由问题。用带 DF 标志位的大包 ping 一下就能验证。
过滤策略误伤。接口上或者区域上配了过滤,把该放行的路由挡了。这类问题在接手别人维护的网络时特别常见,一定要先看有没有隐藏的策略配置。
5.3 特殊区域与汇总的高频翻车点
特殊区域这块的坑集中在"配置不一致"和"预期不符"两类。
配置不一致的典型表现是邻居卡在 Init 或者直接起不来,因为 Hello 报文里的 Stub 标志位对不上。整改方法是区域内所有路由器统一配置,别漏掉任何一台。新增设备上线时,模板里要带上特殊区域的配置,否则就是定时炸弹。
预期不符的典型表现是"我配了 Stub,为什么还能看到外部路由"。原因通常是:这台路由器本身是 ASBR 或者 ABR,它自己产生的路由不受 Stub 限制;或者这条外部路由是从别的区域通过 Type3 传过来的,不是 Type5。要分清"Type5 被拒绝"和"外部路由完全看不到"是两回事。
另一个高频问题是Totally Stubby 配错位置。这个配置只能在 ABR 上做,如果配在普通路由器上,它不产生 Type3,配置了也没用,只会让人误以为生效了。
5.4 排查速查表与几条私房经验
把前面散落的判断点整理成一张表,出问题的时候按行扫一遍,能覆盖八成场景。
| 现象 | 优先怀疑 | 快速验证 |
|---|---|---|
| 邻居一直 Down | 接口未使能、ACL 挡组播、地址不同网段 | 抓包看有无 Hello,display ospf interface |
| 邻居卡 Init | 单向通信、单向 ACL、光路单通 | 双向抓包对比 |
| 邻居卡 ExStart | MTU 不一致、Router ID 冲突 | 比对接口 MTU,查 Router ID |
| 邻居卡 Exchange/Loading | 链路丢包、LSA 异常 | 看接口 CRC 和丢包计数 |
| 邻居频繁 Up/Down | 链路震荡、Dead 定时器太短、CPU 过载 | 查接口日志和 CPU 历史 |
| 有路由但不通 | 单向路由、汇总黑洞、过滤策略 | 两端路由表对比 |
| 负载分担不生效 | 开销不等、路由来源不同 | 看两条路由的 cost 和类型 |
| 外部路由时有时无 | 重分发配置被覆盖、路由策略抖动 | 查 ASBR 的引入配置和日志 |
最后分享几条踩出来的经验。第一,改参考带宽一定要全网统一,哪怕只漏一台,选路就可能出鬼,而且这种问题不会报错,只能靠人工核对。第二,汇总前先确认网段连续性,不连续的网段做汇总迟早出事。第三,虚链路当作临时方案登记在案,写上什么时候加的、什么条件下拆除,不然三年后没人敢动。第四,邻居状态异常的日志一定要开,很多问题事后复盘全靠日志,现场排查时反而看不出所以然。
这套笔记我每隔一段时间会翻一遍,每次都能发现之前理解偏了的地方。OSPF 这个协议的特点是表面简单、细节极多,配置能跑通和真正理解它之间隔着大量的踩坑。我现在判断一个人是不是真懂 OSPF,不问 LSA 有几种,就问他一句:为什么区域间一定要过 area 0。能把这个说清楚,基本上就算入门了。