This is the complete, working DMVPN Phase 3 build: one hub, two spokes, a router simulating the internet underlay, EIGRP over the top, every command shown and every verification step captured from live IOS XE 17.18 devices. Nothing here is theoretical output; if a counter or a flag appears, a lab produced it. Concepts are covered in DMVPN explained and the phase logic in Phase 1 vs 2 vs 3; this article is the hands-on companion in the DMVPN cluster.
Topology and Addressing
Four routers. INET sits in the middle pretending to be the internet, with documentation-range /30s toward each site. Each site router has a loopback standing in for its LAN.
The overlay is Tunnel0 on 10.0.0.0/24 everywhere. NHRP network-id 1, authentication string PLZ123, GRE tunnel key 100. If you are reproducing this in CML, iol-xe nodes boot in seconds and handle everything except IPsec (for encrypted tunnels use Catalyst 8000v, covered in the IPsec article).
Step 1: The Underlay
Spokes and hub each need exactly one thing from the underlay: reachability to each other's tunnel source addresses. A static default toward INET does it, mirroring a real internet edge:
! HUB
interface Ethernet0/1
ip address 203.0.113.1 255.255.255.252
no shutdown
ip route 0.0.0.0 0.0.0.0 203.0.113.2
! SPOKE1 (SPOKE2 mirrors with 192.0.2.x)
interface Ethernet0/1
ip address 198.51.100.1 255.255.255.252
no shutdown
ip route 0.0.0.0 0.0.0.0 198.51.100.2Sanity check before touching any tunnel: every router must ping every other router's underlay address. Skipping this check is the number one way to spend an hour debugging NHRP when the actual problem is underlay routing.
Step 2: The Hub Tunnel
interface Tunnel0
description DMVPN hub - mGRE
ip address 10.0.0.1 255.255.255.0
no ip redirects
ip mtu 1400
ip tcp adjust-mss 1360
ip nhrp authentication PLZ123
ip nhrp network-id 1
ip nhrp redirect
tunnel source Ethernet0/1
tunnel mode gre multipoint
tunnel key 100Line by line, the ones that matter. tunnel mode gre multipoint makes this one interface serve every spoke. ip nhrp redirect is the Phase 3 half that belongs on the hub: it fires an NHRP redirect at any spoke whose traffic hairpins through this interface. ip mtu 1400 and ip tcp adjust-mss 1360 pre-empt fragmentation blackholes (GRE eats 24 bytes, IPsec eats more; the arithmetic is in GRE MTU and fragmentation). tunnel key 100 tags the GRE packets, which must match on every router in this cloud. On IOS XE 17.x you no longer need ip nhrp map multicast dynamic on an mGRE hub; it is the default and will not even appear in the running config. Notably absent: any mention of any spoke.
Step 3: The Spoke Tunnels
interface Tunnel0
description DMVPN spoke - mGRE
ip address 10.0.0.2 255.255.255.0
no ip redirects
ip mtu 1400
ip tcp adjust-mss 1360
ip nhrp authentication PLZ123
ip nhrp map 10.0.0.1 203.0.113.1
ip nhrp map multicast 203.0.113.1
ip nhrp network-id 1
ip nhrp nhs 10.0.0.1
ip nhrp shortcut
tunnel source Ethernet0/1
tunnel mode gre multipoint
tunnel key 100SPOKE2 is identical except its own addresses (tunnel IP 10.0.0.3, source e0/1 on 192.0.2.1). The five NHRP lines do all the work: map bootstraps the hub's overlay-to-underlay binding, map multicast lets routing protocol hellos reach the hub, nhs declares who to register with, and shortcut is the Phase 3 half that belongs on spokes, accepting redirects and installing shortcut routes. Spokes never reference other spokes; that is the entire point.
Step 4: Verify Registration Before Routing
Within seconds of the tunnels coming up, both spokes register. On the hub:
HUB# show dmvpn
Type:Hub, NHRP Peers:2,
# Ent Peer NBMA Addr Peer Tunnel Add State UpDn Tm Attrb
----- --------------- --------------- ----- -------- -----
1 198.51.100.1 10.0.0.2 UP 00:01:35 D
1 192.0.2.1 10.0.0.3 UP 00:01:31 DBoth peers UP and D (dynamically learned). If a peer sits in NHRP state instead, stop and fix registration first (troubleshooting DMVPN diagnoses the three classic causes with captures). Routing on a broken NHRP layer is wasted effort.
Step 5: EIGRP Named Mode Over the Tunnel
! HUB
router eigrp PINGLABZ
address-family ipv4 unicast autonomous-system 100
af-interface Tunnel0
no split-horizon
exit-af-interface
network 10.0.0.0 0.0.0.255
network 10.0.100.0 0.0.0.255
exit-address-family
! SPOKE1 (SPOKE2 mirrors with 10.0.2.0)
router eigrp PINGLABZ
address-family ipv4 unicast autonomous-system 100
network 10.0.0.0 0.0.0.255
network 10.0.1.0 0.0.0.255
exit-address-familyThe single non-default line is no split-horizon on the hub's tunnel af-interface: without it, EIGRP refuses to re-advertise SPOKE1's routes back out Tunnel0 to SPOKE2, and the spokes never learn each other's LANs. Next-hop-self stays at its default (enabled), which is correct for Phase 3. Both spokes come up as neighbors over the multicast maps:
HUB# show ip eigrp neighbors
H Address Interface Hold Uptime SRTT RTO Q Seq
1 10.0.0.3 Tu0 11 00:01:30 11 1398 0 3
0 10.0.0.2 Tu0 11 00:01:35 7 1398 0 4And the spoke RIB shows every remote prefix via the hub, which is the correct resting state for Phase 3 (the design trade-offs, including the OSPF alternative, are in routing over DMVPN):
SPOKE1# show ip route eigrp
D 10.0.2.0/24 [90/102400640] via 10.0.0.1, 00:00:29, Tunnel0
D 10.0.100.0/24 [90/76800640] via 10.0.0.1, 00:00:29, Tunnel0Step 6: Watch the Shortcut Form
Send spoke-to-spoke traffic and run the same traceroute twice. The first flows through the hub and triggers the redirect; the second goes direct:
SPOKE1# traceroute 10.0.2.1 source Loopback1 numeric
1 10.0.0.1 2 msec 1 msec 2 msec
2 10.0.0.3 3 msec * 2 msec
SPOKE1# traceroute 10.0.2.1 source Loopback1 numeric
1 *
10.0.0.3 4 msec *Three commands prove what happened. The NHRP cache now holds a shortcut for the remote prefix (nho flag) and the resolved peer (nhop rib):
SPOKE1# show ip nhrp
10.0.0.3/32 via 10.0.0.3
Tunnel0 created 00:00:09, expire 00:09:50
Type: dynamic, Flags: router nhop rib
NBMA address: 192.0.2.1
10.0.2.0/24 via 10.0.0.3
Tunnel0 created 00:00:09, expire 00:09:50
Type: dynamic, Flags: router used rib nho
NBMA address: 192.0.2.1The RIB keeps the EIGRP route at the hub and overrides its next hop (the % and [NHO] markers, plus an H route for the peer):
SPOKE1# show ip route next-hop-override
H 10.0.0.3/32 is directly connected, 00:00:09, Tunnel0
D % 10.0.2.0/24 [90/102400640] via 10.0.0.1, 00:00:57, Tunnel0
[NHO][90/255] via 10.0.0.3, 00:00:09, Tunnel0And show dmvpn shows the two shortcut entry types, route-installed and next-hop-override:
SPOKE1# show dmvpn
# Ent Peer NBMA Addr Peer Tunnel Add State UpDn Tm Attrb
----- --------------- --------------- ----- -------- -----
1 203.0.113.1 10.0.0.1 UP 00:02:26 S
2 192.0.2.1 10.0.0.3 UP 00:00:09 DT1
10.0.0.3 UP 00:00:09 DT2Leave the traffic idle for the NHRP holdtime (10 minutes by default) and all of it unwinds: the dynamic entries expire, forwarding falls back to the hub, and the next traffic burst rebuilds the shortcut. That self-cleaning behavior is Phase 3 working as designed. The message-level mechanics behind the redirect are in the NHRP deep dive.
The Mistakes That Cost the Most Lab Time
Having built this exact topology more than once, here is where the time actually goes. Forgetting ip nhrp map multicast on a spoke: pings to the hub work, EIGRP never forms, and you debug the routing protocol for an hour when the problem is NHRP replication. Mismatched tunnel key: both interfaces up/up, everything dead, hub logs nothing, because GRE drops keyed packets before NHRP sees them. Forgetting no split-horizon on the hub: both spokes neighbor with the hub and learn the hub's LAN, but never each other's, which looks exactly like a filtering problem. Testing with unsourced pings: ping 10.0.2.1 from SPOKE1 sources from the tunnel interface and works even when LAN-to-LAN forwarding is broken, so always test with source Loopback1 the way the captures here do. And impatience with the shortcut: the redirect only fires on hairpinned data traffic, so a freshly cleared cache legitimately shows the hub path on the first packets. Each of these produces a distinct capture signature, all cataloged in troubleshooting DMVPN.
Worth repeating from the phase article because it defuses a common review comment: the NHRP network-id does not need to match between routers. Ours matches everywhere because uniformity is easier to operate, not because the protocol requires it. What must genuinely match across the cloud: the NHRP authentication string, the tunnel key, and the overlay subnet.
Verifying From a Real Host (bridge1)
Loopbacks prove routing; a real client proves the design. In our lab, the hub's e0/0 faces an external connector at 192.168.99.1/24 with a Debian VM at 192.168.99.100 behind it, and that subnet rides the same EIGRP process over the tunnel (network 192.168.99.0 in the hub's address-family). The spokes learn it like any other prefix:
SPOKE1# show ip route eigrp
D 192.168.99.0/24 [90/77312000] via 10.0.0.1, 00:00:29, Tunnel0Add a static route on the VM pointing 10.0.0.0/16 at 192.168.99.1 and the Linux host can reach every spoke LAN across the overlay. The same pattern (real host, external connector, overlay route) upgrades any CML lab from ping-between-loopbacks to something you can drive iperf and packet captures through.
Production Deltas
Four gaps between this lab and a deployable design. Encryption: internet transport means IPsec, added purely with a tunnel protection profile and an IKEv2 policy, no DMVPN changes (full build here). Summarization: with more than a handful of spokes, advertise a summary or default from the hub instead of individual prefixes; Phase 3 shortcuts keep working because NHRP resolution carries the specifics. Hub redundancy: a second hub is a second ip nhrp nhs line on every spoke (priorities and clusters control preference). Front-door VRF: production designs usually put the underlay in an fVRF (tunnel vrf INTERNET) so the default route toward the ISP cannot collide with the overlay's routing, a recursion problem explained in GRE tunnel troubleshooting.
Key Takeaways
A Phase 3 DMVPN is startlingly little configuration: an mGRE tunnel with five NHRP lines per spoke, two Phase 3 commands (redirect on the hub, shortcut on spokes), one split-horizon exception in EIGRP, and MTU/MSS clamps. Verify in layers, in order: underlay pings, then show dmvpn registration on the hub, then routing adjacencies, then the two-traceroute shortcut test with show ip route next-hop-override as the receipt. The hub scales because it knows nothing about individual spokes, and the shortcuts self-expire because they are cache entries, not routes. Next steps in the cluster: encrypt it, then break it on purpose, with the full map in the DMVPN complete guide.