上个月处理一个分公司访问总部业务变慢的工单,排查到最后,问题出在OSPF特殊区域里一条默认路由的下一跳上。这种问题教科书不会讲,但真机上又特别典型。OSPF作为园区网和运营商网络里最常见的动态路由协议,很多人学的时候背了一堆LSA类型和状态机,上了设备却不知道先看哪张表、怎么判断是邻居问题还是路由通告问题。这篇文章不打算把RFC 2328重新翻译一遍,而是按我在H3C、华为设备上调试OSPF的真实顺序,把最常用的知识点做一轮实战归纳,覆盖邻居排障、ABR与三类LSA、特殊区域选型、以及园区网里和MSTP、VRRP联动的场景。适合刚上手OSPF的网工,也适合准备割接前快速过一遍重点的兄弟。
1. 先搞懂OSPF的"三张表":邻居表、LSDB、路由表的排查顺序
1.1 三张表到底各自负责什么
OSPF之所以让人觉得难,是因为它不是一台路由器自己算完就完事,而是区域内所有路由器一起维护一份一致的"链路状态数据库",再各自算路由。所以上设备之后,第一件事不是看配置,而是分清三张表:
- 邻居表:
display ospf peer,记录我和谁建立了邻居关系,状态是2-Way还是Full。这是OSPF能不能工作的基础。 - LSDB(链路状态数据库):
display ospf lsdb,记录整区域收集到的所有LSA。排障时看它,能判断"路由信息到底有没有传过来"。 - 路由表:
display ospf routing或display ip routing-table protocol ospf,最终用来转发流量的结果。
一次典型的OSPF故障,排查顺序基本固定:先看邻居表,邻居不是Full就往下查接口状态和报文协商;邻居Full了但路由丢,再看LSDB里缺了哪类LSA;LSDB里有LSA但路由表没有,才考虑SPF计算、区域间防环规则、或者路由策略过滤。很多人一上来就翻路由表,路由条目缺失就怀疑策略,结果查半天发现邻居根本没建立,等于白费功夫。
打个不严谨但好记的比方:邻居表是"通讯录",LSDB是"全市道路素材库",路由表是"导航软件最终给的路线"。通讯录断了一页,素材库再全也白搭。
1.2 O和O IA的区别:区域内与区域间
在路由表里看到OSPF路由,通常会有关键字区分:
- O:区域内路由,来自1类Router LSA或2类Network LSA,这类路由可信度最高,不会跨区域。
- O IA:区域间路由,来自3类Summary LSA,由ABR生成并通告到其他区域。
实战中看这个字段非常有用。比如一个业务网段在区域1,你在区域0的核心设备上应该看到O IA;如果这条路由消失了,重点查区域1的ABR是否正常、ABR有没有生成3类LSA。而如果你在区域0内部宣告了一条网段,看到的却是O IA,说明它其实是从其他区域学来的,这对验证区域划分是否正确很有价值。
我习惯每次割接后做一遍"路由体检":把核心设备的路由表导出来,筛出O和O IA路由的条目数、下一跳、优先级,留作基线。后续链路调整或设备重启后,拿当前状态和基线对比,能很快定位是哪个区域的问题。
1.3 等价路由:负载分担不是默认全开
OSPF天然支持等价负载分担(ECMP)。华为和H3C设备上,路由表里同一个目的地址能看到多条下一跳,默认最大等价路由条数通常是4条或8条,具体看型号和软件版本。display ip routing-table里同一个目的掩码出现多次,Flag字段带D,就是等价路由。
实际使用中,有个容易被忽略的点:等价路由的前提是到目的网段的cost完全一致。很多人配置了双上行,以为流量会自动两条链路分担,结果发现一条链路空闲,另一条拥塞,往往就是两条链路的接口带宽不一致、或者参考带宽设置导致cost不同。想控制负载分担,要么调整接口cost,要么用maximum load-balancing修改等价路由数量。
2. 邻居关系从Down到Full:三步排查法解决80%的问题
2.1 Hello和Dead间隔不一致:邻居反复振荡的常见原因
OSPF邻居建立的第一步是互发Hello报文。广播网络上默认Hello间隔10秒,Dead间隔40秒(4倍)。问题出在很多人修改Hello间隔时只改了Hello忘了同步Dead,或者跨厂商对接时两端默认值不同,导致邻居状态反复跳变,表现出来就是路由一会儿有一会儿没有。
华为/H3C设备在接口下修改Hello后,Dead通常会自动跟随变成4倍,但思科设备上单独改ip ospf hello-interval,Dead不会变。跨厂商对接时尤其要小心。排查方法很简单:
display ospf peer看邻居状态,如果邻居在ExStart/2-Way之间反复跳,先怀疑定时器不匹配。- 两端接口下分别
display ospf interface,对照Hello/Dead字段。 - 统一配置,建议直接写成
ospf timer hello 10 dead 40这种显式写法,一目了然。
另外一个更隐蔽的问题是两端网络类型不一致导致Hello报文无法协商。比如一边是广播网络类型,一边被手动改成P2P,DR选举过程被跳过,状态会一直卡在Attempt或2-Way。这个问题我们放到下一小节展开。
注意:修改接口Hello/Dead间隔后,OLd邻居会立即重置,尤其是生产设备,尽量选在业务低峰操作。
2.2 MTU问题:邻居卡在ExStart的隐形杀手
OSPF建立邻居过程中,两台路由器通过DD报文交换LSDB摘要。DD报文里携带接口MTU值,如果两端MTU不一致,邻居状态会卡在ExStart或Exchange阶段,反复协商就是到不了Full。这个坑在新手排障中非常常见,因为接口本身是通的,ping也通,就是OSPF邻居起不来。
华为/H3C设备默认不检查MTU,但思科默认检查。跨厂商对接时,一边查一边不查,或者VLAN子接口、隧道接口MTU被调小,都容易触发。
排查思路:
display ospf peer看到状态停在ExStart/Exchange,且不变化。- 检查两端三层接口MTU,注意
display interface里看到的MTU和实际报文携带的MTU可能不一致。 - 临时解法:在接口下配置
ospf mtu-enable统一开启或关闭MTU检查(华为/H3C命令;思科用ip ospf mtu-ignore)。 - 根治方式:把两端链路MTU调成一致,尤其是GRE隧道、VXLAN、QinQ这类叠加场景,MTU经常比物理口小。
我曾经处理过一个广域网对接故障:总部核心到分部路由器之间跑OSPF,中间经过运营商专线,链路层封装开销导致MTU变成1400,分部侧接口MTU被调小,总部侧没调,邻居状态在ExStart卡了一整晚。后来统一把两端MTU改成1400,邻居秒变Full。
2.3 网络类型不一致:广播、P2P还是P2MP
OSPF接口网络类型决定了邻居发现方式和DR选举行为。常见有四种:广播(Broadcast)、非广播(NBMA)、点到点(P2P)、点到多点(P2MP)。日常用得最多的是广播和P2P。
广播网络需要选DR/BDR,Hello报文组播发往224.0.0.5,邻居状态机里会出现2-Way。P2P网络不需要选DR/BDR,直接建立邻居,收敛更快,也不存在DR切换带来的短暂路由中断。所以互联链路只要两端只有两台路由器,我强烈建议显式配置为P2P,一劳永逸。
但要注意:同一段链路两端的网络类型必须一致。如果一边是广播、一边是P2P,会出现一方能收到Hello但另一方不回应的情况,或者只有单方向邻居。排查时看display ospf interface的Type字段即可。
此外,NBMA和P2MP在实际工程中用得较少,多见于帧中继、X.25这类老旧网络或特殊组播受限场景。如果遇到,必须结合静态邻居或组播能力规划,不建议普通园区网使用。
3. ABR的作用边界:三类LSA与区域间路由的防环机制
3.1 什么样的路由器才是ABR
ABR(Area Border Router)是连接骨干区域(Area 0)和非骨干区域的路由器。这个定义看起来简单,但实战中经常有人把概念搞混:一台路由器同时连接Area 1和Area 2,但没有连接Area 0,它不是ABR,它就是一台普通区域内路由器,因为OSPF规定区域间路由必须经过骨干区域转发,非骨干区域之间不能直接交换路由信息。
判断ABR的方法很简单,登录设备执行display ospf brief,看Router Type字段,显示ABR才是ABR。例如热词里出现的ospf 1 router-id 1.1.1.1,配置完进程后,这个Router ID会出现在邻居表、LSDB的各种LSA里,方便你快速了解这台设备在整个OSPF域中的位置。
3.2 三类LSA的生成与防环规则
ABR的核心工作之一,就是把所连接区域的内部路由汇总成三类LSA,通告到其他区域。三类LSA有几个关键特性:
- 只能由ABR生成。
- 通告范围是本区域,不会继续被其他区域的ABR"转发"回原区域。
- 三类LSA中携带的是路由信息而非链路状态,所以SPF计算时,区域间路由是"距离矢量式"的。
OSPF的区域间防环规则,最核心的一条:ABR不会将从一个非骨干区域学习到的三类LSA,再通告回另一个非骨干区域。换句话,Area 1的路由要通过ABR发给Area 0,Area 0再发给Area 2;Area 1的ABR绝不能直接把路由塞给Area 2的ABR。理解这条规则,排障时才能解释很多"怪现象"。
3.3 一个区域间路由丢失的排查案例
之前项目里遇到一个问题:区域2的一台接入交换机引入了一条直连网段,区域0的核心设备能学到,但区域1的设备始终看不到。链路是通的,邻居也都是Full,那问题大概率出在ABR的LSA通告上。
排查链路如下:
- 在区域1的ABR上执行
display ospf lsdb summary,没看到关于那个网段的三类LSA。 - 在骨干区域核心设备上执行
display ospf lsdb summary,能看到该网段的三类LSA。 - 对比发现,区域1的ABR确实收到了来自Area 0的三类LSA,但它的SPF计算没有把它放入路由表。
- 查看ABR的
display ospf routing,发现ABR虽然有到Area 0的路由,但接口cost配置异常,导致该区域间路由被备用路径抑制。
最终定位为ABR与核心之间链路cost配置不合理,加上区域1内部有一条更优的静态路由,OSPF区域间路由被本地优先级规则顶掉。调整cost后路由恢复。
这个案例给我们的启发是:区域间路由丢,不要只盯ABR,还要看ABR到骨干区域的路径是否最优。OSPF的区域内路由优先于区域间路由,如果ABR自己有一条到目标网段的更优静态路由,外部区域的路由很可能不会被采纳。
4. 特殊区域不是"少学点路由"那么简单:Stub、NSSA怎么选
4.1 四类特殊区域选型对比
特殊区域设计的初衷是减少区域内LSDB规模和路由条目,同时解决外部路由引入问题。很多初学者把它理解成"特殊区域就是不让学外部路由",这话对了一半。实战中经常要对用户需求做取舍,必须把四种特殊区域的差异彻底搞清楚。
| 区域类型 | 允许的LSA | 默认路由来源 | 能否引入外部路由 | 适用场景 |
|---|---|---|---|---|
| 普通区域 | 1/2/3/4/5 | 无 | 可以(通过ASBR) | 默认情况 |
| Stub | 1/2/3(过滤4/5) | ABR生成3类默认 | 不能 | 末端区域,不需要外部路由 |
| Totally Stub | 1/2(过滤3/4/5) | ABR生成3类默认 | 不能 | 纯末梢,只靠默认路由出区域 |
| NSSA | 1/2/3/7(过滤4/5) | 取决于配置,默认不一定有 | 可以(7类LSA经ABR转5类) | 需要引入外部路由的末端区域 |
| Totally NSSA | 1/2/7(过滤3/4/5) | ABR生成3类默认 | 可以 | NSSA + 精简路由表 |
这张表的信息量很大,我们拆开讲。
4.2 特殊区域里"默认路由"到底谁产生的
Stub区域比较好理解:区域内部路由器不接收四类和五类LSA,外部路由完全靠ABR往区域里下发一条三类默认路由,区域内的设备把去外部的流量全扔给该ABR。
NSSA区域稍微绕一点。它允许本区域内的ASBR把外部路由以七类LSA形式扩散,七类LSA只能在NSSA内部传递。NSSA的ABR有两个选择:
- 把七类LSA转换成五类LSA,通告到骨干区域和其他普通区域。
- 作为默认路由的发布者,如果NSSA区域内没有真实的外部路由,ABR可以手动配置默认路由(
nssa default-route-advertise),或者通过no-summary参数在Totally NSSA场景下生成三类默认路由。
实战中很多人困惑"为什么NSSA里看不到默认路由",因为默认路由在NSSA中不一定自动产生,必须满足条件:要么ABR/ASBR通告了默认路由,要么配置了相关命令。这和Stub区域完全不同。
4.3 H3C设备上配置特殊区域需要注意的细节
H3C(以及华为)的OSPF配置风格类似,下面直接给配置片段。
Stub区域配置:区域内的每台路由器都要进入Area视图,敲stub。
ospf 1 router-id 1.1.1.1 area 0.0.0.1 stub network 10.1.0.0 0.0.0.255如果要在ABR上做成Totally Stub,多一条stub no-summary即可,其他非ABR路由器仍然只需配置stub。这里有个关键:同一区域内的所有路由器,特殊区域类型必须一致。如果一台配了stub另一台没配,邻居状态会一直卡在Init或停留在2-Way,无法建立Full。
NSSA区域配置:
ospf 1 router-id 1.1.1.1 area 0.0.0.1 nssa default-route-advertise network 10.1.0.0 0.0.0.255如果该区域是Totally NSSA,就在ABR上加nssa no-summary。
配置容易踩的坑:
- NSSA区域内的非ABR路由器,如果没配
default-route-advertise,它是不会主动产生默认路由的,需要在边界设备上做route policy或配缺省路由。 - 七类LSA转换为五类LSA时,转换路由器(通常是最先收到七类LSA的ABR,也可能因为Router ID选举指定Translator)可能出现重叠,导致外部路由的下一跳不一致。排障时用
display ospf lsdb nssa和display ospf lsdb ase对比。 - 如果在NSSA里同时引入多条外部路由,建议用路由策略控制转换范围,避免O NSSA路由Table太大。
5. 园区网里的OSPF与MSTP、VRRP联动:网关冗余和路由收敛的配合
5.1 为什么这三样总是绑在一起出现
老园区网用户接入方案,基本就是接入交换机做二层,汇聚交换机做VLAN网关,核心交换机跑三层路由。为了保证网关不单点,汇聚设备会跑VRRP,让两台交换机共享一个虚拟网关IP;为了防环,二层网络要跑MSTP;而汇聚与核心之间的三层互联,通常就用OSPF。
所以"OSPF+MSTP+VRRP"不是谁刻意捆绑,而是各自解决了园区网里一层的需求:MSTP管二层转发拓扑,VRRP管网关冗余,OSPF管三层路由。问题在于这三者如果各调各的,很容易出现"VRRP主备切换了,三条路由还在走老路径"之类的尴尬。
5.2 联动的关键:主备方向和路径cost必须一致
先说VRRP和MSTP的关系。MSTP通过多实例把不同VLAN的转发路径分开,通常会让实例1的根桥在汇聚A、实例2的根桥在汇聚B,实现负载分担。VRRP和MSTP配合时,同一个VLAN的VRRP主设备和该VLAN生成树实例的根桥尽量放在同一台设备上,否则二层流量从接入交换机上来的路径和网关所在设备可能不一致,造成绕路。
再说OSPF。OSPF独立于VRRP和MSTP运行,它只看三层接口的cost和链路状态。所以如果链路出现主备方向不一致,会造成路由层面没有问题、但实际转发绕路的情况。一个典型场景:汇聚A是VLAN10的VRRP主设备,MSTP实例1的根也在A,核心到汇聚A的OSPF cost是10,到汇聚B的cost是20,那VLAN10的东西向流量没问题。但如果调整了MSTP根桥到B,VRRP主还是A,流量就可能在接入交换机上先到B,然后B通过二层绕到A,形成非最优路径。
处理建议:互联口统一跑P2P类型,OSPF手动调整cost,让VRRP主方向对应的OSPF路径cost更小,保证故障切换前后流量走向符合预期。
5.3 联动场景中OSPF的收敛实测与优化
实际调测过一个双汇聚双核心的园区网。汇聚A和汇聚B同时上联核心,双链路上联用Eth-Trunk做了链路聚合。接入交换机上的网关由VRRP承担,主在汇聚A。
割接前的验证阶段发现:把汇聚A的OSPF进程重启后,VLAN10网关从A切换到B,业务中断了将近40秒。排查发现,问题不在OSPF邻居重建,而在VRRP切换和OSPF收敛的先后顺序:汇聚A重启导致VRRP主失效,VLAN10流量切到B,但核心到VLAN10网段的路由下一跳还是A,因为核心侧OSPF还没感知到A上联口的down事件。
优化手段做了三件事:
- 缩短OSPF Hello/Dead间隔:互联口改为
ospf timer hello 5 dead 20,加快故障感知。 - BFD联动:配置
ospf bfd enable,让OSPF邻居状态和链路故障由BFD快速检测,秒级收敛。 - VRRP抢占延迟:把汇聚A的VRRP抢占延迟调大,避免设备刚重启完还没稳定就抢回主状态,造成路由抖动。
最终把故障切换时间压到了10秒以内。这也说明,OSPF本身再快,如果其他协议配合不当,整体业务恢复时间依然不理想。
6. Router-ID、network宣告和几个配置细节:实战里最容易忽略的小事
6.1 Router-ID不会自动"避让":1.1.1.1这类地址怎么规划
Router-ID是OSPF进程的身份标识,在同一个OSPF域内必须唯一。很多设备默认从最大Loopback地址或最大物理接口地址里自动选,但我不推荐这种"随缘"做法,原因有两个:
- 物理接口down了,Router-ID不一定会重新选择,设备重启或接口恢复后,可能导致Router-ID变化,引起邻居震荡。
- 自动选择不容易让人一眼看出"这台设备是谁"。
热词里出现的ospf 1 router-id 1.1.1.1,就是典型的手工规划Router-ID思路。在H3C/华为上,配置如下:
ospf 1 router-id 1.1.1.1后面跟的Router ID建议取自Loopback接口地址,也顺带用它做设备管理地址,便于SSH登录和排障时对号入座。比如核心交换机用1.1.1.1,汇聚A用1.1.1.2,汇聚B用1.1.1.3,区域边界的ABR用1.1.1.4,一目了然。
需要注意:修改Router-ID后,OSPF进程不会自动重启,必须执行reset ospf process(华为/H3C)或重启进程,否则新Router-ID不生效。生产环境尽量选在维护窗口做,因为会中断该进程下的所有OSPF邻居。
6.2 network宣告:通配符掩码不是子网掩码
OSPF的network宣告格式是network 网段 通配符掩码,注意后面的反掩码,不是子网掩码。常见的错误是把255.255.255.0写成子网掩码格式,一旦写成255.255.255.0,实际匹配范围变小,接口宣告不上。
正确示例如下:
ospf 1 router-id 1.1.1.1 area 0.0.0.0 network 192.168.10.0 0.0.0.255 network 192.168.11.0 0.0.0.255有人图省事,直接写network 0.0.0.0 255.255.255.255,把所有接口都宣告进OSPF。这种写法能跑通,但隐患很大:只要接口up,不管业务接口还是管理接口,都会被宣告,路由表里会冒出很多本不该出现的直连网段。而且一旦将来设备角色调整或做路由过滤,排查非常痛苦。建议始终用精确网段宣告,把OSPF边界控制在自己手里。
还有一点,network宣告的范围是"接口匹配"而不是"只宣告这个网段"。比如network 192.168.10.0 0.0.0.255,匹配的是192.168.10.0/24这个子网里的接口,如果设备上有192.168.10.1/25和192.168.10.128/25两个接口,它们都会进这个区域。这也是为什么精确规划地址和掩码非常重要。
6.3 默认参数优化:带宽参考值、静默接口、区域认证
几个实用小参数,平时不显眼,关键时刻很影响稳定性。
带宽参考值(bandwidth-reference)。OSPF计算cost的基础是参考带宽除以接口带宽,默认参考带宽是100Mbps。在万兆链路环境下,10G接口除以100M就是100,而千兆接口是1,导致所有高速链路cost几乎都一样,等价路由的选择就变得不直观。建议在核心设备上统一调整:
ospf 1 bandwidth-reference 10000将参考带宽改为10000Mbps(10G),这样万兆口cost是1,千兆口是10,路由选路更符合预期。
静默接口(silent-interface)。终端侧接口如果不需要建立OSPF邻居,但网段又需要宣告进OSPF,可以在进程下配置:
ospf 1 silent-interface GigabitEthernet1/0/1静默接口不发送Hello报文,也就不会和接入设备建立OSPF邻居,但该接口的直连网段依然会被network宣告进LSDB,非常实用。否则所有接入交换机都可能和你建立OSPF邻居,路由表乱七八糟。思科对应命令是passive-interface。
区域认证。如果OSPF区域里设备比较多,建议至少配置简单区域认证,避免有人误接入一台设备就参与路由计算。H3C/华为命令:
ospf 1 area 0.0.0.0 authentication-mode hmac-sha256 key-id 1 cipher 123456配置认证时务必保证区域内所有设备同时修改,并留好回退方案,否则认证不一致会导致邻居全部断开。
这轮OSPF实战归纳写到这里,核心思路其实就一句话:先把邻居关系搞稳,再看路由表,最后才谈选路和优化。真机上遇到的问题,很多时候不是OSPF协议本身太深,而是我们对顺序和细节的把控不够。我的体会是,每周抽点时间在模拟器或真机上复现一遍邻居振荡、特殊区域通告、VRRP联动这几种常见场景,比背十遍LSA类型有用得多。尤其是特殊区域部分,投产前一定要把默认路由的产生方式测清楚,不要等到割接当晚才去查为什么NSSA里没有默认路由,那真的是拿业务在赌。