MPLS

MPLS VPNv6 and 6VPE: IPv6 L3VPN over an IPv4 Core

6VPE - IPv6 traceroute showing a two-label MPLS stack across an IPv4 core on Cisco IOS XE
In: MPLS, IPv6, BGP, Labs, CCIE

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.

6PE
Address family: ipv6 unicast + send-label
Isolation: none - one global IPv6 table
Labels: one VPN label per prefix
For: IPv6 internet transit over a v4 core
6VPE
Address family: vpnv6 unicast
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-family

Note 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-override

One 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/20

Two 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 msec

Hop 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/32

That 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 extended everywhere. 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-override because both CEs share an AS - covered next.

Troubleshooting

  1. VPNv6 prefixes present in BGP but not in the VRF? Route-target import/export mismatch, or missing send-community extended. Check show bgp vpnv6 unicast all vs show ipv6 route vrf.
  2. Prefixes in the VRF but no forwarding? The label stack is broken. show bgp vpnv6 unicast all labels - if the out-label is nolabel where it should be numbered, the VPN label was not assigned. Check the LDP LSP to the remote PE loopback.
  3. Next hop inaccessible? The IPv4-mapped next hop ::FFFF:x.x.x.x must resolve through the IGP with a label-switched path. No LSP to the remote PE loopback, no 6VPE.
  4. 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 extended is 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.

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.