老实说第一次把 MGRE 和 OSPF 这两个词放在同一个拓扑里时我脑子里全是问号一个多点GRE隧道怎么把动态路由跑起来NHRP 解析出来的是物理地址OSPF 关心的是隧道口逻辑地址这两者怎么捏到一块但后来在分支较多、链路又抖的组网里踩了几次坑我才真正体会到这套组合的实用价值。这篇文章不追概念主要聊聊 MGREOSPF 的组网设计、配置思路、OSPF 特殊区域在分支场景里的作用以及我实际排障中遇到过的典型问题。适合正在做企业网、广域网改造或者备考高级网络认证的朋友参考。1. 为什么偏偏是 MGREOSPF而不是点对点 GRE 加静态路由1.1 点对点隧道和静态路由的瓶颈先说个最熟悉的场景总部一台核心路由器下面挂了三十个分支。如果按传统思路做点对点 GRE 隧道总部隧道接口上得建三十个子接口或者三十个独立 tunnel每加一个分支就要复制一整段配置光看配置就足够让人头大。更要命的是OSPF 或者 EIGRP 跑在点对点隧道上的时候每个隧道都是独立邻居关系总部要维护三十个邻居状态分支一跳总部就要跟着抖一下。如果不用动态路由纯靠静态路由一开始还能撑住但当分支数量上来之后链路切换、新增网段、路由去重这些事会变得非常痛苦。尤其是总部和分支之间经常出现“同一份业务流量有两条可以走的路径”静态路由在策略调整时很容易出现黑洞排障时还得一台一台设备翻路由表。我见过不少项目早期用静态路由撑了两年后来加分支加网段加到无法维护最后还是要回到动态路由。1.2 MGRE 把隧道从“一对一”变成“一对多”MGRE 的核心价值就是在一个逻辑隧道接口上承载多个远端站点。它本身是 GRE 的一种多点模式不预设固定的对端隧道地址而是借助 NHRP 协议来动态学习每个分支的物理地址。分支上线后向中心注册自己的隧道地址和真实物理地址中心侧收到注册消息后维护一张动态映射表。这样一来中心只需要一个 tunnel 接口不管接三十个分支还是一百个分支接口配置都是同一份分支无论怎么变换出口地址只要还能和中心互通就能自动完成注册和路由更新。很多朋友一听到 MGRE 就会想到加密和防篡改其实 MGRE 本身只是一层封装不提供加密能力。通常项目里要在隧道外面再挂加密或者认证机制才能真正用于公网环境。这也是我在工程交付里反复强调的一点MGRE 解决的是“动态组网”问题安全加固是另一层事情不能因为隧道通了就觉得万事大吉。1.3 OSPF 在动态隧道上的不可替代性为什么非要用 OSPF不能用静态或者 RIPOSPF 的优势在于它能感知链路状态的变化在隧道抖动时快速收敛它支持按区域隔离路由抖动避免一个分支刷屏影响全网它还能做路由汇总和特殊区域规划把分支路由器上的路由表体积降下来。对 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 的优先级要调到 255Spoke 的优先级必须设为 0。如果不这么做某些分支可能在重新启动或拨号地址变化后抢到 DR 角色路由震荡和表项不一致的情况就会陆续出现。与此同时OSPF 的 Hello 报文默认走组播地址Hub 上必须配置ip nhrp map multicast dynamic让 NHRP 知道把组播报文复制给哪些动态注册上来的 SpokeSpoke 上则需要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. 从零开始配置 MGREOSPF附完整命令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.1Spoke1 是 10.0.0.2Spoke2 是 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 0Hub 通过 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.3Router 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 ospfHub 上应该出现分支局域网的路由Spoke 上应该出现默认路由或者远端分支路由。测试三层连通性从 Spoke1 ping Spoke2 的隧道地址再 ping 对方局域网地址确认封装和路由都没问题。如果show ip ospf neighbor里邻居卡在 INIT 或 EXSTART优先检查 NHRP 组播映射、MTU 和 Hello 计时器。这三个问题占了 MGREOSPF 排障案例里的一大半。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 上配置 NSSArouter 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.0Area 1 内的明细路由就不会以零散 Type 3 的形式全部进入 Area 0而是被聚合成一条汇总路由。这样 Hub 的路由表保持精简远端分支也只看到汇总路由收敛速度会明显改善。汇总配置需要注意一点汇总地址必须能完整覆盖区域内所有明细网段否则会出现部分网段不可达。每次新增分支网段时先确认是否落在汇总范围内再更新设备配置这是我被真实项目教训出来的习惯。5. 真实环境排错与避坑实录5.1 OSPF 邻居起不来的三大类原因MGREOSPF 排障最常碰到的就是邻居状态卡在 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 RequestHub 帮它找到目标 Spoke 的物理地址两个 Spoke 之间直接建立动态隧道。但这个机制落到 OSPF 设计上就有个需要注意的地方。如果采用广播网络类型且 Spoke 优先级为 0OSPF 邻居关系只在 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 分支网关延迟波动很大排查了很久才发现是二层路径和三层层路径不一致。所以做 MGREOSPF 方案时一定要先梳理清楚分支局域网里的二层拓扑和网关归属再动路由配置。5.5 分支拨号地址变化后的重收敛问题很多分支的出口地址是动态获取的每隔一段时间就会变化。Spoke 的物理地址变了之后NHRP 需要重新注册OSPF 邻居需要重新建立期间业务会中断。要减少这种抖动可以调短 NHRP 的注册间隔和 OSPF 的 Hello/Dead 计时器但也不能调得太激进否则链路稍微波动一下全网都在重算 SPF。我习惯的做法是保持 OSPF Hello 10 秒、Dead 40 秒的默认节奏不刻意追求秒级收敛对于更敏感的业务依靠跟链路状态联动的接口跟踪机制而不是把所有计时器卷到极限。这里有一条实测心得分支设备的拨号地址变化时如果 Hub 上残留了旧 NHRP 映射OSPF 邻居可能不会立刻重建。排障时先clear ip nhrp清掉旧映射再观察注册过程能省掉很多瞎猜的时间。6. 关于这套方案我在实际项目里的几点体会MGREOSPF 不算什么新技术但它对工程习惯的考验比一般静态组网大得多。我做过不少分支互联项目最大的感受是协议本身只是引子真正决定项目质量的是对链路模型、路由区域、故障边界的设计。MGRE 把物理链路变成了一张动态逻辑网OSPF 又把这张网变成了有序的层次化路由结构两者配合得当几十甚至上百个分支都能稳定运行配合不当两台设备都可能一直互相折腾。再分享一个细节分支数量一旦超过二十个我一定会在 Hub 上把 OSPF 的 LSA 洪泛限制、路由汇总和区域规划提前做掉而不是等到路由表爆炸了才去救火。隧道 MTU、物理接口协商模式、NHRP 注册间隔这些参数也会在开局阶段统一固化下来。这套习惯帮我躲过了很多“半夜被叫起来处理分支失联”的情况如果你也正在规划类似的组网希望这些经验能让你少走几步弯路。