IPv6 has been “the future” for two decades, but 2026 is the year it stops being optional. ISPs are dropping legacy IPv4 prefixes, enterprise customers are demanding dual-stack connectivity, and regulatory frameworks in several regions now mandate IPv6 readiness for new deployments. If you’re running Cisco IOS-XE and haven’t enabled IPv6 yet — or if you did it years ago and the config is a mess — this guide walks through everything: dual-stack setup, OSPFv3, DHCPv6, and the security controls that keep your IPv6 infrastructure tight.
This post assumes IOS-XE 16.x or later. Most commands apply to Catalyst 9000 series, ISR 4000 series, and ASR 1000 platforms. Some older IOS-XE releases have quirks — I’ll call them out where they matter. If you’re unsure which platform OS you’re on, check out the breakdown of Cisco IOS vs IOS-XE vs IOS-XR before diving in.
1. Enable IPv6 Routing
Global IPv6 routing is disabled by default on IOS-XE. The first thing you need — before configuring a single address — is to turn it on:
Router# configure terminal
Router(config)# ipv6 unicast-routing
Without this, IPv6 packets will not be forwarded between interfaces, even if addresses are configured. This is the most common “why isn’t my IPv6 working” mistake engineers run into.
Verify it’s enabled:
Router# show ipv6 cef
IPv6 CEF is enabled and running
CEF for IPv6 is enabled automatically when ipv6 unicast-routing is on. On older platforms that separated these, you’d also need ipv6 cef explicitly — but modern IOS-XE handles it automatically.
2. Interface Addressing: EUI-64 vs Static
You have two main options for assigning IPv6 addresses to interfaces: statically assigned addresses and EUI-64 addresses auto-derived from the interface MAC address.
Static address assignment:
Router(config)# interface GigabitEthernet0/0/1
Router(config-if)# ipv6 address 2001:db8:10:1::1/64
Router(config-if)# ipv6 address FE80::1 link-local
Router(config-if)# no shutdown
Always manually set the link-local address on router interfaces. The auto-generated EUI-64 link-local is long and makes troubleshooting a headache. Using FE80::1 on the core side and FE80::2 on the remote side gives you a clean, predictable addressing scheme.
EUI-64 address (auto-derived):
Router(config-if)# ipv6 address 2001:db8:10:1::/64 eui-64
This derives the host portion from the interface’s MAC address (with the 7th bit flipped). Useful for tracking which device owns an address, but creates management headaches when you swap interface cards. Stick to static for router and switch SVIs. EUI-64 is more appropriate for end-host SLAAC in enterprise LANs.
Verify interface addressing:
Router# show ipv6 interface GigabitEthernet0/0/1
GigabitEthernet0/0/1 is up, line protocol is up
IPv6 is enabled, link-local address is FE80::1
No Virtual link-local address(es):
Global unicast address(es):
2001:DB8:10:1::1, subnet is 2001:DB8:10:1::/64
Joined group address(es):
FF02::1
FF02::2
FF02::1:FF00:1
MTU is 1500 bytes
ICMP error messages limited to one every 100 milliseconds
ICMP redirects are enabled
ICMP unreachables are sent
ND DAD is enabled, number of DAD attempts: 1
ND reachable time is 30000 milliseconds (using 30000)
ND NS retransmit interval is 1000 milliseconds
Pay attention to the joined multicast groups. FF02::2 is the all-routers multicast group — this interface is participating as a router. FF02::1:FF00:1 is the solicited-node multicast for NDP (Neighbor Discovery Protocol), the IPv6 equivalent of ARP.
3. Dual-Stack Configuration
Dual-stack means the interface carries both IPv4 and IPv6 simultaneously. On IOS-XE, this just means configuring both ip address and ipv6 address on the same interface:
Router(config)# interface GigabitEthernet0/0/0
Router(config-if)# description WAN Link to Provider
Router(config-if)# ip address 203.0.113.1 255.255.255.252
Router(config-if)# ipv6 address 2001:db8:200:1::1/64
Router(config-if)# ipv6 address FE80::1 link-local
Router(config-if)# no shutdown
The two stacks are completely independent in terms of routing and forwarding. Your IPv4 OSPF/BGP neighbors and IPv6 OSPFv3/BGP neighbors are separate processes. This is both a strength (clean separation) and a management challenge (you’re running two routing domains in parallel).
Verify dual-stack forwarding:
Router# show ip interface brief | include Gig0/0/0
GigabitEthernet0/0/0 203.0.113.1 YES NVRAM up up
Router# show ipv6 interface brief | include Gig0/0/0
GigabitEthernet0/0/0 [up/up]
FE80::1
2001:DB8:200:1::1
4. OSPFv3 Configuration
OSPFv3 is the IPv6-capable version of OSPF. On modern IOS-XE with the address-family model, you can run OSPFv3 for both IPv4 and IPv6 from the same process — this is the recommended approach as it simplifies operations.
OSPFv3 with address-family model:
Router(config)# router ospfv3 1
Router(config-router)# router-id 1.1.1.1
Router(config-router)# address-family ipv6 unicast
Router(config-router-af)# redistribute connected
Router(config-router-af)# exit-address-family
Router(config)# interface GigabitEthernet0/0/1
Router(config-if)# ospfv3 1 ipv6 area 0
The router-id is still a 32-bit IPv4-formatted value, even in OSPFv3. If your router has no IPv4 addresses configured, you must set this manually — otherwise OSPFv3 won’t start. This catches engineers off guard on IPv6-only deployments.
Verify OSPFv3 neighbors:
Router# show ospfv3 neighbor
OSPFv3 1 address-family ipv6 (router-id 1.1.1.1)
Neighbor ID Pri State Dead Time Interface ID Interface
2.2.2.2 1 FULL/DR 00:00:33 4 GigabitEthernet0/0/1
Check OSPFv3 database:
Router# show ospfv3 database
OSPFv3 1 address-family ipv6 (router-id 1.1.1.1)
Router Link States (Area 0)
ADV Router Age Seq# Fragment ID Link count Bits
1.1.1.1 623 0x80000005 0 1 B
2.2.2.2 541 0x80000004 0 1 None
Link (Type-8) Link States (Area 0)
ADV Router Age Seq# Fragment ID Link ID Prefix
1.1.1.1 623 0x80000003 0 4
2.2.2.2 541 0x80000003 0 4
Prefix (Type-9) Link States (Area 0)
ADV Router Age Seq# Fragment ID
1.1.1.1 441 0x80000004 0
2.2.2.2 460 0x80000003 0
One thing engineers migrating from OSPFv2 frequently miss: OSPFv3 authentication uses IPsec, not the simple MD5/SHA key chains from OSPFv2. On IOS-XE 17.x:
Router(config-router-af)# area 0 authentication ipsec spi 256 sha1 0123456789012345678901234567890123456789
There’s no area authentication message-digest equivalent in OSPFv3 — it’s full IPsec. Plan for this when writing your migration runbook.
5. DHCPv6
IPv6 hosts can get addresses via three mechanisms: SLAAC (Stateless Address Autoconfiguration), DHCPv6 stateless (prefix + options from DHCP, address from SLAAC), or DHCPv6 stateful (full address assignment like traditional DHCP). On IOS-XE you can operate the router as a DHCPv6 server or relay.
DHCPv6 stateful server:
Router(config)# ipv6 dhcp pool CORP-LAN-V6
Router(config-dhcpv6)# address prefix 2001:db8:10:20::/64
Router(config-dhcpv6)# dns-server 2001:4860:4860::8888
Router(config-dhcpv6)# dns-server 2001:4860:4860::8844
Router(config-dhcpv6)# domain-name corp.example.com
Router(config-dhcpv6)# exit
Router(config)# interface GigabitEthernet0/0/2
Router(config-if)# ipv6 dhcp server CORP-LAN-V6
Router(config-if)# ipv6 nd managed-config-flag
Router(config-if)# ipv6 nd other-config-flag
The RA (Router Advertisement) flags are critical here:
- M flag (
managed-config-flag): tells hosts to use DHCPv6 for address assignment - O flag (
other-config-flag): tells hosts to use DHCPv6 for other config (DNS, domain) but use SLAAC for addressing
Pure SLAAC: set neither flag. DHCPv6 stateless (SLAAC addresses + DHCPv6 for DNS): set only O flag. Full DHCPv6 stateful: set both flags.
DHCPv6 relay:
Router(config)# interface GigabitEthernet0/0/2
Router(config-if)# ipv6 dhcp relay destination 2001:db8:10:1::10
Verify DHCPv6 bindings:
Router# show ipv6 dhcp binding
Client: FE80::1A2B:3C4D:5E6F:7A8B
DUID: 0001000124F3A1B203000C29EF1234
Username : unassigned
VRF : default
Interface : GigabitEthernet0/0/2
IA NA: IA ID 0x00030001, T1 43200, T2 69120
Address: 2001:DB8:10:20::A
preferred lifetime 86400, valid lifetime 172800
expires at Aug 25 2026 10:34:17 (86392 seconds)
6. Security Hardening for IPv6
IPv6 introduces attack surfaces that don’t exist in IPv4 — NDP spoofing, rogue RAs, and ICMPv6 flooding. IOS-XE has solid tools to address all of these, and deploying them is not optional on any network carrying production traffic. For broader network security context, our network security guide covers the foundational framework.
RA Guard (blocks rogue Router Advertisements):
Rogue RA attacks are the IPv6 equivalent of a rogue DHCP server. An attacker sends a Router Advertisement claiming to be the default gateway and redirects all IPv6 traffic. RA Guard blocks this at the switch level:
Switch(config)# ipv6 nd raguard policy HOST-POLICY
Switch(config-nd-raguard)# device-role host
Switch(config-nd-raguard)# exit
Switch(config)# interface GigabitEthernet1/0/1
Switch(config-if)# ipv6 nd raguard attach-policy HOST-POLICY
Apply HOST-POLICY to all access ports. Only uplink/trunk ports should be allowed to receive RAs.
IPv6 DHCP Guard:
Switch(config)# ipv6 dhcp guard policy DHCP-SERVER-POLICY
Switch(config-dhcp-guard)# device-role server
Switch(config-dhcp-guard)# exit
Switch(config)# interface GigabitEthernet1/0/1
Switch(config-if)# ipv6 dhcp guard attach-policy DHCP-SERVER-POLICY
IPv6 Snooping and Source Guard:
Switch(config)# ipv6 snooping policy SNOOP-POLICY
Switch(config-ipv6-snooping)# security-level guard
Switch(config-ipv6-snooping)# exit
Switch(config)# interface GigabitEthernet1/0/1
Switch(config-if)# ipv6 snooping attach-policy SNOOP-POLICY
IPv6 snooping builds a binding table of IP-to-MAC-to-port mappings, similar to DHCP snooping for IPv4. Source Guard uses this table to drop packets with spoofed source addresses. On Cat9K platforms, this is hardware-accelerated and doesn’t impact forwarding performance.
ICMPv6 rate limiting:
Router(config)# ipv6 icmp error-interval 50 10
This limits ICMPv6 error messages to a maximum of 10 per 50ms — protection against ICMPv6-based DoS attacks. The default (100ms/1 burst) is too permissive for public-facing interfaces.
ACL for IPv6 management plane:
Router(config)# ipv6 access-list MGMT-ACCESS-V6
Router(config-ipv6-acl)# permit ipv6 2001:db8:mgmt::/48 host 2001:db8:10:1::1
Router(config-ipv6-acl)# permit icmp any any echo
Router(config-ipv6-acl)# permit icmp any any echo-reply
Router(config-ipv6-acl)# permit icmp any any unreachable
Router(config-ipv6-acl)# permit icmp any any time-exceeded
Router(config-ipv6-acl)# permit icmp any any packet-too-big
Router(config-ipv6-acl)# deny ipv6 any any log
Router(config-ipv6-acl)# exit
Router(config)# line vty 0 4
Router(config-line)# ipv6 access-class MGMT-ACCESS-V6 in
Critical difference from IPv4 ACLs: you must explicitly permit the ICMPv6 types needed for path MTU discovery (unreachable, time-exceeded, packet-too-big). Blocking all ICMPv6 breaks IPv6 in subtle ways — TCP sessions will hang on large transfers if PMTUD is broken.
7. IPv6 over BGP
If you’re advertising IPv6 prefixes to a provider or between sites, you need BGP with IPv6 address-family enabled. IPv6 BGP can run over IPv4 TCP sessions (MP-BGP) or native IPv6 sessions. Native IPv6 sessions are simpler operationally.
Router(config)# router bgp 65001
Router(config-router)# bgp router-id 1.1.1.1
Router(config-router)# no bgp default ipv4-unicast
Router(config-router)# neighbor 2001:db8:200:1::2 remote-as 65002
Router(config-router)# address-family ipv6 unicast
Router(config-router-af)# neighbor 2001:db8:200:1::2 activate
Router(config-router-af)# network 2001:db8:10::/48
Router(config-router-af)# exit-address-family
no bgp default ipv4-unicast is best practice — it prevents accidentally activating a new neighbor in the IPv4 address-family when you intend to use IPv6 only. For BGP internals and path selection, we covered how BGP works in an earlier post.
Verify BGP IPv6 neighbors:
Router# show bgp ipv6 unicast summary
BGP router identifier 1.1.1.1, local AS number 65001
BGP table version is 8, main routing table version 8
2 network entries using 544 bytes of memory
2 path entries using 416 bytes of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
2001:DB8:200:1::2
4 65002 87 85 8 0 0 01:12:48 1
8. Troubleshooting IPv6 Issues
A few show commands that save time when IPv6 isn’t behaving:
# Check NDP neighbor table (IPv6 ARP equivalent)
Router# show ipv6 neighbors
IPv6 Address Age Link-layer Addr State Interface
FE80::2 0 0050.5600.0001 REACH Gi0/0/1
2001:DB8:10:1::2 0 0050.5600.0001 REACH Gi0/0/1
# Check IPv6 routing table
Router# show ipv6 route
IPv6 Routing Table - default - 8 entries
Codes: C - Connected, L - Local, S - Static, U - Per-user Static route
B - BGP, R - RIP, H - NHRP, I1 - ISIS L1, I2 - ISIS L2
IA - ISIS interarea, IS - ISIS summary, D - EIGRP, EX - EIGRP external
O - OSPF Intra, OI - OSPF Inter, OE1 - OSPF ext 1, OE2 - OSPF ext 2
C 2001:DB8:10:1::/64 [0/0]
via GigabitEthernet0/0/1, directly connected
L 2001:DB8:10:1::1/128 [0/0]
via GigabitEthernet0/0/1, receive
B 2001:DB8:20::/48 [20/0]
via 2001:DB8:200:1::2
LC ::1/128 [0/0]
via Loopback0, receive
# Ping with source interface specified
Router# ping ipv6 2001:db8:10:1::2 source GigabitEthernet0/0/1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 2001:DB8:10:1::2, timeout is 2 seconds:
Packet sent with a source address of 2001:DB8:10:1::1
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/2 ms
Common IPv6 gotchas to watch for:
- NDP incomplete: Check that the remote host is in REACH or STALE state, not INCOMPLETE. INCOMPLETE means NDP solicitations are going unanswered — check for ACLs blocking ICMPv6 neighbor solicitation/advertisement (types 135/136).
- OSPFv3 adjacency stuck in INIT: Usually a multicast issue. Verify
FF02::5andFF02::6are reachable between routers. Check for interface-level ACLs blocking these multicast groups. - Ping works, TCP fails: Classic PMTUD breakage. Check for ACLs blocking ICMPv6 Packet Too Big (type 2). Add
permit icmp any any packet-too-bigto your ACL. - SLAAC addresses appear but hosts can’t reach the internet: Run
debug ipv6 ndbriefly on the router to verify RAs are being sent with the correct prefix and default router information.
Putting It All Together
A solid IOS-XE IPv6 deployment has a clear stack: ipv6 unicast-routing enabled globally, interfaces with static addresses and clean link-locals, OSPFv3 with the address-family model handling intra-domain routing, DHCPv6 providing addresses and options to end hosts with proper M/O flag configuration, RA Guard and DHCP Guard locked down on all access ports, and BGP advertising your IPv6 prefix to the outside world.
The operational model differs from IPv4 mostly at layer 2 — NDP replaces ARP, and the security controls (RA Guard, Snooping, Source Guard) are the IPv6 analogs of Dynamic ARP Inspection and DHCP Snooping. If you’ve already built those IPv4 protections into your access layer, the IPv6 equivalents follow the same logic and the Cat9K enforces them in hardware.
One last recommendation: enable IPv6 on loopbacks and use those for OSPFv3/BGP peering and management access. Loopback addresses survive interface failures and make routing stable. Set your management ACL to permit your NOC’s IPv6 block to the loopback and you’ll have clean, auditable remote access on both stacks.
IPv6 is no longer a future project — it’s infrastructure debt that compounds every quarter you delay. Get the foundation right now, while your network is stable, rather than scrambling when a provider or customer forces the issue.