OSPF这三个字母,大多数人第一次见到它是在一台设备的配置界面里,翻到router ospf那一行,然后被network 10.0.0.0 0.0.0.255 area 0这种反掩码写法劝退。我当年也是这样,能敲通配置、能 ping 通,但真被问到"为什么这条路由走这边不走那边"、"为什么邻居卡在 ExStart 不动",就只能靠重启碰运气。后来做过的园区网、多分支互联、机房双出口改造多了,才慢慢把 OSPF 从"一堆要背的命令"变成"一套可以推理的模型"。
这篇东西讲的是 OSPF 协议基础,但我不会按教材顺序从术语表开始念。我想干的事情是:把 OSPF 当成一个链路状态型内部网关协议,拆开看它到底在解决什么问题、每个机制为什么长成这样、配置的时候哪些参数是会真出事的、出了故障按什么顺序查。适合刚接手网络运维、正在啃路由协议、或者从静态路由和 RIP 那一套转过来的人看,也适合已经会敲配置但说不清原理的人回头补课。看完至少能做到两件事:第一,给你一个拓扑你能独立配通并且验证;第二,邻居起不来或者路由不对的时候,你知道先去哪几个地方看一眼,而不是盲改。
1. 为什么选 OSPF:从选路需求反推协议设计
1.1 静态路由的天花板在哪里
先说清楚动态协议不是天然的必需品。一个只有三台设备、出口单一的小网络,静态路由配两条就完事,稳定、可控、排错简单,没有理由上动态协议。问题出在规模上去之后。
假设一个网络里有 N 台路由设备需要两两互通,全用静态路由,理论上要维护的路由条目量级是 N×(N-1)。10 台设备就是 90 条,20 台是 380 条。这还只是数量,真正要命的是变更成本:任何一条链路断了、任何一台设备加进来,你都得登录到所有相关设备上逐条改。改十条能忍,改三百条必然出错,而路由配错往往是全网级别的故障。
再往下想一层,静态路由还有一个隐性缺陷:它没有"感知"能力。链路物理上还亮着,但中间的传输设备丢了包,静态路由依然会往那个方向送,直到有人发现。动态协议的价值就在这儿——它让设备之间互相交换拓扑信息,链路出问题时能自己算出一条新路径。
所以选型的判断标准其实很简单:拓扑会不会变、规模会不会涨、有没有冗余链路需要自动切换。三个里占两个,就该考虑动态协议了。
1.2 链路状态和距离矢量:两种完全不同的思路
动态路由协议分两大流派,理解这个分歧比背 OSPF 的命令重要得多。
距离矢量(比如 RIP)的思路是"问路"。每台设备只知道邻居告诉它的信息:到某个网段多远、往哪个方向走。它不需要知道全网长什么样,只需要相信邻居。这种模式的问题是信息会失真——A 告诉 B,B 加工一下告诉 C,C 再告诉 D,中间任何一环理解错了,错误就会被放大。经典的路由环路、计数到无穷,根源都在这里。虽然可以用水平分割、毒性反转、触发更新这些手段去缓解,但那是打补丁,不是从根上解决。
链路状态(OSPF、IS-IS)的思路是"每个人都拿一张完整地图"。每台设备把自己直连的链路状态(我连着谁、这条链路开销多少)打包成 LSA 泛洪出去,所有设备收集齐了,各自在本地建一个一模一样的拓扑数据库(LSDB),然后用 Dijkstra 算法独立算最短路径树。因为大家的地图是同一份,算出来的结果不会互相矛盾,天然无环。
代价也很明确:内存要装 LSDB,CPU 要跑 SPF 计算,带宽要用来泛洪。设备多了、拓扑抖了,这三样都会吃紧。这就引出了 OSPF 最关键的一个设计——分层。
1.3 区域设计到底在省什么
单区域的 OSPF 全网只有一个 LSDB。任何一条链路抖动,所有设备都要重新收 LSA、重新跑 SPF。一百台设备的网络里,一根网线松一下,全网 CPU 抖一轮,这是不可接受的。
区域(Area)的作用就是把一个大网络切成若干块,区域内拓扑变化只在本区域泛洪,不扩散到其他区域。区域边界上的设备叫 ABR(区域边界路由器),它一边连骨干区域,一边连普通区域,把区域内的明细路由汇总成一条摘要路由通告出去。对区域外的人来说,不需要知道你这个区域内部有多少台设备、多少条链路,只要知道"去那边从我这个口走,开销是多少"就够了。
这个设计有个硬性规矩:所有非骨干区域必须直接或间接连到骨干区域 Area 0。原因在于区域间的路由是靠 ABR 从 Area 0 学到的,如果两个普通区域直接对接,ABR 之间没有公共区域可以中转路由信息,就会出问题。真遇到了不得不用的情况,可以用虚链路(Virtual Link)在逻辑上把区域拉通,但那是权宜之计,能重新规划拓扑就别用。
1.4 几种协议怎么选
常见的选择其实就那么几个,我把实际项目里的判断依据列一下:
| 协议 | 类型 | 适用场景 | 主要代价 |
|---|---|---|---|
| 静态路由 | 手工 | 小网络、单出口、末梢网段 | 变更成本高,无故障感知 |
| RIP | 距离矢量 | 基本只剩教学和老设备兼容 | 跳数限制 15,收敛慢 |
| OSPF | 链路状态 | 中大型企业网、多厂商混跑、需要快速收敛 | 配置复杂度中等,LSDB 占资源 |
| IS-IS | 链路状态 | 运营商骨干、超大规模 | 概念抽象,排错门槛高 |
| EIGRP | 混合型 | 单一厂商环境 | 多厂商互通性差 |
| BGP | 路径矢量 | 跨自治域、策略路由 | 收敛慢,配置重策略轻拓扑 |
多厂商混跑这个条件很关键。OSPF 是开放标准,任何一家的设备都能对接,这是它在企业网里活下来的核心原因之一。EIGRP 技术上很优秀,收敛快、配置简洁,但跨厂商就断了,一旦网络里有两家设备,它就用不了。
2. 核心机制拆解:邻居、LSA 和 SPF
2.1 五种报文与邻居状态机
OSPF 的所有交互都靠五种报文完成,理解这五种报文的分工,排错的时候就有方向感了。
- Hello:周期发送,用来发现邻居、维持邻居关系、选 DR/BDR。它不带拓扑信息,纯粹是打招呼。
- DBD(数据库描述):交换阶段用,概括性地告诉对方"我有哪些 LSA",相当于先报目录。
- LSR(链路状态请求):看完目录发现自己缺哪些,就发请求要具体的。
- LSU(链路状态更新):真正的数据快递,LSA 就装在里头发出去。
- LSAck:确认收到,保证可靠传输。
邻居建立要经过七个状态,这条链路是排错的主干道:
| 状态 | 含义 | 卡在这里通常意味着 |
|---|---|---|
| Down | 没收到任何 Hello | 接口没起、链路不通、没开 OSPF |
| Init | 收到 Hello 但对方邻居列表里没有我 | 单向通信、认证一端配了一端没配 |
| 2-Way | 双向确认 | 广播网络中非 DR/BDR 之间停在这里是正常的 |
| ExStart | 协商主从关系、确定 DBD 序列号 | MTU 不一致是头号嫌疑人 |
| Exchange | 交换 DBD 摘要 | 报文丢失、链路质量差 |
| Loading | 请求缺失的 LSA | LSA 请求发不出去或回应不来 |
| Full | 数据库完全同步 | 到这才算真正建立邻接 |
Hello 报文里有一堆字段必须双向一致,否则邻居起不来:Hello 间隔、Dead 间隔、区域 ID、认证类型和密钥、Stub 区域标志。这些不是"建议一致",是硬性门槛。广播型网络默认 Hello 10 秒、Dead 40 秒;点到点和 NBMA 类型默认 Hello 30 秒、Dead 120 秒。两端接口网络类型不一致,间隔就会对不上,邻居直接停在 Down。
提示:Dead 间隔默认是 Hello 间隔的 4 倍,这个比例改动的时候要一起改,只改一个会导致邻居频繁震荡,而且现象很隐蔽——日志里反复出现邻居建立又断开,但每次都能短暂 Full 一下。
2.2 DR/BDR 选举:为了省掉多少邻接
广播网络(比如一个交换机下挂多台路由器)有个数学问题。N 台设备两两建立 Full 邻接,需要 N×(N-1)/2 条邻接关系。10 台设备就是 45 条,每条邻接都要同步 LSDB,泛洪量会爆掉。
DR/BDR 机制就是把"两两同步"改成"大家跟 DR 同步"。同样的 10 台设备,非 DR 之间只维持 2-Way,只跟 DR、BDR 建立 Full,邻接数量降到 N-1,也就是 9 条。BDR 是备份,DR 挂了它顶上,避免重新选举导致长时间中断。
选举规则只有两条,按顺序比:
- 接口优先级大的赢,默认 1,范围 0-255,配成 0 表示放弃选举。
- 优先级相同,比 Router-ID,大的赢。
这里有个很多人踩过的坑:选举是非抢占的。DR 一旦选出来,后来接入一台优先级更高的设备,它也不会抢走 DR 身份,除非 DR 失效或者接口重置。这也意味着如果你改了优先级想让它生效,得把相关接口都重置一次 OSPF 进程。
举个实际的例子。某机房两台核心设备接同一台交换机,Router-ID 分别是 10.255.255.1 和 10.255.255.2,接口优先级都是默认 1。按规则 10.255.255.2 更大,它当 DR。这时候如果运维不指定 Router-ID,让它自动取接口 IP,某次接口地址调整后 Router-ID 变了,DR 就可能换人,虽然一般不影响转发,但收敛期间会有短暂抖动。所以生产环境一定手工指定 Router-ID,这是几乎零成本的操作。
2.3 LSA 类型与 LSDB
LSA 是 OSPF 传递拓扑信息的基本单位,几种常见的类型必须分清楚,否则看 LSDB 的时候会一头雾水:
| 类型 | 名称 | 谁产生 | 泛洪范围 | 描述内容 |
|---|---|---|---|---|
| Type 1 | Router LSA | 每台路由器 | 本区域 | 我有哪些接口、连了谁、开销多少 |
| Type 2 | Network LSA | DR | 本区域 | 这个广播网段上挂了哪些路由器 |
| Type 3 | Summary LSA | ABR | 跨区域 | 我这边某个网段可达,开销多少 |
| Type 4 | ASBR Summary | ABR | 跨区域 | 去某个 ASBR 怎么走 |
| Type 5 | External LSA | ASBR | 全 AS | 外部引入的路由 |
| Type 7 | NSSA External | NSSA 内 ASBR | 本区域 | NSSA 区域的外部路由,由 ABR 转成 Type 5 |
理解这张表的关键在于泛洪范围。Type 1 和 Type 2 是区域内的"原始拓扑",出了区域就看不到了;Type 3 是 ABR 加工后的"摘要",只告诉你方向和开销,不告诉你细节。这也解释了为什么区域外的人看不到你区域内部的拓扑变化——他们眼里只有一条摘要路由,内部怎么抖都跟他们无关。
Type 5 要单独说一句。外部路由(比如从其他协议重分发进来的、或者静态路由注入的)默认以 Type 5 泛洪到整个 OSPF 域,这就破坏了区域化设计的意义。所以有了 Stub 区域(拒绝 Type 5)、Totally Stub(连 Type 3 也拒绝,只留一条默认路由)、NSSA(允许在自己区域内引入外部路由,用 Type 7,再由 ABR 转 Type 5 出去)。选择哪种,取决于你这个区域里有没有设备需要引入外部路由。
2.4 SPF 计算与路由表生成
每台设备拿到完整 LSDB 后,以自己的 Router-ID 为根跑 Dijkstra,算出去每个网段的最短路径,然后把结果写进路由表。这个过程有个细节值得说:OSPF 的路由不是"学来的",是"算出来的"。它学的是拓扑,路由是计算结果。这跟距离矢量协议完全不一样。
路径开销的计算方式是累加,公式很简单:
路径总开销 = 沿途所有出接口 cost 之和 接口 cost = 参考带宽 / 接口带宽默认参考带宽是 100 Mbps。这里就出现了一个经典问题:千兆接口算出来是 100/1000,小于 1,取整为 1;万兆也是 1。也就是说在默认配置下,一条百兆链路和一万兆链路的 cost 完全一样,SPF 会认为它们等价,可能把流量甩到窄链路上,这就是次优路径的常见成因。
解决办法是改参考带宽,改成 10000(10G)或者 100000(100G),让高带宽接口能算出区分度:
router ospf 1 auto-cost reference-bandwidth 10000注意:参考带宽必须全网一致。如果有设备改了有设备没改,同样的链路两端算出来的 cost 不一样,虽然邻居能起来,但路由会出现单向不对称,排错时非常难定位。改之前先想清楚影响范围。
当多条路径 cost 完全相同时,OSPF 默认做等价负载均衡,一般设备默认支持 4 条,可以调高。这不是配置出来才有的功能,是默认行为,很多人不知道自己的流量其实已经被分摊了。
3. 实操:从零搭一个三区域 OSPF
光讲原理容易空,我把一个完整的落地过程走一遍。拓扑设计成三台设备、三个区域,够覆盖 ABR、区域间路由、汇总这几个核心点。
3.1 拓扑设计与地址规划
[R1]---Area 0---[R2]---Area 1---[R3] | | Area 2 末梢网段具体规划如下:
| 设备 | 角色 | 接口 | 地址 | 区域 |
|---|---|---|---|---|
| R1 | ABR | G0/0 | 10.0.0.1/30 | Area 0 |
| R1 | G0/1 | 10.0.1.1/24 | Area 2 | |
| R1 | Lo0 | 10.255.255.1/32 | Area 0 | |
| R2 | ABR | G0/0 | 10.0.0.2/30 | Area 0 |
| R2 | G0/1 | 10.0.2.1/30 | Area 1 | |
| R2 | Lo0 | 10.255.255.2/32 | Area 0 | |
| R3 | 内部 | G0/0 | 10.0.2.2/30 | Area 1 |
| R3 | Lo0 | 10.255.255.3/32 | Area 1 | |
| R3 | G0/1 | 172.16.1.1/24 | Area 1 |
三个设计决定说明一下理由。第一,互联链路用 /30 而不是 /24,能省地址也减少广播域里的无效主机;第二,每台设备都配 Loopback,一是作为 Router-ID 的稳定来源(Loopback 不会 down),二是作为管理地址,排错时不受物理接口状态影响;第三,R1 和 R2 都挂在 Area 0 上,这是标准的双 ABR 结构,任意一个区域出问题都不会导致全网瘫痪。
3.2 基础配置与关键参数
以 R1 为例,配置分几步:
# 全局开启 OSPF 进程,进程号本地有效,两端可以不同 router ospf 1 router-id 10.255.255.1 ! 宣告 Area 0 的互联链路 network 10.0.0.0 0.0.0.3 area 0 ! 宣告 Loopback network 10.255.255.1 0.0.0.0 area 0 ! 宣告 Area 2 的网段 network 10.0.1.0 0.0.0.255 area 2 ! 面向终端的接口设为被动,不发 Hello 但网段照样宣告 passive-interface GigabitEthernet0/1 # 调整参考带宽,与全网保持一致 auto-cost reference-bandwidth 10000这里有几个点必须解释清楚。
反掩码怎么算。network后面跟的是通配符掩码,不是子网掩码,规则是子网掩码按位取反。255.255.255.0 取反是 0.0.0.255;255.255.255.252 取反是 0.0.0.3。算反掩码有个偷懒办法:用 255.255.255.255 减去子网掩码。比如 /30 的掩码是 255.255.255.252,255.255.255.255 - 255.255.255.252 = 0.0.0.3。很多人在这里配错,导致接口没被宣告,邻居起不来,日志里却什么提示都没有。
进程号本地有效。R1 用 1,R2 用 100,照样能建邻居。进程号只是个本地标识,别把它当成区域 ID 或者什么全局参数。
Loopback 用 0.0.0.0 反掩码。Loopback 是单主机地址,反掩码必须是全 0 的精确匹配。
被动接口不是可选项。面向终端 PC 的接口如果也发 Hello,一是浪费带宽,二是如果有人在这条链路上接了台开着 OSPF 的设备(比如测试机、误配的交换机),可能把它拉进 OSPF 域,轻则引起路由震荡,重则形成环路。passive-interface让这个接口只宣告网段、不发报文,是标准做法。
R2 的配置多了一段,因为它连两个区域:
router ospf 1 router-id 10.255.255.2 network 10.0.0.0 0.0.0.3 area 0 network 10.255.255.2 0.0.0.0 area 0 network 10.0.2.0 0.0.0.3 area 1R3 相对简单:
router ospf 1 router-id 10.255.255.3 network 10.0.2.0 0.0.0.3 area 1 network 10.255.255.3 0.0.0.0 area 1 network 172.16.1.0 0.0.0.255 area 1 passive-interface GigabitEthernet0/1配完之后,OSPF 会自己选出 R1 和 R2 谁是 DR。这条 10.0.0.0/30 链路上只有两台设备,DR 实际上没有意义,但选举还是会跑一遍。如果不想看到这种没必要的状态,可以两端都配ip ospf network point-to-point,把网络类型改成点到点,跳过 DR 选举,同时 Hello 间隔变成 30 秒。
3.3 验证:命令输出怎么读
配完先别急着测业务连通性,按顺序看这几条:
show ip ospf neighbor正常输出应该是这样:
| Neighbor ID | Pri | State | Dead Time | Address | Interface |
|---|---|---|---|---|---|
| 10.255.255.2 | 1 | FULL/DR | 00:00:38 | 10.0.0.2 | G0/0 |
| 10.255.255.3 | 1 | FULL/BDR | 00:00:39 | 10.0.2.2 | G0/1 |
看到 FULL 才算真正同步完。如果大量出现 2WAY/DROTHER,那是正常的,说明这些设备是非 DR/BDR,它们之间本来就只维持 2-Way。
接着看接口参数:
show ip ospf interface GigabitEthernet0/0重点看这几项:Area ID 是不是对的、网络类型是什么、Cost 是多少、Hello/Dead 间隔、DR/BDR 是谁。Cost 如果是 1,而这条链路实际带宽不高,那说明参考带宽没调,需要回头处理。
然后看 LSDB:
show ip ospf database在 R1 上应该能看到:Type 1 有 R1 和 R2 的(Area 0),Type 3 有 R2 通告的来自 Area 1 的摘要。Type 2 只有在广播网络里才有,如果改成点到点就没有了。数量对不上就是泛洪出了问题,可以从这里往回倒推。
最后看路由表:
show ip route ospfR1 上应该能看到O IA 10.0.2.0/30、O IA 172.16.1.0/24、O IA 10.255.255.3/32,前面的 O IA 表示区域间路由。如果 R3 的 Loopback 没宣告,这里就少一条,对应的是 Type 3 里缺这一项。
3.4 区域间路由与虚链路的实际操作
ABR 会自动做区域间路由,不需要额外配命令——只要一台设备同时有接口在两个区域里,它就是 ABR。但有两件事要手工处理。
路由汇总。ABR 把区域内的明细一条条通告出去,网段多了 Type 3 会很多。可以在 ABR 上做区域汇总,把连续网段合并:
router ospf 1 area 1 range 10.0.2.0 255.255.255.252这条命令的意思是:把 Area 1 里落在 10.0.2.0/30 范围内的所有明细路由,合并成一条通告给其他区域。汇总之后,Area 1 内部某条链路抖动不会引起其他区域的路由变化,收敛影响面被切断了。这是大规模网络里必做的优化。
虚链路。假设某次改造后 Area 2 没有直连 Area 0 了,中间隔了一个 Area 1,这时候可以打一条虚链路临时救急。配置写在两端 ABR 上:
# 在 R1 上 router ospf 1 area 1 virtual-link 10.255.255.2 # 在 R2 上 router ospf 1 area 1 virtual-link 10.255.255.1两端的 virtual-link 后面跟的是对方的 Router-ID,不是接口地址,这点很容易写错。虚链路建立后,两端会多出一个状态为 FULL 的邻居,接口名显示为 OSPF_VL0。虚链路上可以跑认证,也可以调 Hello 间隔,但它的可靠性完全依赖底层区域,底层区域挂了虚链路也挂,所以它从来不是长期方案。
4. 故障排查实录
4.1 邻居起不来:按这个顺序查
这是 OSPF 最高频的问题。我的排查顺序固定,从底层往上走,每一步都能排除一大片:
第一步,物理和二层。接口 up 不 up,收发光是否正常,两端 VLAN 是否一致。这一步不通过,后面全白搭。有人喜欢一上来就看 OSPF 配置,结果折腾两小时发现是网线水晶头松了。
第二步,IP 是否同网段。同一广播域里两台 OSPF 设备的接口地址必须在同一网段,且掩码一致。注意一个隐蔽情况:掩码不一致。10.0.0.1/24 和 10.0.0.2/25 看起来都在 10.0.0.x,但实际上 /25 的子网范围是 10.0.0.0-10.0.0.127,它们的主机部分能互通,但 OSPF 认为不在同一网络,邻居起不来。
第三步,区域 ID。两端区域 ID 不一致,Hello 包里这个字段对不上,直接丢包,状态停在 Down。这种情况往往发生在手工配错 area 号,尤其是把 area 1 写成 area 10 这类笔误。
第四步,Hello/Dead 间隔。用show ip ospf interface看两端,逐项对比。最常见的原因是网络类型不一致:一端是广播,一端被改成了点到点,间隔从 10/40 变成 30/120。
第五步,认证。一端配了认证一端没配,或者密钥不同、认证类型不同(明文和 MD5 混用)。现象是能收到 Hello 但进不到 2-Way,或者日志里明确报认证失败。
第六步,MTU。这个只在 ExStart 阶段卡住时怀疑。MTU 不一致的话,DBD 报文会被丢弃,邻居永远停在 ExStart/Exchange。查法是看两端接口 MTU,或者打开ip ospf mtu-ignore(这是绕过,不是修复,生产上要慎重,因为可能掩盖实际的分片问题)。
第七步,网络类型和 Stub 标志。Stub 区域标志不一致同样会导致邻居起不来。一端在 stub 区域,另一端不是,Hello 包里的 E-bit 对不上。
我把这个顺序整理成表,出问题的时候照着走:
| 卡住的状态 | 优先排查项 | 快速验证手段 |
|---|---|---|
| 一直 Down | 链路、IP 网段、区域 ID、Hello 间隔 | ping 通不通,对比接口参数 |
| Init | 单向通信、认证 | 检查两端认证配置 |
| 2-Way 但非 DR/BDR | 广播网络下的正常现象 | 无需处理 |
| ExStart | MTU、Router-ID 冲突 | 对比 MTU,检查 Router-ID 是否重复 |
| Exchange/Loading | 链路丢包、LSA 数量过多 | 看接口错包计数 |
| 反复 Full/断开 | Dead 间隔不匹配、链路抖动 | 看日志时间规律 |
注意:Router-ID 重复是一个非常隐蔽的故障。两台设备配了同一个 Router-ID,可能会短暂建立邻居然后不断重置,LSDB 也会混乱。手工指定 Router-ID 的时候一定要核对全网唯一性,别图省事全抄一个模板。
4.2 邻居是 Full 但路由不出来
这种问题比邻居起不来更难查,因为表面看起来一切正常。我遇到过几次,原因各不相同:
一是 network 宣告漏了。接口配了地址,但 network 命令里的反掩码没覆盖到这个地址,接口就没参与 OSPF。用show ip ospf interface brief能看到哪些接口真的进了 OSPF 进程,对照物理接口列表一查就清楚。
二是被动接口配错了范围。有的设备支持passive-interface default,把全部接口设为被动,然后单独放开互联口。这种写法不容易出错,但如果只放开了物理口忘了放开 Loopback,Loopback 就不会被宣告。
三是区域类型导致的过滤。Stub 区域天然不收 Type 5,如果你的外部路由是通过 Type 5 通告进来的,Stub 区域里的设备就看不到。这不是故障,是设计如此,但第一次遇到的人容易懵。要引入外部路由的区域,必须配成 NSSA 或者普通区域。
四是路由汇总配得范围过大。area x range的掩码写错了,可能把本来不该汇总的网段也吃掉,或者汇总出来的路由被上游设备当成不可达丢弃。
五是管理距离。OSPF 默认管理距离是 110,比静态路由(1)、直连(0)、甚至 eBGP(20)都大。如果同一目的地有静态路由存在,OSPF 算出来的路由虽然进了 LSDB 但不会进路由表。用show ip route看具体路由的来源,能直接分辨。
4.3 路径不对:次优路由的几个成因
流量走了不该走的路,这类问题在排查单里排第二。常见成因:
参考带宽没调。前面说过,默认 100 Mbps 参考带宽下,千兆和万兆 cost 都是 1,SPF 认为等价,做了负载均衡,你可能看到流量一半走窄链路。查法是show ip ospf interface看各接口 cost,如果高带宽接口 cost 也是 1,就该调了。
接口带宽配置和实际不符。有些设备的接口默认 bandwidth 值不等于实际速率,OSPF 按配置值算 cost,算出来就是错的。手工bandwidth一下让 cost 符合预期。
汇总掩盖了明细。做了区域汇总后,区域外的人只看到一条汇总路由,通往所有明细网段的流量都走汇总指向的那条路,即使内部有更优路径。这是汇总的固有代价,所以汇总的范围要谨慎划。
单向 cost 不对称。去程走 A 路,回程走 B 路。OSPF 本身不保证对称,cost 不一致就会这样。如果业务对时延敏感,需要两端 cost 都核对。
4.4 一份能直接抄的检查清单
我把日常排 OSPF 用的检查项整理成表,新接手一个网络的时候按这个过一遍,能提前发现大部分隐患:
| 检查项 | 期望状态 | 检查命令 |
|---|---|---|
| Router-ID 唯一且手工指定 | 全网无重复 | show ip ospf |
| 参考带宽全网一致 | 相同数值 | show ip ospf |
| Hello/Dead 间隔两端一致 | 同网络类型下相同 | show ip ospf interface |
| 区域 ID 配置正确 | 与规划一致 | show ip ospf interface brief |
| 被动接口覆盖终端侧 | 无 Hello 发出 | show ip ospf interface |
| 邻居状态 | 该 Full 的是 Full | show ip ospf neighbor |
| LSDB 类型数量 | 与拓扑预期相符 | show ip ospf database |
| 路由汇总范围 | 不吞明细、不漏网段 | show ip ospf |
| 认证配置 | 两端一致 | show run相关段 |
| 路由表 AD 值冲突 | 无静态路由抢占 | show ip route |
5. 生产环境调优与踩坑心得
5.1 参数调优的取舍
调 OSPF 参数之前,先想清楚你在优化什么。收敛速度、资源占用、稳定性,这三者互相牵扯,不可能同时拉满。
SPF 计算节流。拓扑抖动时如果每次都立刻跑 SPF,CPU 会被打满。可以配 SPF 计算间隔,让它攒一攒再算:
router ospf 1 timers throttle spf 50 200 5000三个数字分别是初始等待、第二次等待、最大等待(毫秒)。意思是第一次变化等 50ms 再算,如果 200ms 内又变了就继续等,最长不超过 5000ms。这个设计的好处是:单次抖动响应快,连续抖动时自动退避,避免 CPU 过载。参数没有标准答案,看你的设备性能和抖动频率来定。
LSA 泛洪节流。同理,LSA 生成和传输也可以加节流,避免大量 LSA 同时泛洪。
BFD 加速收敛。OSPF 靠 Hello 判断邻居存活,默认 40 秒 Dead 时间,意味着链路断了要 40 秒才被发现。这在很多业务场景里不可接受。可以开 BFD(双向转发检测),用毫秒级的探测替代 Hello 超时判断,故障检测时间能压到几百毫秒。代价是 BFD 报文也要占带宽和 CPU,而且两端都得配。
收敛优先级。如果某台设备 CPU 比较弱或者承载的业务重要,可以调低它的 SPF 计算优先级,让它少参与路径变更。这是比较进阶的用法,一般网络用不上。
5.2 那些文档里不写的坑
改参考带宽要全网一起改。我见过一次,某台新设备上线的默认配置没改,跟老设备的 cost 算出来不一样,导致一部分流量绕路。查了两天才定位到。所以现在我的做法是:参考带宽写进配置模板,新设备上线自动带上。
Router-ID 变更会导致邻居重置。改 Router-ID 不是热生效的,必须重启 OSPF 进程或者重置邻居。在大网里做这个操作要挑窗口期,别在业务高峰改。
虚链路不要当常规方案用。虚链路一旦建立,两端会形成一条逻辑上的骨干连接,但它的稳定性完全依赖穿越的那个区域。那个区域里任何一条链路抖动,虚链路都可能断,而且断的时候日志提示不明显。我现在的原则是:虚链路只用于过渡,规划阶段就该避免。
区域划分不要过细。见过有人为了"规范",把每个楼层都划一个区域。结果 ABR 上 Type 3 数量爆炸,LSDB 反而比单区域还大。区域的意义是控制泛洪范围,不是越多越好,一般按地理或者功能块划分,单个区域控制在几十台设备以内比较合适。
被动接口和 network 宣告是两个独立的事。passive-interface不影响网段宣告,只是不发 Hello。所以给终端网段配被动接口是对的,但别指望配了被动接口就等于宣告了——network 命令该写还得写。
OSPF 不感知应用层。它只看链路开销和拓扑,不看你这条链路实际跑了什么业务。如果要做基于业务的选路,得靠策略路由或者 BGP 的策略属性,OSPF 本身做不到。
5.3 几个我实际踩过的坑
有一次是两台设备的接口 MTU 不一致,一台 1500 一台 9000,邻居卡在 ExStart 整整一下午。当时先怀疑认证,又怀疑区域配错,最后是用show ip ospf neighbor看到状态一直停在 ExStart,才想到 MTU 这个方向。教训是:ExStart 卡住,第一反应就该是 MTU,别绕弯。
还有一次是 LSDB 里 Type 3 数量异常多,查下来是某个 ABR 上做了错误的汇总配置,掩码写成了 0.0.0.0,把所有明细都汇总成了一条 0.0.0.0/0,全网路由直接乱套。汇总命令的掩码一定要反复核对,配之前先想清楚要覆盖哪些网段。
最典型的一次是邻居反复 Full 又断。日志里每隔几十秒一次,看起来很规律。查了半天发现是有条链路上存在二层环路,广播包在里面转圈,Hello 报文重复到达导致邻居状态机混乱。这种问题从 OSPF 层面查不出根因,必须回到二层去抓包看。所以排错的时候别被协议层局限住,往下一层看往往才是答案。
最后说一个配置习惯上的事。我现在配 OSPF 一定按这个顺序:先配 Loopback 和 Router-ID,再配互联接口的 network,最后配被动接口和汇总。这个顺序的好处是每一步都能单独验证——配完 Loopback 先确认邻居能建立,配完互联再确认区域内路由通了,最后加汇总确认区域间路由没丢。反过来先配汇总再配邻居,出了问题根本分不清是哪一步的锅。配置是死的,验证顺序是活的,这个顺序感比记住命令重要得多。