Every interesting thing DMVPN does, it does with NHRP. Spokes appearing on the hub without configuration? NHRP registration. Spoke-to-spoke tunnels forming on demand? NHRP resolution. Phase 3's ability to summarize routes and still cut hub-free paths? NHRP redirects rewriting the forwarding table underneath the RIB. If you can read NHRP's three message flows in debug output, DMVPN stops being magic and starts being inspectable. This article walks all three with real debugs and cache states from an IOS XE 17.18 lab (one hub, two spokes). It assumes the component overview from DMVPN explained and slots into the wider DMVPN complete guide.
What NHRP Is Actually For
NHRP (RFC 2332) predates DMVPN; it was designed for resolving next hops across NBMA networks like Frame Relay and ATM. An mGRE cloud is just the modern NBMA network: every router can reach every other router, but nobody knows anybody's transport address in advance. NHRP fills exactly one gap: given an overlay (tunnel) IP, return the underlay (NBMA) IP where it lives. The analogy that holds up under pressure is ARP with a receptionist. Instead of broadcasting "who has 10.0.0.3?", you ask the one router that keeps the ledger: the Next Hop Server.
Keep the division of labor straight, because it explains half of all DMVPN confusion: NHRP maps tunnel addresses to transport addresses. It does not carry routes. Your routing protocol (see routing over DMVPN) advertises what networks exist; NHRP figures out how to deliver GRE packets to the routers that advertised them.
The Cast: NHS, NHC, and the Cache
The hub is the Next Hop Server (NHS), the authoritative ledger. Spokes are Next Hop Clients, each configured with the hub's overlay address (ip nhrp nhs 10.0.0.1) plus one static map bootstrapping how to reach it (ip nhrp map 10.0.0.1 203.0.113.1). Everything else in the system is learned. The ledger itself is the NHRP cache, and learning to read its flags pays off immediately:
SPOKE1# show ip nhrp
10.0.0.1/32 via 10.0.0.1
Tunnel0 created 00:02:25, 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: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.1Static entries come from config and never expire. Dynamic entries age out (default 10 minutes, shown counting down). The flags tell the story: registered means a spoke put it there via registration, nhop marks a resolved next hop, rib means NHRP handed it to the routing table, and nho means it is installed as a next-hop override, the Phase 3 mechanism. A local entry with (no-socket) is the router's own registration record of what it told the NHS about itself.
Flow 1: Registration, How the Hub Learns Everyone
When a spoke's tunnel comes up, it immediately registers with every configured NHS. Here is the exchange in debug nhrp packet on the spoke, captured by bouncing Tunnel0:
*Jul 11 18:39:31.271: NHRP: Attempting to send packet through interface Tunnel0 via DEST dst 10.0.0.1
*Jul 11 18:39:31.271: NHRP: Send Registration Request via Tunnel0 vrf: global(0x0), packet size: 106
*Jul 11 18:39:31.272: NHRP: 134 bytes out Tunnel0
*Jul 11 18:39:31.274: NHRP: Receive Registration Reply via Tunnel0 vrf: global(0x0), packet size: 126
*Jul 11 18:39:31.274: NHRP-EVE: NHS-UP: 10.0.0.1, NBMA: 203.0.113.1
*Jul 11 18:39:31.274: %DMVPN-5-NHRP_NHS_UP: Tunnel0: Next Hop Server : (Tunnel: 10.0.0.1 NBMA: 203.0.113.1) for (Tunnel: 10.0.0.2 NBMA: 198.51.100.1) is UPThe request carries the spoke's own binding (tunnel 10.0.0.2, NBMA 198.51.100.1). The hub caches it as a dynamic, registered entry and answers with a reply. Registrations refresh periodically (a fraction of the holdtime), so the hub's cache is self-healing: change a spoke's underlay address and the next registration overwrites the binding. Registrations also set a uniqueness flag by default, which stops a second device from registering an already-claimed tunnel address.
Registration health is the first thing to check on any DMVPN problem, and it has a dedicated command whose counters do the diagnosing for you:
SPOKE2# show ip nhrp nhs detail
Legend: E=Expecting replies, R=Responding, W=Waiting, D=Dynamic
Tunnel0:
10.0.0.1 E priority = 0 cluster = 0 req-sent 7 req-failed 0 repl-recv 0 (00:01:48 ago)
Pending Registration Requests:
Registration Request: Reqid 11, Ret 64 NHS 10.0.0.1 expired (Tu0)That capture is from a deliberately broken spoke: req-sent climbing while repl-recv stays at zero, NHS stuck in E (expecting replies). A healthy NHS shows RE with matching sent and received counters. The three configuration mistakes that produce exactly this signature are dissected in troubleshooting DMVPN.
Flow 2: Resolution, How Spokes Find Each Other
Registration only teaches the hub. When SPOKE1 wants to reach something behind SPOKE2 directly, it asks: an NHRP Resolution Request goes to the NHS, and (in Phase 3) the hub forwards it to the spoke that owns the answer, which replies directly to the asker. Both directions from the lab debug:
*Jul 11 18:42:31.141: NHRP: Send Resolution Request via Tunnel0 vrf: global(0x0), packet size: 86
*Jul 11 18:42:31.144: NHRP: Receive Resolution Reply via Tunnel0 vrf: global(0x0), packet size: 134
*Jul 11 18:42:31.146: NHRP: Receive Resolution Request via Tunnel0 vrf: global(0x0), packet size: 106
*Jul 11 18:42:31.146: NHRP: Send Resolution Reply via Tunnel0 vrf: global(0x0), packet size: 134
*Jul 11 18:42:31.146: %DMVPN-7-NHRP_RES: Tunnel0: Host with (Tunnel: 10.0.0.2 NBMA: 198.51.100.1) Received Resolution Req from (Tunnel: 10.0.0.3 NBMA: 192.0.2.1)Notice SPOKE1 both sends a resolution request (it wants SPOKE2's binding) and receives one (SPOKE2 wants SPOKE1's binding, because return traffic needs its own shortcut). Resolution replies populate the dynamic cache entries you saw above, and the resulting spoke-to-spoke tunnel shows up in show dmvpn as a D entry on both spokes. Idle entries expire with the holdtime and the mesh prunes itself back to hub-and-spoke.
The per-message-type counters are the fastest way to see which flow is happening (or failing) without a debug:
SPOKE1# show ip nhrp traffic
Tunnel0: Max-send limit:10000Pkts/10Sec, Usage:0%
Sent: Total 10
2 Resolution Request 2 Resolution Reply 5 Registration Request
0 Registration Reply 1 Purge Request 0 Purge Reply
0 Error Indication 0 Traffic Indication 0 Redirect Suppress
Rcvd: Total 11
2 Resolution Request 2 Resolution Reply 0 Registration Request
5 Registration Reply 0 Purge Request 1 Purge Reply
0 Error Indication 1 Traffic Indication 0 Redirect SuppressA spoke sends registrations and receives registration replies, never the reverse (only the NHS receives registrations). Purge messages are NHRP's cache invalidation, sent when a binding a router previously answered for changes or disappears.
Flow 3: Redirects, the Phase 3 Trigger
Resolution needs a trigger. In Phase 2 designs the trigger was the routing table itself: spokes saw each other's tunnel IPs as next hops (which is why Phase 2 forbids summarization; see the phase comparison). Phase 3 moves the trigger into NHRP. The hub, configured with ip nhrp redirect, watches for packets that enter and leave the same tunnel interface. That hairpin is the signal: two spokes are talking through it. The hub forwards the packet normally but also fires an NHRP Traffic Indication (the redirect) back at the source, which says, in effect, "there is a better way to reach this destination; go resolve it."
You can see the receipt in the traffic counters above: Rcvd: 1 Traffic Indication. A spoke configured with ip nhrp shortcut responds by sending the resolution request from Flow 2 and installing the answer as a shortcut. The redirect is rate-limited and purely advisory: a spoke without shortcut ignores it and keeps using the hub, which is why forgetting the command produces a working network that just never optimizes.
How a Shortcut Rewrites Forwarding Without Touching the RIB
The subtle brilliance of Phase 3 is where the shortcut lands. The EIGRP route still points at the hub; NHRP installs a next-hop override beside it, flagged with % and [NHO]:
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, Tunnel0The H route is an NHRP host route to the other spoke's tunnel address; the NHO entry overrides the EIGRP next hop for actual forwarding. When the cache entry expires, both vanish and forwarding falls back to the hub path with zero routing protocol churn. Control plane stability, data plane optimization: that separation is the whole Phase 3 design and the reason hubs can advertise a single summary (or default) route to hundreds of spokes. The complete build is in DMVPN Phase 3 configuration.
Reading show dmvpn Like a Native
The show dmvpn attribute column is a compressed summary of the NHRP cache, and it repays close reading. S is a static entry from an ip nhrp map; D is dynamically learned, which on a hub means a registration and on a spoke means a resolution. The Phase 3 shortcut states come as a pair: DT1 is a shortcut installed as a route (route installed), DT2 is a shortcut installed as a next-hop override on an existing route, and a single resolved peer often shows both, as in this lab capture taken seconds after a shortcut formed:
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 DT2The other attributes worth recognizing on sight: N flags a NATed peer (the hub saw a different source address than the spoke claimed), I is incomplete (resolution in flight or failed), X means no crypto socket in an IPsec design, and I2 marks a temporary entry created to carry a resolution conversation. The State column is coarser but faster: UP is healthy, NHRP means the control plane is actively failing, and IKE-related states point one layer down at IPsec.
NHRP Behind NAT
NAT bends NHRP in a specific, well-handled way. A spoke behind a NAT gateway believes its NBMA address is its private interface address, but its registration arrives at the hub from the NAT's public address. Modern NHRP carries NAT extensions precisely for this: the hub records the claimed address, notices the observed source differs, stores both, and flags the peer N in show dmvpn. Hub-to-spoke traffic then targets the observed (post-NAT) address, and the periodic re-registrations double as NAT keepalives holding the translation open, which is one reason short registration timers matter for spokes behind aggressive home routers.
Spoke-to-spoke shortcuts are where NAT gets philosophical. Two spokes behind separate NATs may simply be unable to reach each other's observed addresses (hairpin and symmetric NAT problems), in which case resolution succeeds, the shortcut attempt fails, and traffic quietly stays on the hub path. That is a feature, not a bug: Phase 3 degrades to hub-and-spoke rather than blackholing. In encrypted designs, IKEv2's NAT traversal moves ESP into UDP 4500 and the whole stack keeps working. The practical rule: spokes behind NAT are fine, expect N flags and occasional hub-path fallbacks; hubs belong on real public addresses.
The Fine Print: Auth, Network-ID, and Holdtime
Three NHRP knobs generate a disproportionate share of tickets. ip nhrp authentication is a cleartext string (8 characters max) checked on every received NHRP packet; a mismatch makes the hub log %DMVPN-3-DMVPN_NHRP_ERROR ... authentication failure and ignore the spoke. It is not security (it is cleartext in the packet), but it is a useful fence against joining the wrong cloud. ip nhrp network-id is locally significant and does not need to match across routers, despite a decade of forum posts claiming otherwise; it exists to bind NHRP processing to a tunnel interface on that box. And ip nhrp holdtime (default 600 seconds) controls how long your bindings live in other routers' caches, which sets both how fast stale entries disappear and how often registration refreshes happen. GRE-layer settings like the tunnel key live one layer down; the GRE guide covers them.
Key Takeaways
NHRP is the resolution layer that makes mGRE usable: it maps overlay addresses to underlay addresses and carries no routes. Registration flows spoke-to-hub and builds the NHS cache automatically; resolution flows on demand and builds spoke-to-spoke entries; redirects are the Phase 3 trigger that tells a spoke a shortcut exists. Read the cache flags (registered, nhop, rib, nho) and the show ip nhrp nhs detail counters before reaching for any debug, and remember that authentication must match while network-id does not. Watching these flows misbehave is the fastest way to learn them, which is exactly what troubleshooting DMVPN does on purpose. For the full architecture picture, return to the DMVPN complete guide.