老实说,第一次把 MGRE 和 OSPF 这两个词放在同一个拓扑里时,我脑子里全是问号:一个多点GRE隧道,怎么把动态路由跑起来?NHRP 解析出来的是物理地址,OSPF 关心的是隧道口逻辑地址,这两者怎么捏到一块?但后来在分支较多、链路又抖的组网里踩了几次坑,我才真正体会到这套组合的实用价值。这篇文章不追概念,主要聊聊 MGRE+OSPF 的组网设计、配置思路、OSPF 特殊区域在分支场景里的作用,以及我实际排障中遇到过的典型问题。适合正在做企业网、广域网改造,或者备考高级网络认证的朋友参考。
1. 为什么偏偏是 MGRE+OSPF,而不是点对点 GRE 加静态路由
1.1 点对点隧道和静态路由的瓶颈
先说个最熟悉的场景:总部一台核心路由器,下面挂了三十个分支。如果按传统思路做点对点 GRE 隧道,总部隧道接口上得建三十个子接口或者三十个独立 tunnel,每加一个分支就要复制一整段配置,光看配置就足够让人头大。更要命的是,OSPF 或者 EIGRP 跑在点对点隧道上的时候,每个隧道都是独立邻居关系,总部要维护三十个邻居状态,分支一跳,总部就要跟着抖一下。
如果不用动态路由,纯靠静态路由,一开始还能撑住,但当分支数量上来之后,链路切换、新增网段、路由去重这些事会变得非常痛苦。尤其是总部和分支之间经常出现“同一份业务流量有两条可以走的路径”,静态路由在策略调整时很容易出现黑洞,排障时还得一台一台设备翻路由表。我见过不少项目早期用静态路由撑了两年,后来加分支加网段加到无法维护,最后还是要回到动态路由。
1.2 MGRE 把隧道从“一对一”变成“一对多”
MGRE 的核心价值,就是在一个逻辑隧道接口上承载多个远端站点。它本身是 GRE 的一种多点模式,不预设固定的对端隧道地址,而是借助 NHRP 协议来动态学习每个分支的物理地址。分支上线后向中心注册自己的隧道地址和真实物理地址,中心侧收到注册消息后维护一张动态映射表。这样一来,中心只需要一个 tunnel 接口,不管接三十个分支还是一百个分支,接口配置都是同一份;分支无论怎么变换出口地址,只要还能和中心互通,就能自动完成注册和路由更新。
很多朋友一听到 MGRE 就会想到加密和防篡改,其实 MGRE 本身只是一层封装,不提供加密能力。通常项目里要在隧道外面再挂加密或者认证机制,才能真正用于公网环境。这也是我在工程交付里反复强调的一点:MGRE 解决的是“动态组网”问题,安全加固是另一层事情,不能因为隧道通了就觉得万事大吉。
1.3 OSPF 在动态隧道上的不可替代性
为什么非要用 OSPF,不能用静态或者 RIP?OSPF 的优势在于:它能感知链路状态的变化,在隧道抖动时快速收敛;它支持按区域隔离路由抖动,避免一个分支刷屏影响全网;它还能做路由汇总和特殊区域规划,把分支路由器上的路由表体积降下来。对 MGRE 这种中心辐射型拓扑来说,OSPF 的 DR/BDR 机制尤其合适——中心节点当 DR,分支节点不参与选举,分支之间不需要建立邻居关系,全网邻居数量被压到最低。
相比之下,RIP 虽然配置简单,但跳数限制和慢收敛在大分支场景基本不可用。BGP 当然也能跑,但在这种纯内部路由互联的场景里,BGP 的配置复杂度、策略模型和故障排查成本都比 OSPF 高不少。所以我个人在实际项目里的选择很明确:MGRE 做隧道底座,OSPF 做路由承载。
2. 组网架构与关键原理拆解
2.1 典型拓扑中的角色划分
这套方案通常会把设备分成 Hub 和 Spoke 两类角色。Hub 是中心设备,承担 NHRP 服务器、OSPF DR、路由汇聚的责任;Spoke 是分支设备,通过 MGRE 隧道接入中心。Hub 的隧道接口有一个固定的逻辑地址,所有 Spoke 的隧道接口都分配在同一个子网里,比如 10.0.0.0/24。Spoke 通过 NHRP 把自身隧道地址映射到出口物理地址,并注册到 Hub 上。
这种架构最舒服的地方在于扩展性。新分支机构上线时,只需要在 Spoke 侧配置隧道接口、NHRP 参数、OSPF 进程,然后接上物理线路,隧道会自动建立,OSPF 邻居会自动起来,远端网段会自动出现在路由表里。总部不需要为每个新分支单独加隧道配置,运维成本大幅降低。
2.2 NHRP 在连接建立过程中的关键作用
NHRP 解决的是“逻辑地址到物理地址的映射”问题。一句话解释:OSPF 在隧道接口上看到的邻居是 10.0.0.2、10.0.0.3,但它不知道这些逻辑地址对应的物理出口在哪里,NHRP 负责把 10.0.0.2 映射到 198.51.100.2,把 10.0.0.3 映射到 198.51.100.3。
实际建立隧道的过程是这样的:Spoke 启动后,根据配置中的 NHS 地址向 Hub 发送 NHRP Registration Request,带上自己的隧道地址和物理地址;Hub 收到后记录在 NHRP 缓存表里,并通过 Registration Reply 确认。之后 Spoke 再发送 NHRP Resolution Request 去解析其他目的地址。如果数据流量需要 Spoke 之间直连,第一个 Spoke 向 Hub 查询目标 Spoke 的物理地址,拿到映射结果后直接封装 GRE 报文发过去,走的是动态按需直连。
因此很多排障都是从 NHRP 表开始的。隧道接口配置再好看,NHRP 没有注册成功,OSPF 邻居就不可能起来。这个顺序必须搞清楚。
2.3 OSPF 在 MGRE 隧道上的网络类型选择
MGRE 隧道接口在 OSPF 看来,既不是标准的广播网络,也不是标准的非广播多点接入网络。默认情况下,很多设备会把隧道口认出一种可以承载广播的链路,但实际组播报文的转发能力完全依赖 NHRP 的多播映射,不像传统以太网那样天然具备组播复制能力。
所以实际工程中,我通常会在 Hub 和 Spoke 的 Tunnel 接口上显式设置ip ospf network broadcast,让 OSPF 走 DR/BDR 选举模式。这样做的理由很直接:Spoke 之间不需要建立完整 OSPF 邻居,只要 Hub 作为 DR 和所有 Spoke 保持邻接关系即可,全网路由收敛依赖 Hub 汇总,邻居规模小、状态干净,故障面可控。如果采用 point-to-multipoint,虽然也能跑,但 Spoke 之间容易形成额外的邻居关系,而且在分支较多时路由条目会变得碎片化,不是我最喜欢的选择。
这里要特别强调 DR 优先级的设计:Hub 的优先级要调到 255,Spoke 的优先级必须设为 0。如果不这么做,某些分支可能在重新启动或拨号地址变化后抢到 DR 角色,路由震荡和表项不一致的情况就会陆续出现。与此同时,OSPF 的 Hello 报文默认走组播地址,Hub 上必须配置ip nhrp map multicast dynamic,让 NHRP 知道把组播报文复制给哪些动态注册上来的 Spoke;Spoke 上则需要ip nhrp map multicast指向 Hub 的物理地址。
2.4 OSPF 特殊区域在大规模分支场景里的价值
分支数量上来以后,OSPF 最大的敌人是路由条目过多和 LSA 泛滥。如果把所有分支都塞进 Area 0,每加一个分支,全网都要处理一套新的链路状态通告,任何一段链路抖动都可能引发大面积 SPF 重算。解决思路是分层:隧道互联放在 Area 0,每个分支的局域网划分到独立的非骨干区域,并借助 Stub 或 NSSA 特殊区域把分支路由器上的路由表精简到最低。
特殊区域的作用不是减少全网路由数据,而是让区域边界路由器(ABR)不把外部路由、明细路由全量灌进叶节点。比如 Stub 区域不允许 Type 4/5 LSA 进入,区域内的路由器只需要默认路由加本区域明细;Total Stub 更狠,连 Type 3 汇总路由都不放进去,只剩默认路由和直连路由。NSSA 则是在需要引入外部路由但又不想让 Type 5 进入区域时使用,允许通过 Type 7 LSA 承载外部路由,再由 ABR 转换。
这个设计在分支路由器内存有限、性能一般的场景里特别实用。分支设备只要知道“默认路由指向总部”,加上自己局域网内的明细,就能正常转发绝大部分流量,而不必关心全网有哪些外部路由。
3. 从零开始配置 MGRE+OSPF,附完整命令
3.1 地址规划和拓扑说明
我以一个简单的两分支环境来演示。Hub 侧物理接口接在 192.168.255.0/24 这个网段,Loopback0 的地址是 192.168.255.1/32,作为隧道源和 Router ID。两个 Spoke 的物理接口地址分别是 192.168.255.2/24 和 192.168.255.3/24。MGRE 隧道接口统一使用 10.0.0.0/24 网段,Hub 隧道地址是 10.0.0.1,Spoke1 是 10.0.0.2,Spoke2 是 10.0.0.3。两个分支的局域网分别是 10.1.1.0/24 和 10.1.2.0/24,后续要把它们划进独立区域。
这个规划里有三条纪律:第一,Loopback0 不要宣告进 OSPF,否则隧道源地址被 OSPF 学到以后会出现递归路由;第二,隧道接口的 MTU 建议调到 1400 左右,避免封装后数据包超过承载网络 MTU 被分片;第三,OSPF 的 Hello/Dead 计时器在 Hub 和 Spoke 上必须一致,不然邻居永远起不来。
3.2 Hub 侧配置
Hub 上的关键配置如下:
interface Loopback0 ip address 192.168.255.1 255.255.255.255 interface Tunnel0 ip address 10.0.0.1 255.255.255.0 ip mtu 1400 ip nhrp network-id 100 ip nhrp map multicast dynamic ip ospf network broadcast ip ospf priority 255 ip ospf hello-interval 10 ip ospf dead-interval 40 tunnel mode gre multipoint tunnel source Loopback0 router ospf 1 router-id 192.168.255.1 network 10.0.0.0 0.0.0.255 area 0tunnel mode gre multipoint是 Hub 侧和 Spoke 侧的区别所在,Hub 上不能配置tunnel destination,否则就退化成点对点隧道了。ip nhrp network-id 100是 NHRP 域的标识,所有隧道路由器必须一致。ip nhrp map multicast dynamic是关键,它让 Hub 把 OSPF 组播报文复制给所有已注册的 Spoke。OSPF 部分把隧道网段放进 Area 0,Hub 通过 DR 角色和所有 Spoke 建立邻接关系。
3.3 Spoke 侧配置
Spoke1 的配置如下:
interface Loopback0 ip address 192.168.255.2 255.255.255.255 interface GigabitEthernet0/0 ip address 192.168.255.2 255.255.255.0 interface Tunnel0 ip address 10.0.0.2 255.255.255.0 ip mtu 1400 ip nhrp network-id 100 ip nhrp nhs 10.0.0.1 nbma 192.168.255.1 ip nhrp map multicast 192.168.255.1 ip ospf network broadcast ip ospf priority 0 ip ospf hello-interval 10 ip ospf dead-interval 40 tunnel mode gre multipoint tunnel source GigabitEthernet0/0 tunnel destination 192.168.255.1 router ospf 1 router-id 192.168.255.2 network 10.0.0.0 0.0.0.255 area 0 network 10.1.1.0 0.0.0.255 area 1Spoke 和 Hub 的差异主要有三处。第一,ip nhrp nhs 10.0.0.1 nbma 192.168.255.1告诉分支去哪个逻辑地址、哪个物理地址找中心服务器。第二,tunnel destination 192.168.255.1是分支建立隧道时的初始目标,Hub 因为没有固定目标所以不写这条。第三,OSPF 优先级别忘了是 0,而且分支本地局域网网段10.1.1.0/24被放进了 Area 1,不是 Area 0,这样才符合分支分层设计。
Spoke2 的配置跟 Spoke1 基本一致,只需要把隧道地址换成 10.0.0.3,Router ID 换成 192.168.255.3,局域网网段换成 10.1.2.0/24。
3.4 配置完成后的验证命令
配置完成以后,我一般按以下顺序验证:
- 在 Spoke 上查 NHRP 注册是否成功:
show ip nhrp,能看到目标地址、物理地址和标志位。 - 在 Hub 上查 OSPF 邻居:
show ip ospf neighbor,正常状态下应该看到 Spoke 处于 Full 状态,而且 Hub 是 DR,没有 BDR。 - 查看路由表:
show ip route ospf,Hub 上应该出现分支局域网的路由,Spoke 上应该出现默认路由或者远端分支路由。 - 测试三层连通性:从 Spoke1 ping Spoke2 的隧道地址,再 ping 对方局域网地址,确认封装和路由都没问题。
如果show ip ospf neighbor里邻居卡在 INIT 或 EXSTART,优先检查 NHRP 组播映射、MTU 和 Hello 计时器。这三个问题占了 MGRE+OSPF 排障案例里的一大半。
3.5 换到 H3C 或华为设备时的移植思路
很多朋友问过我,这套方案在 H3C 或者华为设备上能不能直接照搬。路由协议部分是可以的,H3C 的 OSPF 配置也是基于ospf进程、area和network通配符来写的,思路一样,验证命令也接近,比如用display ospf peer看邻居、用display ospf routing看路由。但隧道部分不同厂商实现差异较大,H3C 和华为在分支互联场景里有自己的动态隧道方案,和 Cisco 的 MGRE 并不是完全一比一对应。
所以我的建议是:路由设计和区域规划完全可以参考本文这套思路,但具体隧道接口、NHRP 或动态解析的命令,必须以设备实际版本的手册为准。项目交付前先在测试环境搭一对设备验证,不要直接用生产设备反复试错。
4. OSPF 特殊区域的实际配置与应用
4.1 Stub 与 Total Stub 的取舍
回到上面的拓扑,Spoke1 的局域网在 Area 1。为了让 Spoke1 的路由表尽量精简,可以在 Spoke1 上把 Area 1 配置成 Stub 或 Total Stub。Stub 区域的特点是:区域内部依然交换 Type 1/2 路由,允许 Type 3 汇总路由进入,但不接受 Type 4/5 外部路由,区域边界路由器会自动向区域内注入一条默认路由。Total Stub 则更严格,连 Type 3 汇总路由都不放进来,区域内路由器只保留本区域明细和一条默认路由。
分支路由器只需要访问总部和其他分支时,Total Stub 是最合适的。它让分支设备的路由表体积降到最低,SPF 计算量和内存占用都会小很多。但如果分支需要访问某个外部重分发进来的网段,且总部没有通过默认路由覆盖所有外部路由,那就得考虑 NSSA,而不是 Stub。
4.2 Stub 区域的配置实例
Spoke1 上配置 Area 1 为 Total Stub,只需要在 OSPF 进程中加一条命令:
router ospf 1 area 1 stub no-summary network 10.0.0.0 0.0.0.255 area 0 network 10.1.1.0 0.0.0.255 area 1area 1 stub no-summary只在 ABR 上配置,也就是在同时连接 Area 0 和 Area 1 的 Spoke1 上配置。这条命令让 ABR 不向 Area 1 发送 Type 3 明细路由,同时自动生成一条默认路由下发。所有和 Area 1 相连的非 ABR 成员设备上只需要配置area 1 stub,两边必须一致,否则邻居会因为区域类型不匹配而无法建立。
如果想控制默认路由的度量值,可以用area 1 default-cost 20这样的命令调大默认路由开销,让分支优先走本地直连路由,在总部链路质量较差时也能实现简单的策略引流。
4.3 NSSA 区域与外部路由引入
分支经常有通过静态路由、其他动态路由引入的网段。如果这些外部路由要从分支进入 OSPF,但又不想把 Type 5 LSA 灌进整个 OSPF 域,可以用 NSSA 区域。NSSA 允许外部路由以 Type 7 LSA 的形式进入区域,到达 ABR 后再转换成 Type 5 LSA 向其他区域传播。这样外部路由只在本区域内以 Type 7 存在,不会在其他区域形成原始的 Type 5 风暴。
在 Spoke1 上配置 NSSA:
router ospf 1 area 1 nssa network 10.0.0.0 0.0.0.255 area 0 network 10.1.1.0 0.0.0.255 area 1 redistribute static subnets这里用redistribute static subnets把分支的静态路由引入 OSPF。NSSA 区域内的普通路由器不需要额外命令,但 ABR 上默认不会自动产生默认路由。如果希望区域内路由器也有一条指向总部的默认路由,需要加上area 1 nssa default-information-originate,让 ABR 生成 Type 7 默认路由。
4.4 多分支汇聚时的路由汇总策略
分支多了以后,如果每个分支都有好几个网段,Hub 的路由表也会膨胀。此时可以在每个分支 ABR 上做区域间汇总。例如 Spoke1 把局域网地址规划成 10.1.0.0/16 下的一段,在 OSPF 进程里配置area 1 range 10.1.0.0 255.255.0.0,Area 1 内的明细路由就不会以零散 Type 3 的形式全部进入 Area 0,而是被聚合成一条汇总路由。这样 Hub 的路由表保持精简,远端分支也只看到汇总路由,收敛速度会明显改善。
汇总配置需要注意一点:汇总地址必须能完整覆盖区域内所有明细网段,否则会出现部分网段不可达。每次新增分支网段时,先确认是否落在汇总范围内,再更新设备配置,这是我被真实项目教训出来的习惯。
5. 真实环境排错与避坑实录
5.1 OSPF 邻居起不来的三大类原因
MGRE+OSPF 排障最常碰到的就是邻居状态卡在 DOWN 或 INIT。这类问题的根源一般不在 OSPF 本身,而在隧道封装层。最常见的原因是 NHRP 没有完成注册,show ip nhrp查不到对方映射,OSPF 的组播 Hello 报文根本送不到对端。解决办法是先确认 Spoke 的路由表里有没有到 Hub 物理地址的路由,再用 ping 测试物理互通性,最后回头查 NHRP 注册。
第二类原因是 MTU 不一致。GRE 封装会额外增加 24 字节左右的开销,如果隧道和数据链路层 MTU 设置不当,大包会被分片,OSPF 邻居状态会反复卡在 EXSTART。遇到这种问题,我一般先把所有隧道接口的 MTU 统一设置成 1400,再把物理接口 MTU 调到 1500 或以上,这样能避开大部分分片坑。第三类原因是 OSPF Hello/Dead 计时器不一致,有些朋友在 Hub 上调了计时器,Spoke 忘了调,邻居就会一直在 DOWN 和 INIT 之间循环。
5.2 递归路由问题
这个坑很容易被忽略。Hub 的隧道源地址是 Loopback0 上的 192.168.255.1,如果我不小心把network 192.168.255.0 0.0.0.255 area 0也写进了 OSPF,那么 OSPF 会通过隧道学到这条路由。下一跳指向隧道对端,而隧道源地址本身又是 192.168.255.1,数据包访问这个地址时会被重新丢回隧道,形成递归循环。轻则路由表诡异,重则隧道直接断掉。
解决方法是:隧道源地址所在的 Loopback 不要宣告进 OSPF。为了让 OSPF 有稳定的 Router ID,可以单独用router-id命令指定,不需要把 Loopback 网段放进去。这个细节我在项目里强调过很多遍,因为报错现象并不直观,查路由表半天才能反应过来。
5.3 Spoke 之间直连流量的 NHRP 解析
中心辐射型拓扑下,Spoke 访问 Spoke 的流量默认也要经过 Hub 转发。在某些场景里,我们希望两个分支之间的流量通过 MGRE 隧道直连,不绕总部。这种需求要靠 NHRP 的解析机制实现:第一个 Spoke 向 Hub 发送 Resolution Request,Hub 帮它找到目标 Spoke 的物理地址,两个 Spoke 之间直接建立动态隧道。
但这个机制落到 OSPF 设计上,就有个需要注意的地方。如果采用广播网络类型且 Spoke 优先级为 0,OSPF 邻居关系只在 Hub 和 Spoke 之间建立,Spoke 之间的路由仍然通过 Hub 学习,本身不会因为 NHRP 直连而改变。所以想让数据平面直连,还需要在路由层面做策略配合,否则流量可能还是会被 OSPF 下一跳指到 Hub。这个问题在 DMVPN 类方案中经常被讨论,核心就是控制面和数据面要分开考虑。
5.4 与 MSTP、VRRP 等二层高可用技术叠加时的注意事项
分支局域网里通常还会涉及 MSTP 和 VRRP。MSTP 负责二层环路消除和负载均衡,VRRP 负责网关冗余。OSPF 跑在三层,和它们的关系属于“船和桥”的关系,但船撞桥的事情还是会发生。举个例子,VRRP 主备切换之后,如果 OSPF 接口状态没有变化,路由并不会跟着切换,流量仍可能被发往原来的下一跳。这时候需要在 VRRP 和 OSPF 之间做联动,比如通过 Track 监视上行接口,主备切换时同步调整 OSPF 接口开销或者强制路由收敛。
MSTP 的实例划分也会影响 VRRP 的负载均衡。如果两个 VLAN 的根桥和主网关不在同一台设备上,二层流量绕路、三层流量直走,就会出现转发不对称,严重情况下还会引发丢包。我遇到过一个分支网络,MSTP 实例划分和 VRRP 主备配置完全相反,结果从总部 ping 分支网关延迟波动很大,排查了很久才发现是二层路径和三层层路径不一致。所以做 MGRE+OSPF 方案时,一定要先梳理清楚分支局域网里的二层拓扑和网关归属,再动路由配置。
5.5 分支拨号地址变化后的重收敛问题
很多分支的出口地址是动态获取的,每隔一段时间就会变化。Spoke 的物理地址变了之后,NHRP 需要重新注册,OSPF 邻居需要重新建立,期间业务会中断。要减少这种抖动,可以调短 NHRP 的注册间隔和 OSPF 的 Hello/Dead 计时器,但也不能调得太激进,否则链路稍微波动一下,全网都在重算 SPF。我习惯的做法是保持 OSPF Hello 10 秒、Dead 40 秒的默认节奏,不刻意追求秒级收敛;对于更敏感的业务,依靠跟链路状态联动的接口跟踪机制,而不是把所有计时器卷到极限。
这里有一条实测心得:分支设备的拨号地址变化时,如果 Hub 上残留了旧 NHRP 映射,OSPF 邻居可能不会立刻重建。排障时先clear ip nhrp清掉旧映射,再观察注册过程,能省掉很多瞎猜的时间。
6. 关于这套方案,我在实际项目里的几点体会
MGRE+OSPF 不算什么新技术,但它对工程习惯的考验比一般静态组网大得多。我做过不少分支互联项目,最大的感受是:协议本身只是引子,真正决定项目质量的是对链路模型、路由区域、故障边界的设计。MGRE 把物理链路变成了一张动态逻辑网,OSPF 又把这张网变成了有序的层次化路由结构,两者配合得当,几十甚至上百个分支都能稳定运行;配合不当,两台设备都可能一直互相折腾。
再分享一个细节:分支数量一旦超过二十个,我一定会在 Hub 上把 OSPF 的 LSA 洪泛限制、路由汇总和区域规划提前做掉,而不是等到路由表爆炸了才去救火。隧道 MTU、物理接口协商模式、NHRP 注册间隔这些参数,也会在开局阶段统一固化下来。这套习惯帮我躲过了很多“半夜被叫起来处理分支失联”的情况,如果你也正在规划类似的组网,希望这些经验能让你少走几步弯路。