You have an IPv4 MPLS L3VPN running. Your customers each have their own VRF, their own routing table, their own isolated slice of the core. It works, it scales, it makes money. Then a customer asks for IPv6, and you discover that your entire VPN infrastructure - VPNv4, route distinguishers, route targets, the lot - only understands IPv4.
6VPE is the answer. It carries IPv6 L3VPN across the same IPv4 MPLS core, using the same VRFs, the same RDs and RTs, the same MP-BGP sessions - just with an IPv6 address family bolted on. This article builds it in a CML lab and shows the two-label stack that makes it work. For the fundamentals, start at the complete MPLS guide.
6VPE vs 6PE: know the difference
These two are constantly confused, and the distinction is the whole point.
Isolation: none - one global IPv6 table
Labels: one VPN label per prefix
For: IPv6 internet transit over a v4 core
Isolation: full - per-VRF, with RDs and RTs
Labels: two (transport + VPN)
For: IPv6 L3VPN sold to multiple customers
If you covered 6PE already, 6VPE is 6PE plus VRF isolation. It uses the VPNv6 address family (AFI 2, SAFI 128) instead of plain labelled IPv6, and every prefix gets a route distinguisher so overlapping customer address space stays separate.
The lab
A classic MPLS L3VPN: CE1 - PE1 - P - PE2 - CE2. The core (PE1, P, PE2) is IPv4-only with OSPF and LDP. There is one VRF, CUST-A, with RD 100:1 on PE1 and 100:2 on PE2, and route-target 100:1 both ways. The CE-PE links are dual-stack. Both customer sites even advertise the same prefix, 172.16.10.0/24, deliberately - to prove the RD keeps them separate.
The VRF, now with an IPv6 address family
vrf definition CUST-A
rd 100:1
address-family ipv4
route-target export 100:1
route-target import 100:1
exit-address-family
address-family ipv6
route-target export 100:1
route-target import 100:1
exit-address-familyNote that the RD is defined once at the VRF level and applies to both families. The route targets are set per address family (they happen to be the same here, but they need not be).
The MP-BGP sessions
router bgp 100
neighbor 3.3.3.3 remote-as 100
neighbor 3.3.3.3 update-source Loopback0
!
address-family vpnv4
neighbor 3.3.3.3 activate
neighbor 3.3.3.3 send-community extended
!
address-family vpnv6
neighbor 3.3.3.3 activate
neighbor 3.3.3.3 send-community extended
!
address-family ipv6 vrf CUST-A
neighbor 2001:DB8:1::2 remote-as 65100
neighbor 2001:DB8:1::2 activate
neighbor 2001:DB8:1::2 as-overrideOne iBGP session between the PE loopbacks carries both VPNv4 and VPNv6. That is the elegance of it - the same session, the same core, one more address family. The send-community extended is mandatory: route targets are extended communities, and without it the whole VPN mechanism silently fails.
The two-label stack
This is what makes 6VPE work and what distinguishes it from 6PE. Look at the labels PE1 has for the remote customer prefixes:
PE1#show bgp vpnv6 unicast all labels
Network Next Hop In label/Out label
Route Distinguisher: 100:1 (CUST-A)
2001:DB8:AA::11/128 2001:DB8:1::2 19/nolabel
2001:DB8:AA:10::/64 2001:DB8:1::2 20/nolabel
2001:DB8:BB::22/128 ::FFFF:3.3.3.3 nolabel/19
2001:DB8:BB:10::/64 ::FFFF:3.3.3.3 nolabel/20Two things to read here. The next hop for the remote prefixes is ::FFFF:3.3.3.3 - an IPv4-mapped IPv6 address, exactly as in 6PE, because the BGP session runs over IPv4. And each prefix carries a VPN label (19, 20).
But that is only the inner label. When PE1 actually forwards an IPv6 packet to a customer behind PE2, it pushes two labels:
- Outer (transport) label - the LDP label to reach PE2's loopback (3.3.3.3) across the core. The P router swaps this hop by hop and never looks deeper.
- Inner (VPN) label - the per-VRF label that tells PE2 which VRF the packet belongs to. Only PE2 sees it.
Watch it in a live IPv6 traceroute from CE1 to CE2:
CE1#traceroute 2001:DB8:BB::22 source 2001:DB8:AA::11 probe 1 timeout 2
1 2001:DB8:1::1 2 msec
2 ::FFFF:10.0.12.2 [MPLS: Labels 17/19 Exp 0] 5 msec
3 2001:DB8:2::1 [MPLS: Label 19 Exp 0] 4 msec
4 2001:DB8:2::2 5 msecHop 2 shows Labels 17/19 - the two-label stack, transport 17 on top, VPN 19 underneath. Hop 3, after penultimate-hop popping has removed the transport label, shows just Label 19, the VPN label about to be used by PE2 to select the VRF. An IPv6 packet, in a two-label MPLS stack, crossing an IPv4 core, arriving in the right customer VRF. That is 6VPE.
And end to end:
CE1#ping 2001:DB8:BB::22 source Loopback0
!!!!!
Success rate is 100 percent (5/5)The RD keeps overlapping customers separate
Both customer sites advertise 172.16.10.0/24. In a plain routed network that would be a conflict. In an L3VPN it is fine, because each prefix is prepended with its route distinguisher to form a globally unique VPN prefix:
PE1#show bgp vpnv4 unicast all 22.22.22.22/32
BGP routing table entry for 100:2:22.22.22.22/32That 100:2: prefix is the RD from PE2 making CE2's route distinct from anything on PE1. The RD's only job is to make otherwise-identical prefixes unique in the VPNv4/VPNv6 table. It plays no part in deciding VPN membership - that is the route target's job. (For the full RD-versus-RT distinction, see the RD vs RT article.)
Design notes
- The core never changes. The P routers run IPv4 and LDP and are completely unaware IPv6 exists. This is the entire commercial appeal - you deliver IPv6 L3VPN without touching, re-testing, or risking the core.
- One session, two families. VPNv4 and VPNv6 ride the same iBGP session between PE loopbacks. You do not build a parallel IPv6 BGP mesh.
send-community extendedeverywhere. Route targets are extended communities. Forget this on one PE and that PE's routes never import into any VRF.- The CE-PE protocol is your choice. BGP, OSPFv3, static, whatever. This lab uses BGP with
as-overridebecause both CEs share an AS - covered next.
Troubleshooting
- VPNv6 prefixes present in BGP but not in the VRF? Route-target import/export mismatch, or missing
send-community extended. Checkshow bgp vpnv6 unicast allvsshow ipv6 route vrf. - Prefixes in the VRF but no forwarding? The label stack is broken.
show bgp vpnv6 unicast all labels- if the out-label isnolabelwhere it should be numbered, the VPN label was not assigned. Check the LDP LSP to the remote PE loopback. - Next hop inaccessible? The IPv4-mapped next hop
::FFFF:x.x.x.xmust resolve through the IGP with a label-switched path. No LSP to the remote PE loopback, no 6VPE. - Overlapping prefixes colliding? Your RDs are not unique between PEs. Give each PE a distinct RD for the VRF.
Key takeaways
- 6VPE carries IPv6 L3VPN over an unchanged IPv4 MPLS core using the VPNv6 address family - 6PE plus per-VRF isolation.
- It uses a two-label stack: an outer LDP transport label to the remote PE, and an inner per-VRF VPN label. An IPv6 traceroute across the core shows both (
Labels 17/19). - The BGP next hop is an IPv4-mapped IPv6 address (
::FFFF:x.x.x.x), because the session runs over IPv4. - VPNv4 and VPNv6 share the same iBGP session between PE loopbacks. One session, two families.
- The RD makes overlapping customer prefixes unique in the VPN table; the RT decides VPN membership. Both are needed.
send-community extendedis mandatory - route targets are extended communities.
Next: BGP as the PE-CE protocol: as-override, allowas-in, and SoO, which this lab already set up. The full cluster index lives on the MPLS pillar, with the IPv6 angle on the IPv6 pillar.