DMVPN Phase 2 on Cisco IOS-XE: Hub-and-Spoke VPN with NHRP and Dynamic Tunnels

DMVPN Phase 2 on Cisco IOS-XE: Hub-and-Spoke VPN with NHRP and Dynamic Tunnels

What Is DMVPN and Why Does Phase 2 Matter?

If you’ve ever managed a hub-and-spoke WAN where branch offices need to communicate directly—without backhauling every packet through headquarters—you already understand the pain that DMVPN Phase 2 solves. Dynamic Multipoint VPN (DMVPN) is one of Cisco’s most flexible overlay technologies, and Phase 2 specifically unlocks spoke-to-spoke tunnels that form on demand, with no static configuration required at the hub.

DMVPN runs on top of three key technologies: mGRE (multipoint GRE tunnels), NHRP (Next Hop Resolution Protocol), and IPsec. The hub acts as the NHRP Next Hop Server (NHS). Spokes register their public WAN IPs with the hub when they come online. When Spoke A needs to reach Spoke B, it sends an NHRP resolution request to the hub, learns Spoke B’s public IP, and a direct IPsec-protected GRE tunnel forms dynamically between them.

Here’s how the three phases differ:

  • Phase 1: All spoke-to-spoke traffic is hairpinned through the hub. Simple to configure, but the hub is a bottleneck and single point of failure for inter-spoke traffic.
  • Phase 2: Spokes can form direct tunnels to each other via NHRP resolution. The routing protocol must preserve the originating spoke’s tunnel IP as the next-hop—not the hub’s. This is the most widely deployed phase.
  • Phase 3: Uses NHRP shortcut routing and redirects (ip nhrp redirect / ip nhrp shortcut), which reduces the routing table requirements at spokes. Requires IOS 12.4(6)T or later.

This guide focuses entirely on Phase 2 on Cisco IOS-XE, using IKEv2 for the IPsec underlay and EIGRP for overlay routing. We’ll cover a three-site lab (one hub, two spokes), full IPsec and NHRP configuration, the two critical EIGRP commands engineers routinely miss, and a complete verification and troubleshooting section.


Lab Topology

Our lab uses the following addressing. All three routers run Cisco IOS-XE 17.x (tested on CSR1000v and Cat8000v). WAN interfaces are assumed to have full Internet reachability.

Device Role WAN (Public) IP Tunnel IP LAN
HUB-R1 Hub (NHS) 203.0.113.1 10.0.0.1/24 192.168.1.0/24
SPOKE-R1 Spoke 1 198.51.100.10 10.0.0.2/24 192.168.2.0/24
SPOKE-R2 Spoke 2 198.51.100.20 10.0.0.3/24 192.168.3.0/24

IPsec Configuration (IKEv2) — Applied to All Routers

We configure IPsec in transport mode, not tunnel mode. GRE already handles the tunnel encapsulation; adding IPsec tunnel mode on top would double-encapsulate and waste 20+ bytes per packet. Apply the following identically on all three routers:

! IKEv2 Proposal - AES-256, SHA-256, DH Group 14
crypto ikev2 proposal DMVPN_PROP
 encryption aes-cbc-256
 integrity sha256
 group 14
!
crypto ikev2 policy DMVPN_POL
 proposal DMVPN_PROP
!
! Wildcard keyring - accepts dynamic spoke addresses
crypto ikev2 keyring DMVPN_KEYRING
 peer ANY_SPOKE
  address 0.0.0.0 0.0.0.0
  pre-shared-key local C1sc0DMVPN!Secure99
  pre-shared-key remote C1sc0DMVPN!Secure99
 !
!
! IKEv2 Profile - match any remote identity
crypto ikev2 profile DMVPN_IKEv2_PROF
 match address local interface GigabitEthernet1
 match identity remote address 0.0.0.0
 authentication remote pre-share
 authentication local pre-share
 keyring local DMVPN_KEYRING
!
! Transform-set in transport mode
crypto ipsec transform-set DMVPN_TS esp-aes 256 esp-sha256-hmac
 mode transport
!
! IPsec profile referenced by the tunnel interface
crypto ipsec profile DMVPN_IPSEC_PROFILE
 set transform-set DMVPN_TS
 set ikev2-profile DMVPN_IKEv2_PROF
!

The match address local interface GigabitEthernet1 line anchors IKE to your WAN interface. On physical Cat8000 hardware this is often GigabitEthernet0/0/0; adjust to match your platform. The wildcard peer (address 0.0.0.0 0.0.0.0) is what allows dynamic spoke IPs—no pre-provisioning needed when a new branch comes online.


Hub Configuration (HUB-R1)

The hub runs a multipoint GRE interface and acts as the NHRP Next Hop Server. It does not need static NHRP maps for spokes—they register dynamically at boot:

interface Tunnel0
 description DMVPN Phase 2 Hub
 ip address 10.0.0.1 255.255.255.0
 no ip redirects
 ip nhrp authentication NHRPAUTH1
 ip nhrp map multicast dynamic
 ip nhrp network-id 100
 ip nhrp holdtime 600
 ip mtu 1400
 ip tcp adjust-mss 1360
 tunnel source GigabitEthernet1
 tunnel mode gre multipoint
 tunnel key 100
 tunnel protection ipsec profile DMVPN_IPSEC_PROFILE

A few parameters deserve explanation:

  • ip nhrp map multicast dynamic — instructs NHRP to replicate multicast frames (EIGRP hellos, OSPF hellos) to all dynamically registered spokes. Without this, the overlay routing protocol loses adjacency to every spoke.
  • ip nhrp holdtime 600 — the hub advertises a 600-second hold time to spokes in NHRP registration replies. Spokes re-register at one-third of this interval (~200 seconds). The default is 7200 seconds; shorter values speed up convergence when spoke WAN IPs change.
  • ip mtu 1400 / ip tcp adjust-mss 1360 — GRE adds 24 bytes of overhead; IPsec in transport mode adds ~50 more. Reducing MTU prevents fragmentation over 1500-byte WAN paths. The MSS clamp ensures TCP sessions self-limit below the reduced MTU.
  • no ip redirectscritical on the hub tunnel. Without this, IOS-XE may generate ICMP redirects when it routes between two spokes, which breaks the Phase 2 tunnel formation logic.

Spoke Configuration

Spokes differ from the hub in two ways: they provide a static NHRP map for the hub’s tunnel IP and public IP, and they specify the hub as their NHS. Apply this to SPOKE-R1:

interface Tunnel0
 description DMVPN Phase 2 Spoke-1
 ip address 10.0.0.2 255.255.255.0
 no ip redirects
 ip nhrp authentication NHRPAUTH1
 ip nhrp map multicast 203.0.113.1
 ip nhrp map 10.0.0.1 203.0.113.1
 ip nhrp network-id 100
 ip nhrp holdtime 600
 ip nhrp nhs 10.0.0.1
 ip mtu 1400
 ip tcp adjust-mss 1360
 tunnel source GigabitEthernet1
 tunnel mode gre multipoint
 tunnel key 100
 tunnel protection ipsec profile DMVPN_IPSEC_PROFILE

For SPOKE-R2, only the tunnel IP changes:

interface Tunnel0
 description DMVPN Phase 2 Spoke-2
 ip address 10.0.0.3 255.255.255.0
 no ip redirects
 ip nhrp authentication NHRPAUTH1
 ip nhrp map multicast 203.0.113.1
 ip nhrp map 10.0.0.1 203.0.113.1
 ip nhrp network-id 100
 ip nhrp holdtime 600
 ip nhrp nhs 10.0.0.1
 ip mtu 1400
 ip tcp adjust-mss 1360
 tunnel source GigabitEthernet1
 tunnel mode gre multipoint
 tunnel key 100
 tunnel protection ipsec profile DMVPN_IPSEC_PROFILE

Both spokes map hub tunnel IP 10.0.0.1 to hub public WAN IP 203.0.113.1. When SPOKE-R1 needs to reach SPOKE-R2, it sends an NHRP resolution request to the hub. The hub replies with SPOKE-R2’s public WAN IP (198.51.100.20). SPOKE-R1 then builds a direct IPsec/GRE tunnel to that address—all dynamically, with zero hub involvement after the initial NHRP exchange.


EIGRP for Phase 2 — The Two Commands Engineers Miss

This is where most DMVPN Phase 2 deployments silently fail. In Phase 1, EIGRP behavior on the hub tunnel doesn’t matter because all traffic routes through the hub anyway. In Phase 2, two default EIGRP behaviors completely break direct spoke-to-spoke routing.

The problem: When EIGRP on the hub learns 192.168.2.0/24 from SPOKE-R1 and re-advertises it to SPOKE-R2, it sets the next-hop to the hub’s own tunnel IP (10.0.0.1) by default. SPOKE-R2 then sends traffic for 192.168.2.0/24 to the hub—Phase 2 spoke-to-spoke tunnels never form. Additionally, EIGRP split-horizon prevents the hub from re-advertising spoke routes out the same multipoint tunnel interface it learned them on, so spokes never even see each other’s prefixes.

The fix: two interface-level commands on the hub’s Tunnel0:

! Hub EIGRP configuration
router eigrp 100
 network 10.0.0.0 0.0.0.255
 network 192.168.1.0 0.0.0.255
 no auto-summary
!
! Hub Tunnel0 - Phase 2 critical overrides
interface Tunnel0
 no ip split-horizon eigrp 100
 no ip next-hop-self eigrp 100

Standard EIGRP on the spokes, no special knobs needed:

! SPOKE-R1
router eigrp 100
 network 10.0.0.0 0.0.0.255
 network 192.168.2.0 0.0.0.255
 no auto-summary
!
! SPOKE-R2
router eigrp 100
 network 10.0.0.0 0.0.0.255
 network 192.168.3.0 0.0.0.255
 no auto-summary

What these two commands do:

  • no ip split-horizon eigrp 100 — disables EIGRP’s rule of not re-advertising routes back out the interface they arrived on. Required here because the hub has a single mGRE interface facing all spokes; with split-horizon enabled, it would suppress routes learned from SPOKE-R1 when advertising to SPOKE-R2.
  • no ip next-hop-self eigrp 100 — the decisive one. Stops EIGRP from rewriting the next-hop to the hub’s own address. With it enabled, SPOKE-R2 receives 192.168.2.0/24 with next-hop 10.0.0.2 (SPOKE-R1’s tunnel IP). The first packet triggers NHRP resolution, and the direct spoke-to-spoke tunnel forms.

These don’t require an EIGRP neighbor reset to take effect—changes propagate in the next EIGRP update cycle.


Verification

DMVPN tunnel state — run on the hub:

HUB-R1# show dmvpn
Legend: Attrb --> S - Static, D - Dynamic, I - Incomplete
        N - NATed, L - Local, X - No Socket
        # Ent --> Number of NHRP entries with same NBMA peer
        NHS Status: E --> Expecting Replies, R --> Responding, W --> Waiting

Interface: Tunnel0, IPv4 NHRP Details
Type:Hub, NHRP Peers:2,

 # Ent  Peer NBMA Addr    Peer Tunnel Add  State  UpDn Tm   Attrb
 -----  ---------------  ---------------  -----  --------  -----
     1  198.51.100.10    10.0.0.2          UP    00:12:43  D
     1  198.51.100.20    10.0.0.3          UP    00:11:07  D

Both spokes show UP with a D (Dynamic) attribute. An NHRP state instead of UP means NHRP registration is pending—verify authentication strings match and that spokes have IP connectivity to the hub’s WAN IP before the tunnel is referenced.

NHRP cache on a spoke — showing both static hub entry and dynamic spoke entry:

SPOKE-R1# show ip nhrp
10.0.0.1/32 via 10.0.0.1
   Tunnel0 created 00:14:02, never expire
   Type: static, Flags: used
   NBMA address: 203.0.113.1

10.0.0.3/32 via 10.0.0.3
   Tunnel0 created 00:02:18, expire 00:07:42
   Type: dynamic, Flags: router used nhop
   NBMA address: 198.51.100.20

The second entry is the dynamic cache for SPOKE-R2, created when the first spoke-to-spoke packet triggered an NHRP resolution request. The expire timer counts down from the negotiated hold time (600 seconds); the spoke re-resolves before expiry if traffic is flowing.

IPsec sessions — confirming spoke-to-spoke IKEv2:

SPOKE-R1# show crypto ikev2 session
 IPv4 Crypto IKEv2 Session

Session-id:1, Status:UP-ACTIVE, IKE count:1, CHILD count:1
Tunnel-id  Local                  Remote                 fvrf/ivrf    Status
1          198.51.100.10/500      203.0.113.1/500         none/none    READY
      Encr: AES-CBC, keysize: 256, PRF: SHA256, Hash: SHA256, DH Grp:14
      Auth sign: PSK, Auth verify: PSK
      Life/Active Time: 86400/872 sec

Session-id:2, Status:UP-ACTIVE, IKE count:1, CHILD count:1
Tunnel-id  Local                  Remote                 fvrf/ivrf    Status
2          198.51.100.10/500      198.51.100.20/500       none/none    READY
      Encr: AES-CBC, keysize: 256, PRF: SHA256, Hash: SHA256, DH Grp:14
      Auth sign: PSK, Auth verify: PSK
      Life/Active Time: 86400/91 sec

Session 1 is the hub tunnel (established at boot); session 2 is the direct spoke-to-spoke IKEv2 session formed 91 seconds ago after NHRP resolution.

Confirm Phase 2 routing (the key test):

SPOKE-R1# show ip route eigrp
D     192.168.1.0/24 [90/27008000] via 10.0.0.1, 00:13:44, Tunnel0
D     192.168.3.0/24 [90/28160000] via 10.0.0.3, 00:13:12, Tunnel0

The route to SPOKE-R2’s LAN (192.168.3.0/24) has next-hop 10.0.0.3, not 10.0.0.1. That’s the confirmation that no ip next-hop-self eigrp 100 is working. If you see 10.0.0.1 as next-hop for every remote LAN, the command is missing on the hub tunnel.


Troubleshooting Common Phase 2 Issues

Spokes reach the hub but not each other

Almost always the missing no ip next-hop-self eigrp 100. Verify with show ip route eigrp on a spoke. If all remote LANs point to 10.0.0.1, add the command to the hub Tunnel0 interface. It takes effect on the next EIGRP update cycle without resetting neighbors.

NHRP state stuck at “NHRP” instead of “UP”

Mismatched NHRP authentication strings silently drop registrations. Enable debug to confirm:

HUB-R1# debug nhrp error
*Sep 18 03:14:22.881: NHRP: Receive Registration Request via Tunnel0 vrf 0
*Sep 18 03:14:22.882: NHRP: Auth failure - source 198.51.100.10, Mismatch

Also verify tunnel key matches on all interfaces—a mismatched key causes GRE packets to be silently dropped before NHRP even runs.

IPsec tunnels form but traffic drops intermittently

MTU/fragmentation. Check show interfaces Tunnel0 for input drops or giants. Reduce ip mtu to 1380 and the MSS clamp to 1340 as a diagnostic step. Use extended ping with the df-bit option to find the actual path MTU:

SPOKE-R1# ping 10.0.0.3 size 1400 df-bit repeat 5
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 8/9/11 ms

SPOKE-R1# ping 10.0.0.3 size 1450 df-bit repeat 5
.....
Success rate is 0 percent (5/5)

The failure at 1450 bytes confirms fragmentation is occurring. Reduce ip mtu until pings succeed, then set ip tcp adjust-mss 40 bytes below that value.

EIGRP neighbor flapping on the tunnel

EIGRP hellos rely on multicast replication across the DMVPN cloud. Verify ip nhrp map multicast dynamic is on the hub and ip nhrp map multicast 203.0.113.1 is on every spoke. If multicast is unreliable on the WAN, switch to unicast EIGRP neighbors on the spokes:

router eigrp 100
 neighbor 10.0.0.1 Tunnel0   ! Spoke only - unicast hellos to hub

Spoke-to-spoke tunnels not forming after NHRP resolution succeeds

Confirm no ip redirects is on the hub Tunnel0. Also check if spokes are behind NAT—DMVPN Phase 2 with NAT requires ip nhrp registration no-unique on spokes plus careful NHRP map entries that account for the NAT’d outside address.


Using BGP Instead of EIGRP

Many operators prefer iBGP for DMVPN overlays, particularly when the hub is a route reflector or when the WAN spans multiple ASes. BGP avoids the split-horizon complexity of EIGRP on mGRE entirely, and dynamic neighbor discovery via bgp listen range eliminates per-spoke neighbor statements. For a deeper look at BGP policy and filtering, see our guide on how BGP runs the internet.

! Hub as iBGP Route Reflector with dynamic spoke peering
router bgp 65000
 bgp listen range 10.0.0.0/24 peer-group DMVPN_SPOKES
 neighbor DMVPN_SPOKES peer-group
 neighbor DMVPN_SPOKES remote-as 65000
 neighbor DMVPN_SPOKES update-source Tunnel0
 neighbor DMVPN_SPOKES route-reflector-client
 !
 address-family ipv4
  neighbor DMVPN_SPOKES activate
  neighbor DMVPN_SPOKES next-hop-unchanged
 exit-address-family
!
! Spoke iBGP (same AS)
router bgp 65000
 neighbor 10.0.0.1 remote-as 65000
 neighbor 10.0.0.1 update-source Tunnel0
 !
 address-family ipv4
  neighbor 10.0.0.1 activate
 exit-address-family

The BGP equivalent of no ip next-hop-self eigrp 100 is neighbor DMVPN_SPOKES next-hop-unchanged under the address-family. Without it, the route reflector rewrites the BGP next-hop to its own tunnel IP, and Phase 2 spoke-to-spoke tunnels never form—exactly the same failure mode as with EIGRP.


Production Operational Tips

Dual-hub redundancy: Never deploy a single hub in production. Use two hubs in separate failure domains. Spokes configure both NHS addresses with priority values:

ip nhrp nhs 10.0.0.1 nbma 203.0.113.1 priority 1 cluster 1
ip nhrp nhs 10.1.0.1 nbma 203.0.113.2 priority 2 cluster 1

NHRP fails over to the secondary NHS automatically when the primary stops responding to NHRP resolution requests.

QoS on the hub: The hub handles all initial spoke-to-hub traffic and multicast replication, making it the first bottleneck under load. Apply QoS marking on the hub’s Tunnel0 to prioritize voice and interactive traffic. Our Cisco QoS guide for voice and video on IOS-XE covers the DSCP marking and LLQ queuing strategies that work best on DMVPN tunnel interfaces.

Automate spoke provisioning: With more than ten spoke sites, manual configuration becomes error-prone and slow. Templating spoke tunnel configuration with Python and Netmiko lets you push consistent configs to new branches in seconds, with NHRP NHS addresses and IPsec profiles rendered from a single Jinja2 template. A new site becomes a one-line YAML entry.

NHRP hold time tuning: The default 7200-second hold time is too slow for environments where spokes have dynamic WAN IPs (DHCP, LTE failover). A spoke that gets a new WAN IP from its ISP will remain in the hub’s NHRP table with the stale address for up to two hours. Setting ip nhrp holdtime 300-600 on all tunnel interfaces provides faster NHRP convergence at the cost of slightly more registration traffic.

Monitor tunnel state with SNMP: Poll ifOperStatus for Tunnel0 on all spokes via SNMP v3, and set alerts for spoke count drops on the hub via show dmvpn parsed through EEM or your monitoring stack. NHRP peer count dropping unexpectedly often indicates a BGP or EIGRP issue before users even notice.


Wrapping Up

DMVPN Phase 2 is the right choice when you need dynamic spoke-to-spoke connectivity on existing IOS-XE infrastructure without the overhead of a controller-based SD-WAN deployment. The architecture is clean: one multipoint GRE tunnel per router, IKEv2 protecting everything dynamically, and NHRP doing the address resolution that makes it all work without static configuration.

The entire Phase 2 feature lives or dies on two EIGRP commands at the hub: no ip split-horizon eigrp 100 and no ip next-hop-self eigrp 100. Miss either one and you get a functioning Phase 1 that silently backhauled all inter-spoke traffic through headquarters. Get them both right and every spoke can tunnel directly to every other spoke, on demand, with zero pre-provisioning.

If your WAN requirements are growing toward centralized policy management, zero-touch provisioning, or application-aware routing, Cisco SD-WAN (Viptela/Catalyst SD-WAN) is the natural evolution of the DMVPN model. But for networks already running IOS-XE 16.x or 17.x with proven hub hardware, Phase 2 delivers the full dynamic spoke-to-spoke capability you need without a controller refresh.

Enjoying this post?

Get more guides like this delivered straight to your inbox. No spam, just tech and trails.