EIGRP

EIGRP over DMVPN: Multi-Hub Design and the Split-Horizon Problem

EIGRP over DMVPN - show dmvpn with three NHRP peers up on a dual-hub single-cloud design
In: EIGRP, Labs, CCIE, DMVPN

EIGRP over DMVPN works beautifully, right up until the moment you realise none of your spokes can reach any of your other spokes. The tunnels are up. NHRP is registered. The neighbours are all in the table. And the routes are simply not there.

The cause is split horizon, doing exactly what it was designed to do in 1988 on a protocol running over a physical, point-to-point serial link - and doing precisely the wrong thing on a multipoint GRE cloud. This article covers split horizon and next-hop-self on mGRE, dual-hub design, and the loop that a dual-homed site creates - all with real output from a CML lab. For the fundamentals, see the EIGRP guide and the DMVPN pillar.

Why split horizon breaks mGRE

Split horizon is a loop-prevention rule from the distance-vector era: do not advertise a route back out of the interface you learned it on. On a point-to-point link that is unarguably correct. The only router out there is the one who told you about it.

An mGRE tunnel is not a point-to-point link. It is one logical interface with many neighbours behind it. Every spoke reaches the hub through Tunnel0, and so does every other spoke. When the hub learns SPOKE1's LAN on Tunnel0 and split horizon stops it re-advertising out Tunnel0, it is not preventing a loop - it is preventing SPOKE2 from ever hearing about SPOKE1.

The fix is one command. It has to be on the hub, and it has to be on the tunnel:

router eigrp DMVPN
 address-family ipv4 unicast autonomous-system 100
  af-interface Tunnel0
   no split-horizon

Spokes do not need it. A spoke has exactly one neighbour of interest per hub, and it should not be re-advertising other spokes' routes anyway.

next-hop-self: the second command nobody tells you about

Turning off split horizon gets the routes to the spokes. It does not get the traffic there directly.

By default, EIGRP sets itself as the next hop on routes it advertises. So when the hub re-advertises SPOKE1's LAN to SPOKE2, it says "reachable via me". SPOKE2 sends the traffic to the hub, and the hub forwards it to SPOKE1. Every spoke-to-spoke packet crosses the WAN twice and traverses the hub's CPU. Your DMVPN is a hub-and-spoke network wearing a dynamic-mesh costume.

The second command tells the hub to preserve the originating spoke as the next hop:

  af-interface Tunnel0
   no split-horizon
   no next-hop-self

Now SPOKE2 learns SPOKE1's LAN with SPOKE1's tunnel address as the next hop. NHRP resolves that to SPOKE1's real NBMA address, a direct spoke-to-spoke tunnel forms, and traffic goes straight across.

Both, visible in one output

From the lab. SPOKE1 looking at SPOKE2's loopback, with both commands in place on both hubs:

SPOKE1#show ip eigrp topology 12.12.12.12/32
  Descriptor Blocks:
  10.1.1.12 (Ethernet0/1), from 10.1.1.12, Send flag is 0x0
      Composite metric is (131153920/163840), route is Internal
        Hop count is 1
        Originating router is 12.12.12.12

  10.0.0.12 (Tunnel0), from 10.0.0.2, Send flag is 0x0
      Composite metric is (13107281920/9830481920), route is Internal
        Hop count is 2
        Originating router is 12.12.12.12

  10.0.0.12 (Tunnel0), from 10.0.0.1, Send flag is 0x0
      Composite metric is (13107281920/9830481920), route is Internal
        Hop count is 2
        Originating router is 12.12.12.12

Read those last two blocks carefully, because both commands are visible in them:

  • from 10.0.0.2 and from 10.0.0.1 - the hubs re-advertised a route they learned on Tunnel0 back out of Tunnel0. That is no split-horizon working.
  • 10.0.0.12 (Tunnel0) - the next hop is 10.0.0.12, which is SPOKE2 itself, not either hub. That is no next-hop-self working.

Break split horizon, and the paths vanish

Turn split-horizon back on at both hubs:

SPOKE1#show ip eigrp topology 12.12.12.12/32
  Descriptor Blocks:
  10.1.1.12 (Ethernet0/1), from 10.1.1.12, Send flag is 0x0
      Composite metric is (131153920/163840), route is Internal

Both tunnel paths are gone. In our lab the spokes happen to share a site LAN, so one path survives. In a real DMVPN, where spokes are in different cities, there would be nothing left at all. Spoke-to-spoke reachability would simply not exist.

Break next-hop-self, and the traffic hairpins

Turn next-hop-self back on (the default):

SPOKE1#show ip eigrp topology 12.12.12.12/32 | include Descriptor|Tunnel0|Ethernet
  Descriptor Blocks:
  10.1.1.12 (Ethernet0/1), from 10.1.1.12, Send flag is 0x0
  10.0.0.2 (Tunnel0), from 10.0.0.2, Send flag is 0x0        <-- next hop is HUB2
  10.0.0.1 (Tunnel0), from 10.0.0.1, Send flag is 0x0        <-- next hop is HUB1

The routes are still there. But the next hop is now the hub. Every packet from SPOKE1 to SPOKE2 goes to a hub first. The tunnels can still form dynamically via NHRP shortcut in Phase 3, but the routing table is no longer pointing at the spoke, and you have made the hub a bottleneck for traffic that never needed to touch it.

Dual-hub: single cloud vs dual cloud

Single cloud (dual hub)
One tunnel interface per spoke, one tunnel subnet, both hubs are NHS on the same cloud. Simpler config, fewer interfaces, and spokes are adjacent to both hubs on one mGRE. What our lab uses.
Dual cloud
Two tunnel interfaces per spoke, two tunnel subnets, one per hub. More config, but full transport separation - useful when each hub sits on a genuinely different WAN (MPLS + internet).

Single cloud is simpler and is the right default when both hubs sit on the same transport. Dual cloud is what you want when the two paths are genuinely different networks and you need to reason about them, police them, or apply per-transport policy independently.

In our single-cloud lab, the DMVPN comes up with both hubs and both spokes on one mGRE:

HUB1#show dmvpn
Interface: Tunnel0, IPv4 NHRP Details
Type:Hub, NHRP Peers:3,

 # Ent  Peer NBMA Addr Peer Tunnel Add State  UpDn Tm Attrb
     1 100.64.2.1             10.0.0.2    UP 00:00:28     D
     1 100.64.11.1           10.0.0.11    UP 00:00:37     D
     1 100.64.12.1           10.0.0.12    UP 00:00:32     D

Making one hub primary

Two hubs advertising identical metrics means spokes load-share, which is usually not what you want. Express the preference once, on the backup hub, with an offset list:

HUB2(config)#access-list 50 permit any
HUB2(config-router-af-topology)#offset-list 50 out 100000000 Tunnel0

One command on one router. Every spoke, present and future, now prefers HUB1 and keeps HUB2 as a feasible successor - ready for instant failover, with no reconvergence.

The dual-homed site problem

Now the failure mode that a dual-hub design creates and that most DMVPN guides never mention.

Site A has two spokes on one LAN. Both advertise the site LAN into the WAN. Which means SPOKE2 learns its own LAN back from the WAN:

SPOKE2#show ip eigrp topology 10.1.1.0/24
  Descriptor Blocks:
  0.0.0.0 (Ethernet0/1), from Connected, Send flag is 0x0
        Originating router is 12.12.12.12          <-- its own LAN, connected

  10.0.0.11 (Tunnel0), from 10.0.0.2, Send flag is 0x0
        Hop count is 2
        Originating router is 11.11.11.11          <-- the SAME LAN, back from the WAN

  10.0.0.11 (Tunnel0), from 10.0.0.1, Send flag is 0x0
        Originating router is 11.11.11.11

The connected route wins today. But if SPOKE2's LAN interface flaps, it will install a WAN path to its own directly-attached network - and start sending local traffic across the internet and back. EIGRP has no AS-path, so nothing in the protocol stops this.

The fix is a route tag applied on every router at the site: stamp everything leaving, drop anything arriving with your own stamp.

route-map TAG-SITE-A permit 10
 set tag 1001
!
route-map BLOCK-SITE-A deny 10
 match tag 1001
route-map BLOCK-SITE-A permit 20
!
router eigrp DMVPN
 address-family ipv4 unicast autonomous-system 100
  topology base
   distribute-list route-map TAG-SITE-A out Tunnel0
   distribute-list route-map BLOCK-SITE-A in Tunnel0
SPOKE2#show ip eigrp topology 10.1.1.0/24
  Descriptor Blocks:
  0.0.0.0 (Ethernet0/1), from Connected, Send flag is 0x0     <-- only the connected path remains

Full treatment, including what happened when we tried Cisco's official SoO mechanism on this platform, in EIGRP Site of Origin.

The complete hub template

interface Tunnel0
 ip address 10.0.0.1 255.255.255.0
 no ip redirects
 ip mtu 1400
 ip nhrp authentication PINGLABZ
 ip nhrp map multicast dynamic
 ip nhrp network-id 100
 ip nhrp holdtime 300
 ip nhrp redirect
 ip tcp adjust-mss 1360
 tunnel source Ethernet0/1
 tunnel mode gre multipoint
 tunnel key 100
!
router eigrp DMVPN
 address-family ipv4 unicast autonomous-system 100
  af-interface default
   passive-interface
  exit-af-interface
  af-interface Tunnel0
   no passive-interface
   hello-interval 5
   hold-time 15
   no split-horizon
   no next-hop-self
  exit-af-interface
  network 10.0.0.0 0.0.0.255
  eigrp router-id 1.1.1.1

Three details in there that people skip:

  • ip mtu 1400 and ip tcp adjust-mss 1360. GRE plus IPsec eats header space. Without these, large packets fragment or get dropped, and you get the classic "ping works, applications hang" symptom that costs people days.
  • af-interface default / passive-interface. Make everything passive by default and explicitly un-passive the interfaces you want. It is the only way to run EIGRP safely, and named mode makes it a two-line pattern.
  • Tuned hellos (5/15). The default on a multipoint interface is 60/180, which means a dead hub is not noticed for three minutes. 5/15 is aggressive but appropriate for a WAN overlay. Better still, pair it with BFD.

Key takeaways

  • no split-horizon on the hub's tunnel is what lets spokes learn each other's routes. Without it, spoke-to-spoke reachability does not exist at all.
  • no next-hop-self on the hub's tunnel is what makes the traffic go directly. Without it the routes exist but every packet hairpins through the hub.
  • Both go on the hub, on the tunnel interface. Spokes need neither.
  • Single-cloud dual-hub is the simpler default. Dual-cloud is for genuinely separate transports.
  • Make one hub primary with an outbound offset list on the backup hub - one command, applies to every spoke, keeps the backup as a feasible successor.
  • A dual-homed site will learn its own LAN back from the WAN. Tag on the way out, deny on the way in, on every router at the site.
  • Set ip mtu 1400 and ip tcp adjust-mss 1360 or you will spend a week debugging a fragmentation problem.

Next: multi-protocol redistribution and the scenarios that break networks. The full cluster indexes live on the EIGRP pillar and the DMVPN pillar.

Written by
More from Ping Labz
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Ping Labz.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.