How to Configure SLAAC and DHCPv6 on Cisco IOS
An IPv6 host gets its address in one of three ways, and the router chooses which by the flags it puts in its Router Advertisements. Pure SLAAC: the host builds its own address from the advertised /64. Stateless DHCPv6: SLAAC still builds the address, and a DHCPv6 pool supplies DNS and the domain name. Stateful DHCPv6: a server hands out the address and records the binding. This guide configures all three on Cisco IOS, adds a relay for a server on another segment, and is exact about which flag does what — A, O and M are the whole story, and confusing them is why a LAN half-works. If the addressing itself is not in place yet, start with configuring IPv6 addressing on Cisco.
Practice on hands-on CCNA & CCNP labs.
The three flags that decide everything
Every IPv6 host on a LAN starts the same way. It sends a Router Solicitation to FF02::2, the router answers with a Router Advertisement, and everything after that follows from three bits in the answer. Get them right and there is almost nothing else to configure. Get them wrong and hosts end up with two addresses, or an address and no DNS, or an address and no way off the subnet.
Two of those bits, M and O, sit in the RA header and describe the whole link. The third, A, sits inside each Prefix Information Option and describes that one prefix. That split is the source of most confusion, because M and A are independent: telling hosts to use DHCPv6 does not stop them building a SLAAC address as well. RFC 4861 defines the header flags and RFC 4862 defines the autoconfiguration they drive.
- SLAAC only: A set, M and O clear. The host builds an address; nothing supplies DNS.
- Stateless DHCPv6: A and O set, M clear. SLAAC builds the address, DHCPv6 supplies the options.
- Stateful DHCPv6: M set, and A cleared if you want the server to be the only source of addresses.
| Flag | What it tells the host | IOS command and default |
|---|---|---|
| A — Autonomous | Build your own address from this prefix. Per-prefix, carried in the Prefix Information Option, not in the RA header. | Set by default for a prefix configured on the interface. Clear it with ipv6 nd prefix 2001:db8:acad:10::/64 2592000 604800 no-autoconfig |
| O — Other Configuration | Ask DHCPv6 for everything except the address: DNS servers, domain name. | Off by default. ipv6 nd other-config-flag on the interface |
| M — Managed Address Configuration | Ask DHCPv6 for the address itself. | Off by default. ipv6 nd managed-config-flag on the interface |
| L — On-Link | Other hosts in this prefix are reachable directly, without sending through the router. | Set by default alongside A, on the same ipv6 nd prefix line |
| Router lifetime | Not a flag, but the only place a host learns its default gateway. DHCPv6 never carries one. | Nonzero as soon as ipv6 unicast-routing is on; ipv6 nd ra lifetime 0 advertises prefixes while refusing to be a gateway |
Mode 1 — Pure SLAAC
SLAAC needs two commands and no pool. ipv6 unicast-routing in global configuration turns the box from an IPv6 host into an IPv6 router: it forwards unicast traffic, and it starts sending Router Advertisements. Then put a /64 on the LAN interface. IOS advertises that prefix on its own, with A and L set, periodically and immediately in answer to any Router Solicitation.
The host does the rest. It takes the advertised /64, appends an interface ID of its own — EUI-64 derived from its MAC, or a stable randomized value on most current stacks — runs Duplicate Address Detection on the result, and installs a default route toward the RA's source address. That source is the router's link-local address, never its global one, which is why a host's IPv6 default gateway is always an FE80:: address.
The prefix has to be a /64. The interface ID that SLAAC builds is 64 bits wide, so on a /112 or a /126 hosts ignore the prefix for autoconfiguration and build no global address — they still take a default route from the RA, and stateful DHCPv6 still works, but SLAAC is dead. The same rule is why the graded SLAAC lab makes the /64 an explicit objective.
R1(config)# ipv6 unicast-routing
R1(config)# interface GigabitEthernet0/0
R1(config-if)# ipv6 address 2001:db8:acad:10::1/64
R1(config-if)# no shutdownPure SLAAC. The RA carrying this /64 is automatic once unicast routing is on.
Prove the router is advertising
Three checks, cheapest first. show ipv6 interface GigabitEthernet0/0 ends its neighbor discovery block with plain-English lines about what hosts are expected to do for addresses and for other configuration — those lines are your flags, rendered for humans, so reread them after every flag change.
In the same output, look for FF02::2 in the joined group addresses. The interface joins the all-routers group only when ipv6 unicast-routing is enabled, so its absence tells you no RA will ever be sent. If you want to watch the advertisements themselves, debug ipv6 nd prints them as they go out.
Mode 2 — Stateless DHCPv6
SLAAC delivers an address and a default route and nothing else. No DNS server, no domain name. Stateless DHCPv6 fills that gap without taking addressing away from SLAAC: a pool that carries options only, bound to the LAN interface, plus the O flag so hosts know there is something to ask for.
The exchange is two messages. A host that sees O set sends an Information-Request to FF02::1:2, the All_DHCP_Relay_Agents_and_Servers group, on UDP 547, and the server replies with the options. No address is requested, so no binding is created — show ipv6 dhcp binding stays empty on a correctly built stateless LAN, which unsettles people who expect to see their clients listed there.
Two mistakes cause nearly every failure in this mode. Either the pool exists but no interface carries ipv6 dhcp server, so nothing answers; or the pool is bound but O was never set, so nothing ever asks. Both look identical from the host: IPv6 works, pings by address succeed, and names do not resolve.
- The pool has no
address prefixline. That absence is the entire difference between this mode and stateful. ipv6 dhcp server <pool>goes on the interface the clients are on, and binds one pool to it.ipv6 nd other-config-flaggoes on that same interface. Setting it on the wrong interface is silent.- Addressing does not change: hosts still need the interface to hold a /64 with A set.
R1(config)# ipv6 dhcp pool LAN10-OPTS
R1(config-dhcpv6)# dns-server 2001:db8:acad:99::53
R1(config-dhcpv6)# domain-name lab.example
R1(config-dhcpv6)# exit
R1(config)# interface GigabitEthernet0/0
R1(config-if)# ipv6 dhcp server LAN10-OPTS
R1(config-if)# ipv6 nd other-config-flagStateless DHCPv6: options only, and the O flag that makes hosts ask for them.
Mode 3 — Stateful DHCPv6
Stateful DHCPv6 is the IPv4-shaped model: the server owns the addresses and records who holds which. The pool gains an address prefix line, and the interface gets M instead of O.
The client exchange is four messages — Solicit, Advertise, Request, Reply — with clients on UDP 546 and servers on UDP 547. It leaves a row in show ipv6 dhcp binding, keyed on the client's DUID rather than its MAC address, which is why the binding table looks nothing like an IPv4 DHCP lease list. Since a client asking for an address collects options in the same exchange, M makes O redundant; set one or the other, not both.
R1(config)# ipv6 dhcp pool LAN10-STATEFUL
R1(config-dhcpv6)# address prefix 2001:db8:acad:10::/64
R1(config-dhcpv6)# dns-server 2001:db8:acad:99::53
R1(config-dhcpv6)# domain-name lab.example
R1(config-dhcpv6)# exit
R1(config)# interface GigabitEthernet0/0
R1(config-if)# ipv6 dhcp server LAN10-STATEFUL
R1(config-if)# ipv6 nd managed-config-flagStateful DHCPv6: the pool owns a prefix, and M tells hosts to ask for an address.
M does not switch SLAAC off
This is the trap, and it is worth being precise about. ipv6 nd managed-config-flag sets one bit in the RA header. It does nothing to the Prefix Information Option, which still goes out with A set because the interface has a /64 configured on it. Hosts obey both instructions independently: they build a SLAAC address and they request a DHCPv6 address, and they keep both, so an interface ends up with two global addresses and picks between them by source-address selection rules you did not intend to involve.
If the point is that the server controls addressing, clear A on the prefix as well. The keyword sits after the prefix's two lifetimes, so restate IOS's own defaults — valid 2592000, preferred 604800 — and nothing but the A bit changes. The prefix stays on-link, hosts keep using it to reach each other directly, and the only source of addresses is the pool.
R1(config)# interface GigabitEthernet0/0
R1(config-if)# ipv6 nd managed-config-flag
R1(config-if)# ipv6 nd prefix 2001:db8:acad:10::/64 2592000 604800 no-autoconfigM on, A off: the DHCPv6 pool becomes the only source of addresses on this LAN.
The default route still comes from the RA
DHCPv6 has no default-gateway option, in any mode. Hosts learn their router from the RA's router lifetime and from nowhere else. That makes suppressing RAs on a stateful segment worse than it looks: the RA is also what told hosts to use DHCPv6, so most never start the exchange at all, and any that do end up with a valid address, correct DNS, and no route off the subnet.
Leave RAs running. If you do need to stop them on some other interface, the command is ipv6 nd ra suppress on current images and ipv6 nd suppress-ra on older ones, so check which your image takes. Either way, plain suppression stops only the periodic RAs — the router still answers a Router Solicitation unless the image supports ipv6 nd ra suppress all.
Relay: when the server is on another segment
Clients multicast to FF02::1:2, and FF02:: is link-scoped — a router does not forward it. So a DHCPv6 server that lives somewhere else is unreachable until the client-facing interface becomes a relay.
ipv6 dhcp relay destination <server-address> on that interface is the whole command. The relay wraps the client's message in a RELAY-FORW, unicasts it to the server, and unwraps the RELAY-REPL that comes back. It is the IPv6 counterpart of ip helper-address, and the placement rule is the same one that catches people in IPv4 DHCP relay: it goes on the interface facing the clients, not the interface facing the server.
Three things sit beyond that one command. IOS sources the RELAY-FORW from the interface facing the server, not from the client LAN; the client-LAN address travels separately, in the message's link-address field. So the server needs a route back to the relay's server-facing address — a relay that appears to be ignored is often a routing problem in the return direction — and the pool must be bound with ipv6 dhcp server on the interface the relayed traffic arrives on. An interface is in server mode or in relay mode, never both, and show ipv6 dhcp interface will tell you which. And the flags are still local: RAs do not cross the router either, so the branch router must set O (or M) itself, no matter where the pool lives.
! Branch router, on the client LAN
R1(config)# interface GigabitEthernet0/0
R1(config-if)# ipv6 dhcp relay destination 2001:db8:acad:99::2
R1(config-if)# ipv6 nd other-config-flag
!
! Server router, on the far segment
R2(config)# ipv6 dhcp pool REMOTE-OPTS
R2(config-dhcpv6)# dns-server 2001:db8:acad:99::53
R2(config-dhcpv6)# domain-name lab.example
R2(config-dhcpv6)# exit
R2(config)# interface GigabitEthernet0/1
R2(config-if)# ipv6 dhcp server REMOTE-OPTSThe relay on the client LAN, the pool on the remote router. Both halves are required.
Which mode did the host actually use?
You can answer this from the router without touching a host. Read three things, in this order.
show ipv6 interface GigabitEthernet0/0. The neighbor discovery block states in words what hosts are expected to do: stateless autoconfiguration for addresses, DHCP for other configuration, DHCP for routable addresses, or a combination of those. This is what you are advertising — the first thing worth confirming and the last thing most people check.show ipv6 dhcp interface. Server mode or relay mode, plus the pool name or the relay destination. An interface that does not appear here is doing neither, whatever the pool section of the config says.show ipv6 dhcp binding. One entry per stateful client, keyed on DUID. Empty here while hosts hold working global addresses means SLAAC built them, regardless of what you intended.show ipv6 dhcp poolshows the options a pool carries and how many clients it counts.
R1# show ipv6 interface GigabitEthernet0/0
<output omitted>
ND router advertisements are sent every 200 seconds
ND router advertisements live for 1800 seconds
Hosts use stateless autoconfig for addresses.
Hosts use DHCP to obtain other configuration.
R1# show ipv6 dhcp interface
GigabitEthernet0/0 is in server mode
Using pool: LAN10-OPTS
Preference value: 0
Rapid-Commit is disabledIllustrative, not a capture: the ND lines that name the mode, and the interface confirming which pool it serves.
Reading it from the host
The address itself is a weak clue. A SLAAC address sits inside the advertised /64 with an interface ID the host chose: either EUI-64, where the FF:FE wedged into the middle is unmistakable, or a long random-looking value, and most stacks hold a second temporary privacy address beside it. A stateful DHCPv6 address also comes from the pool's prefix, but IOS picks its interface ID for the client rather than handing out tidy low values, so it can look just as random — the deciding test is whether the router can show you a binding for it.
Either way the default route points at the router's link-local address. If a host has a global address but no FE80:: default route, the RA is the problem, not the pool.
When no host gets anything
One cause dominates: ipv6 unicast-routing is missing from the global configuration. Without it the router accepts IPv6 addresses on interfaces but never sends a Router Advertisement, so hosts hold a link-local address, learn no prefix, install no default route, and are never told to contact DHCPv6 either. A stateful LAN fails exactly as completely as a SLAAC one, because the M flag only exists inside an RA that is not being sent. Check this first, every time.
- The LAN prefix is not a /64. SLAAC cannot build an address on it; only stateful DHCPv6 still works.
- The interface is down, or has no IPv6 address, so there is no prefix to advertise.
- A pool exists but no interface carries
ipv6 dhcp server <pool>, so nothing answers a Solicit or an Information-Request. - O or M is set with no pool and no relay on that interface: hosts ask and meet silence, which reads like a host fault and is not one.
- RAs are suppressed on the interface. With no RA there is no M or O flag to see, so most hosts never contact DHCPv6 at all — and any that do still have no default route.
- An IPv6 ACL on the LAN. Every IPv6 ACL ends with implicit permits for neighbor discovery, but your own
deny ipv6 any anyoverrides them, and DHCPv6 needs UDP 546 and 547 through as well. - Two routers advertising different prefixes on one segment. Hosts autoconfigure from both and source traffic from an address you did not plan for; the fix is RA Guard on the switch, not a host setting.
Change one thing at a time
Flags are rarely the fault when nothing at all is happening — they choose between three working outcomes, not between working and broken. Work down the list above first, get a SLAAC address onto a host, and only then add O or M. That order also matches how the graded labs below are built: SLAAC alone, then options, then the same options served from another segment through a relay.
Frequently asked questions
Do I still need DHCPv6 if SLAAC already gives hosts an address?
SLAAC delivers an address and a default route and nothing else. It carries no DNS server and no domain name, so a SLAAC-only LAN leaves hosts able to ping by address and unable to resolve a name. Stateless DHCPv6 fills that gap while SLAAC keeps doing the addressing. Some newer stacks can learn DNS servers from the Router Advertisement itself, but support varies by IOS release and by host operating system, so the dependable answer on Cisco IOS is a DHCPv6 pool.
Which flag do I set for stateless DHCPv6, and which for stateful?
Stateless uses the Other Configuration flag, set with the interface command ipv6 nd other-config-flag: hosts keep building their own address with SLAAC and ask DHCPv6 only for options. Stateful uses the Managed Address Configuration flag, set with ipv6 nd managed-config-flag: hosts ask DHCPv6 for the address too. Setting the managed flag makes the other flag redundant, because a client requesting an address collects the options in the same exchange, so set one or the other and not both.
Why does my host have two global IPv6 addresses after I enabled stateful DHCPv6?
Because the managed flag and the autonomous flag are independent. The managed-config-flag command sets a bit in the Router Advertisement header, while the prefix configured on the interface is still advertised with the autonomous flag set, so the host builds a SLAAC address, requests a DHCPv6 address, and keeps both. Clear the autonomous flag with the no-autoconfig keyword on the ipv6 nd prefix line when the server is meant to be the only source of addresses. The keyword sits after the prefix's valid and preferred lifetimes, so restate them to leave everything else as it was.
Does DHCPv6 hand out a default gateway the way IPv4 DHCP does?
No. There is no default-gateway option in DHCPv6 in any mode. Hosts learn their router only from the Router Advertisement, and the next hop they install is the router's link-local address, which is why an IPv6 default route points at an FE80 address. Suppressing Router Advertisements on a stateful DHCPv6 segment breaks it twice over: with no advertisement there is no managed flag to see, so most hosts never start DHCPv6 at all, and any that do have no route off the subnet.
Why does no host get an IPv6 address at all?
Almost always because ipv6 unicast-routing is missing from the global configuration. Without it the router never sends a Router Advertisement, so hosts hold only a link-local address and are never told to contact DHCPv6 either. The quick check is whether the LAN interface has joined the all-routers multicast group FF02::2, which happens only once unicast routing is enabled. The next most common cause is a LAN prefix that is not a /64, which stops SLAAC dead.
Configure each mode on a graded lab
Build SLAAC, then stateless DHCPv6, then a relay to an off-segment server on real Cisco IOS in CML, and upload each config for a grade.
Practice on real Cisco IOS
Build it on real Cisco IOS and get instant pass/fail grading on your own config.