⚠️ Modernization Notice These notes were written in 2018–2019. IPv6 CPE and OS support, DHCPv6 implementations, and ISP best practices have evolved significantly since then. Treat this as a record of real testing and the architectural decisions behind it, and validate against current RFCs, CPE datasheets, and OS release notes before deploying in production.
Overview
This post brings together two pieces of work I did on IPv6 for PPP broadband. The first is a set of notes and lab tests on running a single dual-stack PPP session per subscriber and assigning IPv6 prefixes to the CPE from a Cisco IOS XE BNG. The second is a design sketch for assigning static IPv6 prefixes per customer from a RADIUS/AAA backend. They belong together: the lab work shows how Cisco ISG/IOS XE actually behaves when prefixes arrive over RADIUS, and the design sketch is the natural next step once you decide that static, per-customer prefixes are what you want.
The whole topic splits naturally into two halves: the ISP↔CPE link, and the CPE↔host LAN. How far you can push depends heavily on CPE capabilities and end-user operating systems. These notes focus mostly on the ISP↔CPE side, where IPv6 is enabled per customer. In our setup IPv6 options live under the virtual-template, and IPv6 is switched on per subscriber with a RADIUS Cisco AVpair:
| |
Worth reading first:
- RFC 7084 — Basic Requirements for IPv6 Customer Edge Routers
- RFC 6177 — IPv6 Address Assignment to End Sites (persistent vs. non-persistent, and what size to choose)
- Broadband Forum TR-187 — IPv6 for PPP Broadband Access
MTU Considerations
Some intermediate nodes on the Internet block ICMPv6, which breaks Path MTU Discovery. If you hit reachability problems, lower the MTU and adjust TCP MSS — this works for IPv6 just as it does for IPv4:
| |
ISP–CPE IPv6 PPP Model
Single PPP Dual-Stack Session
Using a single PPP session for both IPv4 and IPv6 is far more efficient than running separate sessions, and it is widely supported on both CPE and BNG. Separate sessions double the PPP session count on the BNG and complicate every subscriber resource that is keyed on the session (AAA, RADIUS, accounting). Most CPE today default to dual-stack on a single session — the main thing is to make sure IPv6 is actually enabled, because on many CPE it ships disabled.
Static /64 Prefixes vs. Dynamic Assignment
The Broadband Forum suggests a /60 per broadband customer, but a /64 is enough for typical consumers. Either way, plan your address blocks with plenty of headroom toward /60. I prefer static prefix assignment per customer because it removes most of the operational pain:
| Aspect | Static | Dynamic (non-persistent) |
|---|---|---|
| Auditing | Simple: prefix → customer mapping lives in your database | Harder: needs separate DHCPv6 logging, since the delegated prefix is not in session accounting |
| Prefix changes (CPE/DSLAM reboot) | None | CPE must tell LAN hosts to re-lease DHCPv6 prefixes — many CPE handle this badly |
| Accounting | Prefix is in the session records | DHCPv6 runs after session establishment, so accounting must be updated afterward |
| NAT | Not used and not needed | Not used and not needed |
| Security | CPE firewall / customer access device features | CPE firewall / customer access device features |
If you do go dynamic, remember that the Delegated-IPv6-Prefix is not included in the accounting records (it is meant for DHCPv6), so you have to enable DHCPv6 logging or periodic accounting updates to capture it:
| |
(Periodic updates may not be necessary in your environment.)
Static assignment sidesteps most of this. There is no NAT for IPv6 and none is needed — security is left to the CPE firewall and the customer’s own access devices. Assign the prefix when you provision the customer in your back office. Avoid mapping username or port directly to a prefix (that leaks information); use an offset or similar scheme instead, and remember to return unused prefixes to the pool.
SLAAC and Stateful DHCPv6
There are several ways to get a prefix from the ISP to the CPE:
- SLAAC relies on ND Router Advertisement (RA) messages. The CPE needs RA in any case to install its default route, and the RA carries the prefix used for the WAN link.
- DHCPv6 is generally how the CPE obtains the LAN prefix (prefix delegation). Some CPE can also derive a LAN prefix from the RA-received prefix instead.
- DNS can come from IPv4 in a dual-stack environment. RA can announce DNS (RFC 8106 / RFC 6106), but support is uneven across CPE; DHCPv6 is the more reliable channel.
You can use different prefixes for the WAN side and the LAN side of the CPE, and in a real deployment you usually should.
IPv6 Prefix Delegation for PPP Customers
RADIUS Attributes
| Attribute | Purpose |
|---|---|
Framed-IPv6-Prefix | Prefix advertised by SLAAC/ND on the WAN link |
Delegated-IPv6-Prefix | Prefix handed to the CPE LAN via DHCPv6-PD |
Framed-IPv6-Pool | Pool name for dynamic SLAAC prefix selection |
Delegated-IPv6-Prefix-Pool | Pool name for dynamic DHCPv6 delegation (RFC 6911) |
Framed-Interface-Id | Interface identifier the CPE may use as the lower 64 bits of its WAN address |
Delegated-IPv6-Prefix is not carried in accounting messages, because it is expected to be used with DHCPv6. If you rely on it, enable DHCPv6 accounting so the delegated prefix lands in the session’s accounting records.
Cisco ISG/IOS XE DHCPv6 Fallback Logic
Cisco ISG/IOS XE has a useful fallback when you point DHCPv6 at AAA for prefix delegation:
If you configure AAA for DHCPv6 and a
Delegated-IPv6-Prefixcomes back in the Access-Accept, that prefix is used as the DHCPv6 prefix.If AAA is configured for DHCPv6 but no prefix is returned, the BNG makes a second AAA request just to fetch the prefix.
You can avoid that second request by feeding the
Framed-IPv6-Prefixto the DHCPv6 server. To do that, stop ND from advertising it as an on-link prefix:1no ipv6 nd prefix framed-ipv6-prefixNow a single attribute can drive both the WAN (ND/SLAAC) and LAN (DHCPv6) prefix.
If both
Framed-IPv6-PrefixandDelegated-IPv6-Prefixare present, the delegated prefix wins for the DHCPv6 server.
You can also send a pool name instead of a fixed prefix via Framed-IPv6-Pool (SLAAC) or Delegated-IPv6-Prefix-Pool (DHCPv6, RFC 6911).
Framed-Interface-Id
From Broadband Forum TR-187:
In contrast with IPCP, which provides other configuration information, IPV6CP only negotiates an interface identifier. Other configuration information is provided via Neighbor Discovery and DHCPv6. The 64-bit interface identifier is used to derive the Link-local address on the WAN interface.
If Framed-Interface-Id is returned in the Access-Accept, the BNG offers it to the CPE during IPV6CP. A CPE that honors it will use that identifier as the lower 64 bits of its WAN IPv6 address — effectively a predefined /128. How you construct the interface-id is up to the ISP; a hash over customer information works, as long as you watch for collisions.
Configuration: Cisco IOS XE ASR1000
Our IPv4 model is built on RADIUS. Dynamic customers draw from IPv4 pools defined on the BNG; static customers have their address returned via Framed-IP-Address in the Access-Accept. We deliberately avoid RADIUS-based pools for IPv4 because tracking and releasing resources for large numbers of customers is hard — the BNG does this far better, releasing the resource when the PPP session drops.
For IPv6 we wanted the same property: static prefix assignment per customer, with the dynamic (pool) option still available. For the tests below I used the same prefix on the WAN and LAN sides to keep things simple, but in production they would normally differ.
| |
We run Internet access inside a VRF, so the per-customer AVpair also re-asserts the unnumbered source interface (the VRF-forwarding service policy otherwise strips the source address):
| |
Per-Customer RADIUS Attributes
| Attribute | Example | Purpose |
|---|---|---|
Framed-IPv6-Prefix | 2a02:ff0:00f0:0003::/64 | Static WAN prefix (SLAAC) |
Delegated-IPv6-Prefix | 2a02:ff0:00f0:0002::/64 | Static LAN prefix (DHCPv6) |
Framed-IPv6-Pool | dynamic-pool-1 | Dynamic WAN prefix pool name |
Delegated-IPv6-Prefix-Pool | dynamic-pd-pool-1 | Dynamic LAN prefix pool name |
Framed-Interface-Id | DEDE:DEDE:DEDE:DEDE | CPE WAN interface ID |
Customer Profiles
| Profile | WAN | LAN | Notes |
|---|---|---|---|
| Static WAN + Static LAN | Framed-IPv6-Prefix | Delegated-IPv6-Prefix | If you insist on the same prefix for both (strongly discouraged), add no ipv6 nd prefix framed-ipv6-prefix |
| Dynamic WAN + Static LAN | Framed-IPv6-Pool | Delegated-IPv6-Prefix | Most usable option for broadband |
| Static WAN + Dynamic LAN | Framed-IPv6-Prefix | Delegated-IPv6-Prefix-Pool | Easier CPE management if you compute the CPE address from Framed-Interface-Id; assumes no TR-069 |
| Dynamic WAN + Dynamic LAN | Framed-IPv6-Pool | Delegated-IPv6-Prefix-Pool | Fully dynamic |
Tests on Cisco IOS XE (ASR1000)
A few things about the lab are worth stating up front, because they shaped the results. I used a ZTE CPE and macOS as the host. The ZTE CPE in auto mode cannot get a GUA from a DHCPv6-delegated prefix — it wants SLAAC; manual configuration changes that. macOS has no DHCPv6 client at all and configures itself purely from RA. So in this lab, the host’s GUA always comes from SLAAC, and DHCPv6-PD is about what the CPE receives for its LAN.
Each test below keeps the key debug lines inline; the complete per-session debug is linked beneath it.
Test 1 — Framed-IPv6-Prefix alone (why you need no ipv6 nd prefix framed-ipv6-prefix)
In this first run the customer profile returns only Framed-IPv6-Prefix (plus Framed-Interface-Id), and the virtual-template does not carry no ipv6 nd prefix framed-ipv6-prefix. The Access-Accept looks like this:
| |
The Framed-Interface-Id is honored during IPV6CP — the BNG NAKs the CPE’s proposed identifier and the CPE accepts the one from AAA:
| |
The WAN prefix is advertised in RA, so SLAAC works. But because we did not redirect the framed prefix to DHCPv6, the CPE’s DHCPv6 SOLICIT for an IA-PD has nothing to bind to, and the router discards it:
| |
So Framed-IPv6-Prefix on its own gives you a WAN prefix via SLAAC but no LAN delegation. That is exactly the gap no ipv6 nd prefix framed-ipv6-prefix closes. Full session debug: test-1-framed-ipv6-prefix-without-dhcpv6.md.
Test 2 — no ipv6 nd prefix framed-ipv6-prefix (the configuration we use)
Here the virtual-template adds the one missing line:
| |
Now the single Framed-IPv6-Prefix from RADIUS feeds both sides: ND still advertises the prefix for SLAAC on the WAN, and the same prefix is available to the DHCPv6 server for the LAN delegation. This time the SOLICIT is answered from the AAA pool:
| |
The subsequent REQUEST creates the binding and installs the delegated route:
| |
This is the case we run in practice. Because the prefix arrives as Framed-IPv6-Prefix, it shows up in the session’s accounting records, which aligns IPv6 auditing with our existing IPv4 method — no separate DHCPv6 logging required for this first phase. Full session debug: test-2-dynamic-wan-static-lan-recommended.md.
Test 3 — Both Framed and Delegated prefixes
In the last run the profile returns both Framed-IPv6-Prefix (…:0003::/64) and Delegated-IPv6-Prefix (…:0002::/64). Because the delegated prefix is present, no ipv6 nd prefix framed-ipv6-prefix is no longer needed:
| |
The two prefixes now do separate jobs. ND advertises the framed prefix (…:0003) for SLAAC on the WAN, while DHCPv6 hands out the delegated prefix (…:0002) for the LAN:
| |
This confirms the precedence: when both are present, the delegated prefix drives DHCPv6 and the framed prefix drives ND. Using both with the same value is pointless; the value of this mode is precisely that WAN and LAN can differ. Full session debug: test-3-separate-framed-and-delegated-prefixes.md.
IPv6 Static Prefix Assignment via RADIUS (a design sketch)
This second part is a design I worked through but did not lab-test. Treat it as a starting point, not a validated recipe.
As the tests above show, dynamic prefix assignment causes trouble: depending on lifetimes, customer devices can end up holding several prefixes at once, and the audit story is messy. So the obvious question is how to assign a static prefix per customer from AAA.
There are a few approaches. The prefix can be assigned at customer provisioning time. If you have more than one PE, you should manage prefix pools per PE and assign from the customer’s PE — otherwise you lose route summarization on the PE. That means keeping a mapping between customers and their PE.
For AAA-based services the assignment happens in the AAA server. Doing it dynamically (allocate on session start, release on session end) drags in all the pool-management drawbacks we were trying to avoid. A mapping-based approach is cleaner: keep a table that maps customer (and optionally NAS) to a prefix. If you run DSLAMs, you might even map a prefix to each port, so a customer inherits the prefix of whatever port they connect to.
The flow behaves a little like a dynamic pool, but the binding is sticky:
When a prefix request comes in, the AAA server looks up the customer in the mapping. If found, it returns the existing prefix. If not, it picks a free prefix, assigns it, and returns it. Including the NAS in the mapping lets a customer move between PEs (an infrequent move — adding a new NAS and spreading users across it, or a customer relocating — not Wi-Fi-style roaming).
Table format
| |
Constraints:
NasIPAddress+prefixmust be unique.prefix+usernamemust be unique.- To seed it, insert every prefix for a given NAS with an empty
username.
AAA flow
Look up the customer’s existing prefix:
| |
If nothing is found, claim a free prefix for this user. In a multithreaded AAA server two threads can race on the same row, so randomize which free row you take to spread the contention:
| |
Then read it back. The earlier UPDATE may have lost the race to another thread, so the re-SELECT is what tells you whether you actually own a prefix:
| |
If this still returns nothing, the allocation failed — reject the session and let the CPE retry. If a NAS runs out of free prefixes, that reject is also your signal to raise a warning for that NAS.
This gives a subscriber the ability to move between PEs while keeping a stable prefix. You do have to clean the table up for such users: find duplicates and keep the latest record.
Reference: IPv6 Address Assignment Methods
A quick recap of the mechanisms referenced throughout, since the right combination depends on your CPE and host OS.
Static — customer and ISP agree on the prefix in advance; assigned at account creation.
SLAAC — based on RA, and effectively required on every link for proper IPv6 operation. RA carries prefixes and lifetimes, some flags, and the default router and its lifetime. For DNS, RFC 6106 (later RFC 8106) adds a DNS option to RA — check CPE and host support.
DHCPv6 stateless — still uses SLAAC for the prefix and router; DHCPv6 only supplies DNS. The host sends RS, the router replies with an RA carrying the other-config flag, and the host then queries DHCPv6 for DNS.
DHCPv6 stateful — SLAAC only kicks off the process. The host sends RS, the router replies with the managed-config flag, and the host configures prefix and DNS over DHCPv6 (using its link-local address). If no router is found, the host may start stateful DHCPv6 on its own.
DHCPv6 prefix delegation — the ISP↔CPE case. An extension to DHCPv6 that delegates a set of subnets rather than a single address.
OS behavior also depends on the combination of the A bit and the M/O flags; the IETF draft “DHCPv6/SLAAC Interaction Problems on Address and DNS Configuration” covers the failure modes.
| Flag | Meaning | Effect on the host |
|---|---|---|
| M (Managed) | Get the address/prefix from DHCPv6 | Host uses DHCPv6, not SLAAC, for addressing |
| O (Other) | Get other config from DHCPv6 | Host uses SLAAC for the prefix, DHCPv6 for DNS |
| A (Address/autonomous) | Use the RA prefix for SLAAC | Host derives its address from the RA prefix |
A note on logging
The ISP logs the customer’s assigned prefix (a /64 or shorter), either via a RADIUS AVP or from the static mapping. Logging individual host addresses is much harder for enterprise customers, and IPv6 Privacy Extensions — on by default in most operating systems — make it worse: the OS generates a fresh temporary address per service, so a single user produces a great many addresses, and the hashed generation complicates troubleshooting. It can be turned off at the OS level; check current guidance for the OS in question. This is another argument for logging the prefix, not the address.
Summary
The practical conclusions from this work:
- Run a single dual-stack PPP session per subscriber — more efficient than separate IPv4/IPv6 sessions.
- Prefer static /64 (or /60) prefixes — simpler auditing and customer management, and no NAT to worry about.
- On Cisco IOS XE,
no ipv6 nd prefix framed-ipv6-prefixlets one attribute drive both WAN and LAN (Test 2) — and keeps the prefix in session accounting. - Use separate
Framed-andDelegated-prefixes when WAN and LAN must differ (Test 3); the delegated prefix wins for DHCPv6. - For static per-customer assignment, a mapping table in AAA beats dynamic pools — at the cost of writing careful, race-safe lookup logic.
- Log the prefix, not the address — Privacy Extensions make per-address logging impractical.
References
- Cisco Live BRKRST-2304 — Deploying IPv6 in Broadband Access Networks
- Building an IPv6 Address Management System (NANOG)
- Broadband Forum TR-187 — IPv6 for PPP Broadband Access
- Configuring the Cisco IOS XE DHCP Server
- RFC 5072 — IP Version 6 over PPP
- RFC 6106 — IPv6 Router Advertisement Options for DNS Configuration
- RFC 6177 — IPv6 Address Assignment to End Sites
- RFC 6911 — RADIUS Attributes for IPv6 Access Networks
- Jordan Dobson — IPv6CP + DHCPv6 + SLAAC + RA / MTU notes
The content of this post was created by the author; AI was used for editing and restructuring.