做运维这些年,我越来越觉得路由协议是一道绕不过去的坎。网络小的时候,一台核心加几台接入,手工静态路由完全够用;但业务一扩张、链路一冗余、网段一多,静态路由表就变成维护噩梦。我第一次认认真真研究OSPF配置,是给某园区网做网络改造的时候,三台核心设备、上百条路由,当时最直观的感受就是:动态路由协议真的能救命,但前提是你得真正懂它,而不是只会照着文档敲命令。
这篇是网管实战系列的第5篇,主线就是OSPF配置,从核心原理讲到单区域实验、多区域部署、以及排查实战里我自己踩过的坑。内容比较适合两类人:一类是刚接手网络管理的运维新人,另一类是已经在用静态路由、正准备上动态路由的朋友。看完你至少能独立完成一个中小型网络的OSPF单区域和多区域配置,遇到邻居起不来、路由学不到这类问题,也知道该从哪里下手。
我会尽量用“干活”的视角讲,少堆术语,多给命令和现场经验。有些参数在不同厂商设备上略有差异,我会说明原理和适用场景,你实操时以手上设备的官方文档为准,但核心逻辑是通用的。
1. OSPF到底解决什么问题——先搞懂原理再动手
1.1 静态路由不省心,OSPF为什么能顶上
先说一段我的真实经历。之前维护的那个网络,互联段、业务段加起来要维护的路由有三四十条,全部靠静态配置。每次网络结构一变,我就得一台一台登录设备删旧路由、加新路由。最难受的是双链路场景:核心设备到上游有两条物理链路,静态路由只能手工指定主备,主链路一旦断了不会自动切到备用链路上去,业务中断时间全看人的响应速度。
OSPF解决的就是这两个核心问题:自动学习路由、故障时自动收敛。它属于链路状态路由协议,跟RIP这种距离向量协议完全不同。OSPF里的每台路由器首先收集全网链路的“状态”信息,然后基于这份完整的拓扑数据,运行SPF(Shortest Path First,最短路径优先)算法,独立计算出到达各网段的最优路径。链路一旦断开,所有路由器会感知到拓扑变化,重新计算并收敛新路由,整个过程不需要人介入。
我一般用一个不太严谨但非常好懂的比喻:RIP像邻居之间互相转告,“去东边走我这里最快”;OSPF则像大家把各自的地图碎片拼在一起,每个人手里都有一张完整地图,再拿尺子量出最短的路。这个比喻虽然简单,却足以解释为什么OSPF收敛快、不易产生环路——因为它看的是全局拓扑,而不是一跳一跳的传闻。
1.2 理解LSA、LSDB和区域
OSPF里有几个核心概念,配置之前最好先建立直觉。LSA(Link-State Advertisement,链路状态通告)是路由器描述自身接口状态、连接关系、开销等信息的小通告;每台路由器产生的LSA在区域内洪泛传播,所有路由器收到的LSA汇总起来,就构成了一份LSDB(Link-State DataBase,链路状态数据库)。只要同一个区域里各设备的LSDB一致,每台路由器就能基于同一份拓扑算出相同的路由结果,这是OSPF可靠性的根基。
区域(Area)则是LSDB的隔离边界。引入区域的目的是控制LSA的传播范围:区域内的详细拓扑只在区域内洪泛,区域之间只交换汇总后的路由信息,这样全网规模变大时,每台路由器需要维护的数据量不会跟着一起爆炸。这里有一条铁律必须记住:所有区域都要与骨干区域Area 0相连,跨区域路由必须经过骨干区域中转,否则区域间学不到彼此路由。这条规则我在后面配置时会反复用到。
1.3 配置前的术语清单
动手之前,把下面这几个词的意思彻底搞清楚,后面看命令输出才不吃力。
- Router ID:路由器的OSPF标识,相当于给每台参与OSPF的设备一个全网唯一的“工号”,一般用某个IPv4地址充当。如果没手工指定,协议会自动选一个接口地址当Router ID,我强烈建议手工指定,否则接口地址一变,Router ID跟着变,会导致邻接关系重建。
- 邻居(Neighbor)与邻接(Adjacency):两台直连设备互相发Hello报文后建立邻居关系;邻居关系进一步完成数据库同步之后才形成邻接关系。不是所有邻居都会形成邻接,在广播型链路上,只有DR、BDR才与所有路由器形成邻接。
- Cost(开销):OSPF判断路径优劣的度量值,默认跟接口带宽成反比,带宽越大Cost越小,具体算法后面单独讲。
- 区域ID:32位数值,用点分十进制表示就是Area 0、Area 1这种格式,Area 0是骨干区域。
这些术语在调试命令的输出里出现频率极高,尤其是display ospf peer这类信息,每一列都对应一个概念。提前铺个底,后面看输出就能一眼定位是哪个环节出了问题。
2. 实验环境搭建与基础配置——单区域OSPF实操
2.1 用一个能动手的拓扑
纸上谈兵没用,我直接用一个典型的小型网络拓扑作为实验对象。三台路由器Router-1、Router-2、Router-3,其中Router-1与Router-2互联,Router-2与Router-3互联,Router-1与Router-3之间再加一条备份链路。这个拓扑足够简单,又能演示OSPF选路和收敛,两条等价链路还能用来验证路径切换。
地址规划我按下面的表来:
| 设备 | 接口 | 互联网段 | 接口地址 |
|---|---|---|---|
| Router-1 | G0/0/0 | 10.0.12.0/30 | 10.0.12.1 |
| Router-1 | G0/0/1 | 10.0.13.0/30 | 10.0.13.1 |
| Router-1 | Loopback0 | 192.168.1.0/24 | 192.168.1.1 |
| Router-2 | G0/0/0 | 10.0.12.0/30 | 10.0.12.2 |
| Router-2 | G0/0/1 | 10.0.23.0/30 | 10.0.23.2 |
| Router-2 | Loopback0 | 192.168.2.0/24 | 192.168.2.1 |
| Router-3 | G0/0/0 | 10.0.13.0/30 | 10.0.13.3 |
| Router-3 | G0/0/1 | 10.0.23.0/30 | 10.0.23.3 |
| Router-3 | Loopback0 | 192.168.3.0/24 | 192.168.3.1 |
为什么要用/30这种掩码?点对点互联段原则上只需要两个可用地址,/30正好够用,还能避免浪费私网地址。Loopback0接口用来模拟业务网段,也方便测试路由学习效果,配置协议时它也算一个可通告的网络。
2.2 在Router-1上启动OSPF进程
实际操作时,我在某厂商的设备上用的命令类似这样。为了阅读方便,全文统一用一套命令风格,你在自己设备上做等价转换即可。
# Router-1 system-view sysname Router-1 interface GigabitEthernet0/0/0 ip address 10.0.12.1 255.255.255.252 quit interface GigabitEthernet0/0/1 ip address 10.0.13.1 255.255.255.252 quit interface LoopBack0 ip address 192.168.1.1 255.255.255.0 quit ospf 1 router-id 1.1.1.1 area 0 network 10.0.12.0 0.0.0.3 network 10.0.13.0 0.0.0.3 network 192.168.1.0 0.0.0.255 return这里有三处容易看花眼的地方,我重点说明。
第一,ospf 1后面的“1”是进程号,同一台设备可以跑多个OSPF进程,一般一个就够,进程号只在本地有意义。router-id 1.1.1.1是手工指定的Router ID,建议从稳定的Loopback地址里挑一个来充当。
第二,network后面跟的不是子网掩码,而是通配符(反掩码)。0.0.0.3表示匹配/30网段,0.0.0.255表示匹配/24网段。写成255.255.255.252是错的,这是新手最容易翻车的地方。反掩码的规则是“0表示必须匹配,1表示任意”,所以255.255.255.252这种正常掩码根本不会按预期匹配。
第三,network命令必须覆盖接口所在的网段,对应接口才会参与OSPF。很多人以为写一句network 10.0.0.0 0.0.0.255就能通吃,并不是,反掩码匹配不到就白配。我的习惯是每个接口对应的网段单独写一条,虽然啰嗦,但排障时一眼就能看清哪些网段参与了协议。
OSPF只在接口上发Hello报文。默认情况下,广播网络的Hello间隔是10秒,Dead间隔是40秒。如果接口没配地址或者没被network覆盖,协议不会在这个接口上工作,邻居关系自然建立不起来。
2.3 对端设备配置和验证
Router-2和Router-3的配置思路与Router-1完全一样,只是接口地址和Router ID不同。我以Router-2为例:
# Router-2 system-view sysname Router-2 interface GigabitEthernet0/0/0 ip address 10.0.12.2 255.255.255.252 quit interface GigabitEthernet0/0/1 ip address 10.0.23.2 255.255.255.252 quit interface LoopBack0 ip address 192.168.2.1 255.255.255.0 quit ospf 1 router-id 2.2.2.2 area 0 network 10.0.12.0 0.0.0.3 network 10.0.23.0 0.0.0.3 network 192.168.2.0 0.0.0.255 return配置完成后,判断邻居是否建立成功,最直接的命令是查看邻居表:
display ospf peer如果邻居状态显示Full,说明两台设备已经形成邻接关系,数据库也完成了同步。如果看到Init、ExStart或者2-Way,先别急,那是中间状态,等几秒再看;如果长时间停在某个中间状态,就是有问题了,排查方法我放在第5章细说。
再看OSPF学习到的路由:
display ospf routing正常的话,Router-2应该能看到192.168.1.0、192.168.3.0这些非直连网段。最后用ping从Router-1去Router-3的Loopback地址做连通性测试,能通就说明单区域基础配置已经没问题。真实网络里还要注意终端的网关指向对应接入设备的三层接口,这里就不展开了。
3. 选路背后的参数:接口开销、DR/BDR与网络类型
3.1 Cost值是影响选路的核心参数
OSPF的Cost值用来判断路径优劣,默认算法是Cost = 参考带宽 / 接口带宽。设备上的参考带宽默认是100Mbps,也就是拿百兆带宽做基准。这样算下来,百兆接口Cost=1,千兆接口算出来是0.1,但Cost必须是整数且最小为1,所以千兆接口的Cost实际上也显示为1。
这就带来一个隐蔽的坑:当网络里既有百兆链路又有千兆链路时,默认参数下两边Cost一样,OSPF分不出优劣,流量可能被分配到慢链路上。解决办法是调整参考带宽,让百兆和千兆能拉开差距:
ospf 1 bandwidth-reference 10000这条命令把参考带宽改成10000Mbps,也就是10Gbps。改完以后,千兆接口Cost=10000/1000=10,百兆接口Cost=10000/100=100,OSPF就能正确走千兆链路了。需要特别提醒:参考带宽必须在同一个OSPF网络里的所有设备上保持一致,否则各设备算出来的Cost口径不同,选路会出大问题。我见过同事只改了核心设备、接入没改,结果链路切换时路由表半天稳定不下来。
3.2 DR/BDR是怎么选出来的,怎么人为控制
在以太网这种广播型多路访问链路上,如果每台路由器都两两建立邻接关系,N台设备就需要N×(N-1)/2个邻接关系,数据库同步风暴会直接把网络打垮。OSPF的解法是选举一个指定路由器DR(Designated Router)和一个备份指定路由器BDR,其他路由器只跟DR/BDR建立邻接关系,所有LSA的交换都以DR为中心。这个机制在有大量接入设备的交换机组网里尤其重要。
DR/BDR的选举依据有两个:接口优先级(默认1,0表示不参与选举)和Router ID。比较时优先看优先级,优先级高者胜;优先级相同再看Router ID,ID大者胜。想人为指定某台设备稳定当DR,就把它的接口优先级调大:
interface GigabitEthernet0/0/0 ospf dr-priority 255但是要注意,DR/BDR选举不是“后来者居上”,新加入的路由器即使优先级更大,也不会抢占已选出的DR/BDR,除非它掉线或者OSPF进程被重启。想人为触发重新选举,可以重启OSPF进程,或者把接口reset一下。这个特性在割接时经常用到,稍不留神就会出现“先起来的设备当了DR,但并不是你预期那一台”的情况,排查半天不如先看一眼DR是谁。
3.3 网络类型不匹配会导致邻居起不来
OSPF的Hello机制在不同网络类型下行为不同。常见的网络类型有Broadcast(广播,通常是以太网)、P2P(点对点,通常是串口)、NBMA(非广播多路访问)等。默认情况下,以太网接口是Broadcast,串口是P2P,但在虚拟化环境和SDH链路里,经常出现把以太网口当P2P来用的情况,这就踩到了网络类型的坑:两边网络类型不匹配,Hello报文收发逻辑对不上,邻居会一直卡在Down或者Init。
如果确认两端设备只有两台,中间也没有交换机,把以太网接口的网络类型改成P2P是常见做法:
interface GigabitEthernet0/0/0 ospf network-type p2p改成P2P之后,链路上不再进行DR/BDR选举,也不需要等待2个Hello周期确认DR,邻居建立更快,收敛也更干脆。唯一的代价是,如果以后这个链路上又接了第三台设备,P2P类型就不适用了。我的个人经验是,核心互联链路只要确认收发两端,P2P比Broadcast省心得多,故障切换时的收敛速度差异尤其明显。
4. 走向真实网络:多区域OSPF与路由汇总
4.1 规模大了,为什么必须拆区域
单区域OSPF在小网络里很舒服,但区域里路由器数量一多,LSA数量跟着膨胀,每台路由器都要保存完整LSDB并且参与全量SPF计算,CPU和内存压力越来越大。更麻烦的是,某个网段的抖动会让区域内所有路由器重新跑一遍算法,故障影响面被成倍放大。
拆成多区域之后,每个区域内部的路由器只需要保存本区域的详细LSDB;区域之间的路由信息由区域边界路由器(ABR,Area Border Router)以汇总LSA的形式传给其他区域。这样单个拓扑变化不会波及其他区域,收敛范围被限制住,整个网络的路由表也能精简不少。这是OSPF能支撑大型网络的关键设计。
拆区域有一条铁规矩:所有非骨干区域必须直接或间接连接到骨干区域Area 0,跨区域流量必须经过骨干区域中转。很多网络规划问题都出在这里——接入区域没有物理链路连到骨干,只能靠虚拟链路(Virtual Link)临时打通。虚拟链路依赖底层路由,一断全断,能不用尽量不用,宁可多拉一条物理链路。
4.2 把Router-2配置成ABR
在单区域实验基础上,增加一个Area 1,把Router-2和它下端的一个业务区域划进Area 1。此时Router-2同时连着Area 0和Area 1,它就是ABR。配置命令如下:
# Router-2 添加Area 1配置 ospf 1 router-id 2.2.2.2 area 0 network 10.0.12.0 0.0.0.3 area 1 network 10.0.23.0 0.0.0.3 network 192.168.2.0 0.0.0.255原来在Area 0里的Router-1和Router-3可以不动,它们与Router-2之间仍然走Area 0的内部路由。但要注意区域归属的一致性:如果Router-2把与Router-3直连的网段划到了Area 1,Router-3对应接口也要加入Area 1,否则两端区域对不上,邻居建立不起来。这种区域归属不匹配,是日常排障里最高频的问题之一。
配置完成后,在Router-1上执行display ospf routing,应该能看到192.168.2.0、192.168.3.0这些网段都有路由,但注意它们的来源可能是Inter-Area类型,也就是跨区域学习到的。看懂这个类型,是为了区分路由是区域内直连学来的,还是ABR汇总过来的,排障时的定位思路完全不同。
4.3 用路由汇总收缩路由表
多区域里最实用的技巧就是路由汇总。ABR可以向Area 0通告自己所在区域的路由,如果这个区域里有几十个连续子网,不汇总的话,骨干区域的路由表会变得非常臃肿。在ABR上做区域间汇总,例如把192.168.0.0/22这一个连续大块通告出去:
ospf 1 area 1 abr-summary 192.168.0.0 255.255.252.0不同厂商把这个命令放在不同位置,有的叫range,有的叫abr-summary,原理都是一样的:ABR把自己从某个区域学到的明细路由收敛成一条汇总路由再通告出去,外部区域只看得到汇总路由,明细保留在ABR本地。汇总的前提是网段必须连续且掩码对齐,如果把192.168.2.0/24和172.16.1.0/24硬汇总到一起,会造出黑洞路由,这是做IP规划时就要提前考虑清楚的。
顺带说一句,汇总还能明显提升稳定性——区域内某个小网段闪断时,只要汇总路由本身还在,外部区域根本感知不到变化,收敛范围被进一步压缩。我在园区网改造时就用这一条规则,把接入层的80多条路由汇总成4条,核心路由表瞬间清爽,后续排障也轻松很多。
4.4 给OSPF加上认证
有些网络里,只要设备能互通、配置了同一个区域ID,就可能被非法设备拖进OSPF域内,所以生产环境一定要加认证。最简单的明文认证可以在接口下配置:
interface GigabitEthernet0/0/0 ospf authentication-mode simple plain 123456更稳妥的是MD5或HMAC-SHA256认证。认证相当于给OSPF报文加了一道口令,密码不一致的设备无法建立邻居关系。我的强烈建议是,生产网络至少用MD5及以上强度的认证,并提前规划好密码轮换流程。
我踩过的一次大坑就是只改了出口设备的认证,对端还没改。配置刷下去的一瞬间,邻居全部中断,远程连接也断掉,只好跑一趟机房。后来我总结出一个安全做法:先在所有对端设备上准备好新认证,再在一台设备上启用;或者干脆放在维护窗口批量操作,避免把自己锁在门外。
5. 邻居起不来、路由学不到——故障排查实战记录
5.1 邻居状态长期不是Full,怎么定位
维护中见得最多的OSPF故障就是邻居状态卡住。先把状态机完整过一遍:Down、Init、2-Way、ExStart、Exchange、Loading、Full。Down表示没收到对端Hello;Init表示收到了Hello但对方还没看到自己;2-Way说明双方Hello交互成功,如果是广播网络里两台DROther设备,停留在2-Way是正常的;ExStart和Exchange出现在数据库同步阶段;Loading在交换LSDB摘要;Full才表示邻接建立完成。
如果状态长时间停在某个中间阶段,按下面几类原因逐一排查:
- Hello间隔和Dead间隔不一致。两边一边是默认10秒/40秒,一边被改成20秒/80秒,邻居会反复Up和Down,甚至一直Down。用display ospf interface查看间隔参数,确保两端一致。
- 区域ID不一致。一边Area 0一边Area 1,永远起不来,重点检查network命令所在的区域。
- Router ID冲突或没有指定。两台设备Router ID一样,邻接建立后处理LSA会出现各种诡异现象,建议全部手工指定。
- 认证不匹配。配了认证但密钥不一致,Hello报文被丢弃,状态在Down和Init之间反复跳。
- 接口MTU不一致导致卡在ExStart或Exchange。跨厂商对接时特别常见,某厂商默认不开MTU协商,另一个厂商默认开启,两边MTU不一致会让数据库同步一直失败。
排查时主要看两个输出:display ospf peer查看邻居当前状态;display ospf interface查看接口下的区域、网络类型、Hello间隔、Cost、接口状态。状态卡住时把两边的输出对照着看,差异项往往就是问题点。
5.2 邻居Full了但路由不对,从哪查起
邻居Full不代表路由表一定正确,尤其是多区域和路由汇总参与进来之后。一个典型场景:客户新加了一段业务网段,接入设备上宣告了,但核心就是ping不通业务地址。这时候不要急着翻OSPF,先看全局路由表里这段路由的下一跳是否正确,有没有被汇总路由覆盖。
如果OSPF路由表里有明细,但全局路由表里没有,多半是引入外部路由或路由优先级问题,要看引入外部路由的配置动作。如果OSPF路由根本学不到,优先检查宣告里的反掩码是否覆盖了真实接口地址,以及该接口是否在正确的区域里。我处理过不少次,网段掩码是/25,反掩码却写成0.0.0.255,宣告匹配失败,路由自然学不到。
还有一种坑是转发地址(Forwarding Address)导致的路由不可达。常见于引入外部路由的场景,LSA里的转发地址指向一个不可达网段,接收方认为路由存在,但下一跳不可达,业务照样不通。遇到这种情况,别只看路由表,直接把LSA导出来看转发地址是谁,再顺着查那台设备。
5.3 常用排查命令速查
这里整理一张速查表,方便现场对照:
| 需求 | 命令 | 期望输出 |
|---|---|---|
| 查看邻居状态 | display ospf peer | 状态为Full,邻居数量正常 |
| 查看接口OSPF参数 | display ospf interface | 区域、网络类型、Cost、Hello间隔正确 |
| 查看OSPF路由表 | display ospf routing | 目标网段均有路由,下一跳正确 |
| 查看全局路由表 | display ip routing-table | OSPF路由正常入表,优先级合理 |
| 查看链路状态数据库 | display ospf lsdb | 区域内LSA类型完整,无异常重复 |
| 查看OSPF错误统计 | display ospf error | 无持续增长的认证或MTU错误计数 |
现场排障时,我习惯先看邻居,再看接口,再看路由表,最后看LSDB。这个顺序能帮你快速缩小问题范围,不会像无头苍蝇一样乱敲命令。
5.4 三个真实踩过的坑
第一个坑是反掩码写错。我刚开始接触OSPF时,把network 10.0.12.0 0.0.0.3写成了0.0.0.255,当时心想“反掩码就是子网掩码取反”,结果邻居一直起不来。后来才彻底明白,反掩码的匹配逻辑是“0必须匹配,1可以任意”,不是简单取反就完事。
第二个坑是修改Cost后路由不切换。我把一条链路的Cost调大,想让流量改走另一条链路,等了半天路由表还是老的。原因有两层:一方面OSPF收敛本来就有延迟,需要耐心等待;另一方面,我改的是对端接口的Cost,本端接口没改。要影响本端选路,必须改本端接收流量那个接口的Cost,这个方向性特别容易搞混。
第三个坑是对称认证的时机问题,前面提过。只改一侧认证,邻居直接全断,而且远程登录也断掉,只能人肉去机房。吃一堑长一智,现在凡是涉及认证、ACL、全局参数这类操作,我一定会先确认有一台带外管理通道,否则就老老实实安排现场。
6. OSPF与RIP/静态路由的选型心得
6.1 三种方式怎么选
聊点选型层面的个人看法。静态路由、RIP、OSPF在中小网络里各有位置,不能说谁绝对好。我在小型分支网络或者只有一条上联链路的场景里,仍然会选静态路由——配置简单、依赖少、出问题一眼能看懂。RIP在现代主流网络里已经很难见到,只偶尔在老设备或极简环境里碰到,它最大的短板是跳数上限限制了规模,而且收敛速度实在不敢恭维。
OSPF适合中大型网络、多链路冗余、需要快速收敛的场景。它带来的复杂度是真金白银的学习成本和维护成本,但网络规模过了某个临界点,这些成本完全值得。如果让我给一个粗略判断标准:设备少于10台、拓扑基本是放射状、链路收敛要求不高,静态路由够用;设备超过20台或者有多条冗余链路,直接上OSPF,别再无休止地配静态路由了。
6.2 版本与厂商差异,怎么少走弯路
现在说的OSPF一般指OSPFv2,运行在IPv4网络;IPv6环境要用OSPFv3。协议本质相同,但LSA类型和命令差距不小,如果网络要做IPv6改造,这个版本差异一定要提前考虑。设备厂商之间的命令差异也真实存在,同样是区域汇总,一类设备叫abr-summary,另一类叫range,含义类似但写法不同,跨厂商混合组网时配置脚本必须分开写。
还有个常见误会:不少人以为OSPF只能在硬件路由器和三层交换机上跑,其实Linux上也能用FRR或Quagga这类软件路由套件跑OSPF,做实验和模拟训练非常方便。我在家里搭实验环境时,就用一台普通机器加GNS3或EVE-NG模拟整张网络,故障模拟、反复试错都不心疼,等到了现场操作时反而心里特别有底。
做了这么多年运维,我个人的体会是:OSPF玩得溜不溜,不在于背了多少条命令,而在于能不能快速看懂邻居状态、路由表和LSDB这三样东西。配置敲错大多数时候不是大事,最多改回来;真正容易出大事的是动手之前没想清楚区域归属、认证时机和汇总边界这些设计问题。建议你学完这篇之后,先在虚拟环境里把单区域、多区域、认证、汇总全部练一遍,再故意制造几个故障——邻居Down、路由断、认证失效——把整个排查流程走熟,真上了生产网络遇到问题就不会慌。
还有一个扩展方向值得提一句:OSPF结合BFD(双向转发检测)可以把故障感知从秒级缩短到毫秒级,对核心链路切换要求高的网络非常有用。这算是OSPF配置系列后面值得单独写一篇的主题,如果大家有兴趣,我找时间再展开讲讲。