MGRE 这个技术点,单拎出来看其实不复杂,一个隧道接口、几条 NHRP 命令就能起来。但一旦把它塞进综合实验里——底下接着不同的接入链路、上面跑着动态路由、旁边还挂着 ACL 和地址转换——情况就完全不一样了。我见过太多人 MGRE 单点实验做得飞快,一进综合场景就卡在"隧道是 up 的,邻居起不来"这种状态上一整晚。这篇就聊聊我把 MGRE 和综合实验揉在一起时踩过的那些坑,从地址规划到 NHRP 注册、从 OSPF 邻居卡在 ExStart 到分支互通只走中心绕路,一条链路一条链路地捋清楚。不管你是刚接触隧道技术,还是已经能背下命令但总在联调环节翻车,下面的内容应该都能对上你的痛点。
1. 点到点 GRE 的窘境:MGRE 要填的到底是哪个坑
1.1 一条隧道一根线的代价
GRE 本身是个很朴素的东西,把一种协议的数据包整个打包进另一种协议里发走。点到点的 GRE 隧道,思路就像在两栋楼之间拉一根专线:A 端配一个 Tunnel 接口,B 端配一个 Tunnel 接口,两端 source 和 destination 互相指定,隧道就起来了。
问题出在规模上。假设中心要连 20 个分支,每个分支都跟中心拉一条点到点隧道,中心设备上就得有 20 个 Tunnel 接口。每个接口一套 IP、一套路由、一套 ACL,配置量是线性膨胀的。更麻烦的是维护:新加一个分支,中心要新建接口、加路由、改策略;一个分支下线,还得挨个清理。这种结构在实验室里跑三个节点看不出问题,真到几十个节点就开始失控。
我第一次做多点组网的时候就是这么硬堆的,中心那台设备的配置翻了三屏还没翻完,后来改一个分支的地址,漏改了某个 ACL,排查了两个小时才发现。那次之后就明白,点到点 GRE 的瓶颈不在技术本身,在可维护性。
1.2 NBMA 思维:把一个接口当成一个网段
MGRE 的核心转变是:中心只用一个 Tunnel 接口,就承载所有分支。这个接口在逻辑上被当成一个多路访问网段来用——中心是 10.1.1.1/24,分支分别是 10.1.1.2、10.1.1.3……全都在这一个 /24 里。
这个模型跟帧中继、ATM 那套 NBMA(非广播多路访问)的思路是一脉相承的:物理上分支之间没有直连,逻辑上却在同一个网段。中心节点扮演的角色类似于一个"虚拟交换机",但它不是真的在二层转发,而是靠 NHRP 告诉分支"你要找的那个地址,它的公网出口在哪里"。
这里有个容易混淆的点:Tunnel 接口是 multipoint 的,意味着它不能像点到点接口那样靠"对端就一个"来推断目的地址。每发一个包,设备都得查一次 NHRP 表,问"这个内层目的地址对应哪个外层地址"。所以 MGRE 能不能跑通,八成取决于 NHRP 表里有没有正确的条目。很多人配置时把注意力全放在 tunnel source 和地址上,忽略了 NHRP,结果隧道 up 但什么都通不了。
1.3 综合实验要验证的边界在哪里
单纯做 MGRE,验证的东西有限:隧道起来、能 ping 通、NHRP 表有记录,就结束了。但综合实验的意义在于,它逼你把 MGRE 和别的技术放在一起,看它们会不会打架。
我在设计这类实验时,一般会明确几个验证目标:分支通过中心动态学习路由,而不是写静态;分支之间的流量能不能不经过中心绕行;隧道上叠加安全保护之后,MTU 会不会成为新的瓶颈;中心的策略(比如 ACL、地址转换)在隧道封装前后分别作用在哪一层。这几个问题任何一个没想清楚,实验就只是"配置完能 ping 通",学不到东西。
提示:综合实验里最容易忽略的是"分层"这件事。物理链路、隧道链路、路由协议、安全策略是四层,每层的排错手段完全不同,混在一起看会把你绕晕。
2. 动手前先想清楚的三张表
2.1 分支数量决定 Tunnel 地址的分配方式
地址规划看着是体力活,实际上它直接决定了后面路由协议怎么配。Tunnel 网段我一般按分支最大规模来划,宁可浪费也不要用到一半发现不够。
假设分支数量在 10 到 30 之间波动,那就直接给一个 /24,够用到天荒地老。如果分支可能上百,就得往 /22 甚至 /21 考虑,因为后续如果要按区域做路由汇总,地址块得是连续的。
中心的 Tunnel 地址固定取网段第一个可用地址,分支按编号顺序往后排。这个约定听起来无所谓,但排错的时候特别有用:看到 10.1.1.7,你能立刻反应过来这是 7 号分支,直接去查那台设备的配置,不用翻表。
我这里要强调一个反面经验:不要给 Tunnel 网段和物理链路网段用相邻地址块。曾经有一次物理链路用 10.1.1.0/24,Tunnel 用 10.1.2.0/24,做路由汇总的时候一条10.1.0.0/16把两个网段一锅端了,结果路由指向了错误的方向,现象是"分支能 ping 通中心的隧道地址,但 ping 不通中心的内网口"。这种问题查起来极其恶心,因为它不报错,只是通不了。
2.2 三层地址要分得开
综合实验里至少要区分三种地址:
| 地址类型 | 作用范围 | 典型规划 | 备注 |
|---|---|---|---|
| 物理接口地址 | 公网/承载网 | 202.100.1.0/24 | 分支可能是动态获取 |
| Tunnel 接口地址 | 隧道逻辑网段 | 10.1.1.0/24 | 全网唯一,规划要留余量 |
| 业务网段地址 | 各分支内网 | 192.168.x.0/24 | 每个分支一段,不能重叠 |
业务网段这块是重灾区。多个分支的内网如果用了相同的私网地址段(比如都用 192.168.1.0/24),路由就会冲突,中心根本没法区分去哪个分支。这种场景要么做地址转换,要么从规划阶段就强制每个分支用不同网段。我在实验里一律采用后者,编号和分支号绑定,比如 3 号分支就是 192.168.3.0/24。
2.3 一张参数表管住所有节点
配置之前我会先手写一张参数表,把所有需要跨设备一致的参数列出来。MGRE 里最容易出错的就是"两端不一致",而这类错误往往不报错,只是静默失效。
| 参数 | 中心 | 分支 | 不一致的后果 |
|---|---|---|---|
| NHRP network-id | 100 | 100 | 注册失败,NHRP 表为空 |
| NHRP 认证口令 | lab123 | lab123 | 注册被拒 |
| Tunnel 网段掩码 | /24 | /24 | 路由表出现直连冲突 |
| Tunnel MTU | 1400 | 1400 | 大包不通,小包正常 |
| OSPF 区域号 | 0 | 0 | 邻居起不来 |
这张表看着土,但真能省下大量时间。我的做法是把它写在实验记录最前面,配置的时候逐行对照,配完一项划掉一项。特别是 network-id 和认证口令这两项,命令敲下去没有任何提示,配置成功与否全靠 NHRP 表来验证。
3. NHRP 才是 MGRE 的心脏
3.1 中心节点为什么必须是 NHS
NHRP 的角色分工很明确:NHS(Next Hop Server)负责登记和应答,NHC(Next Hop Client)负责注册和查询。在 MGRE 组网里,中心天然就是 NHS,因为所有分支都能访问到它,而分支之间互相不知道对方的公网地址。
中心要做的配置其实不多:指定 network-id、开启认证(可选但建议)、以及在隧道接口上允许接收注册请求。关键在于,中心自己不需要nhrp nhs指向自己,它只需要监听。这一点经常有人搞混,在中心也写了一行指向自己的 nhs,结果反而制造了环路。
分支侧的配置才是重点。它需要三样东西:一是 network-id 跟中心一致;二是nhrp nhs指向中心的 Tunnel 地址;三是一条静态映射,告诉设备"中心的 Tunnel 地址 10.1.1.1 对应的公网地址是 202.100.1.1"。第三条最容易被漏掉,因为很多人以为注册是自动的——确实,注册上去了之后是自动的,但第一次怎么找到中心,还是得靠这条静态映射。
3.2 注册失败先看这三样
分支启动之后,用display nhrp peer all或者show ip nhrp看表。如果表里只有一条指向中心的静态条目,没有任何动态条目,说明注册没成功。我一般按这个顺序排查:
第一,看 network-id。这是最高频的原因,因为命令敲下去没反馈。中心是 100,分支写成 1,注册包发过去直接被丢弃,日志里可能什么痕迹都没有。
第二,看认证。如果两边都配了认证但口令不一致,注册会被拒绝。有些平台会有日志提示,有些平台完全静默,只能靠对比配置。
第三,看源地址。隧道接口的 source 必须是一个真实可达的接口地址或者物理接口名。如果 source 写的是一个不存在的 Loopback,或者写了物理接口但那个接口没有可达路由,注册包根本发不出去。
注意:分支如果用的是动态公网地址(比如拨号或者地址池分配),中心的 NHRP 表里记的就是那个动态地址。地址变化之后,旧条目会残留一段时间,这期间可能出现"隧道 up 但流量走不通"的情况。可以在分支上加注册超时或者定期刷新,别指望它自己立刻更新。
3.3 手工映射和动态注册的取舍
小规模实验里,有人图省事直接在中心上给每个分支写静态 NHRP 映射,把分支的公网地址手工绑上去。这种做法的好处是确定性强,不依赖注册机制;坏处是分支地址一变就全废,而且要手工维护每一台。
我的建议是:分支地址固定(哪怕是私网固定地址)的时候,静态映射可以接受,调试起来直观;分支地址动态的时候,老老实实用注册。综合实验通常两种场景都会涉及,正好借这个机会把两条路都走一遍,对比一下 NHRP 表的差异——静态条目没有过期时间,动态条目有过期时间,这个区别在排错时很有参考价值。
4. 隧道上跑 OSPF 的两个隐形炸弹
4.1 网络类型不对,邻居关系就卡住
隧道接口的网络类型是个非常隐蔽的坑。不同平台在 multipoint 隧道上的默认网络类型不完全一样,有些按广播处理,有些按 NBMA 处理。如果按广播处理,OSPF 会在这个接口上做 DR/BDR 选举,而 MGRE 环境下分支之间根本没有二层连通性,选举过程就会出岔子——表现是分支只跟中心建立 FULL 邻居,分支之间永远停在 2-Way。
解决办法是把隧道接口的 OSPF 网络类型显式改成点对多点:
interface Tunnel0 ip ospf network point-to-multipoint改完之后,OSPF 不再做 DR 选举,每个分支都跟中心建立点到点式的邻接关系,路由也能正常泛洪。这一步我建议不管默认值是什么都手动写一遍,把行为固定下来,免得换平台之后踩同一个坑。
4.2 MTU 不一致:ping 得通但邻居起不来
这个坑比上一个更阴。现象是:分支能 ping 通中心的隧道地址,NHRP 表也正常,但 OSPF 邻居一直卡在 ExStart 或者 Exchange 状态,反复重传。
根因是 OSPF 在 DBD 报文里携带接口 MTU,两端 MTU 不一致就拒绝继续。隧道接口的 MTU 计算方式是:
Tunnel MTU = 物理接口 MTU - GRE 头(4 字节) - 外层 IP 头(20 字节) = 1500 - 24 = 1476如果一端手动设了 1400,另一端还是默认的 1476,邻居就起不来。这时候有两个选择:统一 MTU,或者在接口上加ospf mtu-ignore。
我一般倾向统一 MTU,因为 MTU 不一致不仅影响 OSPF,后面跑业务也会出问题——大包被丢,小包正常,ping 大包才暴露。统一设成 1400 是个稳妥值,给后续叠加安全封装留出余量。
| 场景 | 建议 Tunnel MTU | 说明 |
|---|---|---|
| 纯 GRE 封装 | 1476 | 理论值,实际可用 |
| GRE + 安全保护 | 1400 左右 | 预留 60-80 字节余量 |
| 多层嵌套封装 | 1360 或更低 | 每层都要扣,别贪多 |
配套还要调 TCP MSS:
interface Tunnel0 ip tcp adjust-mss 1360这条命令的作用是让经过隧道的 TCP 握手协商出更小的 MSS,避免大包在中间被分片或者丢弃。很多"网页打得开但传文件卡住"的怪现象,都是 MSS 没调导致的。
4.3 邻居起来之后还要看路由
邻居 FULL 只是第一步。我见过邻居全部 FULL、路由表也有条目,但分支之间 ping 不通的情况。这时候要看的不是 OSPF,是下一跳。
中心的分支路由,下一跳通常指向隧道接口,这是正常的。但如果中心的隧道接口配了水平分割(split horizon),从某个分支学到的路由不会再发回给其他分支,结果就是分支 A 到分支 B 的路由在中心被拦住了。解决办法是在中心的隧道接口上关掉水平分割,或者改用下一跳自反的写法。
关掉水平分割这件事要谨慎,它本来是为了防环设计的。在中心-分支这种星型结构里,分支不会把路由再传回中心,所以风险可控。但如果拓扑里有分支互联,就得换个思路。
5. 四类典型翻车现场的排查链路
5.1 隧道起来了但 NHRP 表是空的
这是最典型的一类。排查顺序我固定成这样:先在分支上看display nhrp nhs,确认 nhs 状态是不是 up;再在中心上看有没有收到注册请求的日志或者计数;然后核对 network-id 和认证;最后检查外层路由。
外层路由这条经常被漏。分支要能到达中心的公网地址,这个"到达"是走物理链路的默认路由或者明细路由。如果分支上没有指向中心公网地址的路由,注册包压根发不出去。表现是分支上 NHRP 表完全空白,甚至连静态条目都显示异常。
我遇到过一次特别隐蔽的:分支的默认路由指向了错误的下一跳,但因为实验环境里那台设备有别的路由能兜底,所以能 ping 通某些地址。这种半通不通的状态最难查,最后是逐跳 traceroute 才定位出来。
5.2 分支之间通不了,但都能通中心
这个现象说明注册和路由基本正常,问题出在转发路径上。三个可能:
- 中心没开 NHRP 重定向。不开的话,分支 A 要去分支 B,会把包发给中心,中心再转给分支 B,理论上能通但绕路。开了重定向之后,中心会回一个消息告诉分支 A"你直接找 B 的公网地址去",后续流量就直达了。
- 分支没开 shortcut。这个和重定向配套,重定向是中心告诉分支"换条路",shortcut 是分支接受这个建议并缓存。
- 中心的隧道接口上有一条阻止转发的策略或者水平分割。
验证方法很直接:在分支 A 上 traceroute 分支 B 的内网地址,看路径里有没有中心的隧道地址。有就是绕行,没有就是直达。
5.3 来回路径不一致导致的诡异丢包
综合实验里配了多条路径或者多张路由表的时候,很容易出现去程走隧道、回程走别的口的情况。表现是 ping 时通时不通,或者只有某个方向能通。
这类问题用 ping 是查不出来的,得看两端的路由表和接口计数。我的习惯是在两端同时起一个长时间的 ping,然后分别看各自的出接口计数有没有增长,哪边没增长就是哪边的回程有问题。
5.4 重启之后配置"莫名丢失"
这个问题坑了不少人。表现是设备断电重启之后,隧道不通了,检查配置发现全都在,但就是不通。
原因通常是 NHRP 的静态映射没保存,或者映射指向的地址在重启后变了(比如物理接口改用了地址池)。还有一种情况是隧道接口的 source 写的是接口名而不是地址,重启后那个接口的地址变化了,隧道 source 跟着变,但静态映射还指向旧地址。
我的处理办法是:静态映射尽量用接口名引用而不是硬编码地址;每次改完配置手动保存一次;在实验记录里注明哪些配置是易失的。
6. 给 MGRE 套一层保护:思路和顺序都很讲究
6.1 MGRE 天然适合和安全机制配合
MGRE 的封装流量本质上是点对点的外层通信,虽然逻辑上是多点的,但物理上每一对通信两端是明确的。这个特性让它特别适合在隧道外面再套一层加密保护:保护的是中心与分支之间的每一段外层通信。
需要注意的一点是,加密是在隧道封装之后做的,所以顺序是"内层包 → GRE 封装 → 加密 → 物理发送"。这个顺序决定了 MTU 的扣减要多算一层。加密后的外层头通常会增加 50 到 80 字节,所以 Tunnel MTU 要比单纯 GRE 场景再降一截,落到 1330 到 1380 之间比较稳。我一般直接取 1360,配ip tcp adjust-mss 1320。
6.2 分支地址动态时的保护方式
分支如果用的是动态地址,就没法用传统的静态对等体配置,因为对方的地址事先不知道。这时候通常有两种做法:
一种是把保护配置直接挂在隧道接口上,做成"隧道保护"模式,分支侧不指定对端地址,被动接受中心的协商请求。这种模式配置量小,适合分支多且地址不固定的场景。
另一种是在中心侧配动态映射,匹配条件写成"来源是隧道流量、对端地址未知",分支侧仍然用静态映射指向中心。这种写法更灵活,但调试起来复杂一些,因为匹配条件写错的时候不会有任何报错,只是协商不起来。
我倾向第一种,尤其是分支数超过五六台之后。配置量少意味着出错概率低。
6.3 配置顺序和验证方法
顺序上有个小技巧:先把 MGRE 和路由调通,确认分支之间能互通,再往上加保护。反过来的话,一旦加密配置有问题,你没法判断是隧道的问题还是加密的问题,排错范围直接翻倍。
验证的时候分三步:
- 确认隧道本身正常。看 NHRP 表有没有动态条目,看 OSPF 邻居是不是 FULL。
- 确认保护协商成功。看安全关联有没有建立,两端的保护参数是否匹配。
- 确认大包能过。用带大小的 ping 测,比如 1400 字节不分片,能通说明 MTU 和 MSS 都调对了。
ping -s 1400 -M do 10.1.1.1这条命令在分支上执行,-s指定包大小,-M do禁止分片。如果通,说明整条链路的 MTU 链路是健康的;如果报"需要分片",说明某一层的 MTU 还是偏大,回到接口上再降 20 字节试。
提示:加了保护之后,不要只看业务是否通,一定要专门测一次大包。很多实验环境里所有验证都用默认 64 字节的 ping,看着全通,实际业务一跑就卡,问题就出在这儿。
7. 几个只有踩过才知道的细节
说几个我在反复折腾中攒下来的经验,都是在文档里看不到的。
第一个,NHRP 的静态映射在分支上尽量用 multicast 一起配上。命令是nhrp map multicast <中心公网地址>。不配的话,路由协议的多播报文(比如 OSPF 的 hello)在多点隧道上可能发不出去,因为设备不知道多播该往哪几个对端复制。表现就是中心能看到分支的注册,但收不到分支的 hello。
第二个,中心的 Tunnel 接口上如果有访问控制策略,注意策略作用的是内层包还是外层包。隧道接口上的策略通常作用于解封装之后的内层流量,物理接口上的策略作用于封装之后的外层流量。这两者搞混了,会出现"策略明明放通了但流量还是被拦"的情况,因为拦它的其实是另一层。
第三个,实验做到一半改地址规划,一定要把 NHRP 缓存清掉。设备的 NHRP 表有老化时间,旧条目会在里面待好几分钟。你改完配置去测试,看到的可能是旧缓存造成的假象,误以为配置没生效。清缓存的命令各平台不太一样,但一般都有,实在找不到就重启隧道接口。
第四个,分支数量超过七八个之后,中心的 OSPF 邻居状态变化会很频繁,日志刷屏。这时候如果把日志级别调高,反而会把真正有用的信息淹掉。我的做法是实验阶段把邻居状态变化的日志单独过滤出来看,别一股脑全开着。
最后一个,也是我觉得最值得说的一条:这套东西的配置量其实不大,中心三四条、分支五六条,加起来不到二十行。但真正决定你能不能一次调通的,是配置之前的那张参数表和拓扑图。我现在的习惯是先在纸上把地址、网段、network-id、MTU 全写一遍,确认没有冲突再上设备敲。花十分钟画图,能省下两小时排错,这个投入产出比在任何网络实验里都成立。