RFC8950: Announce IPv4 with an IPv6 next-hop
For the last few days I have been playing with RFC8950 setup, which allows routing of IPv4 on top of IPv6. While logically it’s quite simple, it has a very powerful application towards making “IPv4 an optional” feature riding on top of an IPv6 network (but without any tunnels!)
Some of the interesting use cases:
- A large network can run IPv6 only everywhere on its core and leave IPv4 only on edge devices. This can work without customers doing any tweaking at their end. They still do things the old way but Backbone can run IPv6 only at its core.
- An IP transit backbone can run IPv6 only while exchanging IPv4 routes with its customers/peers/upstream over IPv6 sessions. So IPv4 as a “feature” stays but the network in itself is IPv6 only without the overhead of IPv4 interface config, BGP session config, firewall config, etc.
- An IXP can offer services without IPv4 essentually by using a (unique) IPv6 at the IX LAN & running route server to exchange both IPv4 & IPv6 routes over the IPv6 only session.
Thus what 464XLAT did to the mobile networks - this has the potential to do that for the backbone networks.
How does it work?
Multi-protocol BGP (MP-BGP) supports announcement of IPv4 routes over IPv6 sessions with IPv4 next-hops and IPv6 routes over IPv4 sessions with IPv6 next-hops. RFC8950 extends this feature for IPv4 to have IPv6 next-hops. So for IPv4 address, next hop is IPv6, IPv6 reach works via usual NDP and IPv4 rides on ethernet frames to the same MAC as discovered by the NDP. Technically RFC8950 only impacts control plane decisions by using IPv6 as the control plane but keeps the data plane as it is. IPv4 stays IPv4 & goes as IPv4 over the wire unlike say some tunnel or 464xLAT etc.
Hardware support
As of now it’s quite widely supported by a lot of routing platforms like Juniper JunOS, Cisco IOS XR, Nokia SR OS, Mikrotik, Huawei, BIRD, FRR etc. So, it is very likely supported if you are running a recent version of the OS.
Demo lab

Here’s a fun lab with two customer routers: C1 & C2 connected via provider routers R1-R2-R3 in Container Lab. All routers here are running open source FRR.
- C1 is IPv6 only on the WAN side facing R1. It originates 10.0.0.0/24 to R1 over an IPv6 session.
- R1 & R2 are IPv6 only with no IPv4 anywhere on their interfaces (but carry IPv4 routes in their table)
- R3 has IPv6 with R2 but just IPv4 only with C2. So C2 is like a typical enterprise user who lacks IPv6 deployment and still wants IPv4 only to work.
- R3 has 100.64.0.0/24 and originates it in the IPv4 table (to IPv6 adjacency - R2)
- C2 sits on 100.64.0.2/30 given by R3 and communicate in IPv4 only.
- C1 and C2 can reach each other over this network with parts being IPv6 only without any tunnel.
topology.yml
name: rfc8950
topology:
nodes:
R1:
kind: linux
image: frr-with-bgpd
binds:
- configs/R1.conf:/etc/frr/frr.conf
R2:
kind: linux
image: frr-with-bgpd
binds:
- configs/R2.conf:/etc/frr/frr.conf
R3:
kind: linux
image: frr-with-bgpd
binds:
- configs/R3.conf:/etc/frr/frr.conf
C1:
kind: linux
image: frr-with-bgpd
binds:
- configs/C1.conf:/etc/frr/frr.conf
C2:
kind: linux
image: frr-with-bgpd
binds:
- configs/C2.conf:/etc/frr/frr.conf
links:
- endpoints: ["C1:eth1", "R1:eth1"]
- endpoints: ["R1:eth2", "R2:eth1"]
- endpoints: ["R2:eth2", "R3:eth1"]
- endpoints: ["R3:eth2", "C2:eth1"]
> clab deploy -t topology.yml
16:37:08 INFO Containerlab started version=0.76.1
16:37:08 INFO Parsing & checking topology file=topology.yml
16:37:09 INFO Creating lab directory path=~/ipv4-over-ipv6/clab-rfc8950
16:37:09 INFO Creating container name=C2
16:37:09 INFO Creating container name=C1
16:37:09 INFO Creating container name=R1
16:37:09 INFO Creating container name=R2
16:37:09 INFO Creating container name=R3
16:37:09 INFO Created link: R3:eth2 ▪┄┄▪ C2:eth1
16:37:09 INFO Created link: C1:eth1 ▪┄┄▪ R1:eth1
16:37:09 INFO Created link: R1:eth2 ▪┄┄▪ R2:eth1
16:37:09 INFO Created link: R2:eth2 ▪┄┄▪ R3:eth1
16:37:09 INFO Adding host entries path=/etc/hosts
16:37:09 INFO Adding SSH config for nodes path=/etc/ssh/ssh_config.d/clab-rfc8950.conf
╭─────────────────┬───────────────┬─────────┬───────────────────╮
│ Name │ Kind/Image │ State │ IPv4/6 Address │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-C1 │ linux │ running │ 172.20.20.6 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::6 │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-C2 │ linux │ running │ 172.20.20.4 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::4 │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-R1 │ linux │ running │ 172.20.20.2 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::2 │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-R2 │ linux │ running │ 172.20.20.8 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::8 │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-R3 │ linux │ running │ 172.20.20.5 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::5 │
╰─────────────────┴───────────────┴─────────┴───────────────────╯
Checking C1 for route to C2
C1# show ip bgp 100.64.0.2
BGP routing table entry for 100.64.0.0/24, version 2
Paths: (1 available, best #1, table default)
Advertised to non peer-group peers:
2001:db8:0:1::1
65501 65502 65503
2001:db8:0:1::1 from 2001:db8:0:1::1 (172.20.20.2)
(fe80::a8c1:abff:fe60:5467) (used)
Origin IGP, valid, external, best (First path received)
Last update: Mon Jun 22 18:57:38 2026
C1#
C1 -> C2 trace
C1# traceroute 100.64.0.2
traceroute to 100.64.0.2 (100.64.0.2), 30 hops max, 46 byte packets
1 clab-rfc8950-R1.clab (172.20.20.2) 0.004 ms 0.004 ms 0.002 ms
2 clab-rfc8950-R2.clab (172.20.20.8) 0.002 ms 0.003 ms 0.003 ms
3 clab-rfc8950-R3.clab (172.20.20.5) 0.002 ms 0.003 ms 0.003 ms
4 100.64.0.2 (100.64.0.2) 0.002 ms 0.006 ms 0.003 ms
C1#
Note: It took IPv4 from the eth0 management interfaces as deployed by Container Lab for TTL exceeded used in the trace.
If I check R1, it has only IPv6 sessions but no IPv6 prefixes
R1# sh bgp ipv6 summary
IPv6 Unicast Summary (VRF default):
BGP router identifier 172.20.20.2, local AS number 65501 vrf-id 0
BGP table version 0
RIB entries 0, using 0 bytes of memory
Peers 2, using 1434 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
2001:db8:0:1::2 4 64512 151 141 0 0 0 00:39:19 0 0 N/A
2001:db8:0:2::2 4 65502 65 64 0 0 0 00:36:46 0 0 N/A
Total number of neighbors 2
R1#
Checking for IPv4 routes on R1
R1# sh bgp ipv4
BGP table version is 4, local router ID is 172.20.20.2, vrf id 0
Default local pref 100, local AS 65501
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.0.0.0/24 fe80::a8c1:abff:fe44:afb8
0 0 64512 i
*> 100.64.0.0/24 fe80::a8c1:abff:fed8:5eb5
0 65502 65503 i
Displayed 2 routes and 2 total paths
R1#
Router Configs
| Router | Link |
|---|---|
| R1 | Click here |
| R2 | Click here |
| R3 | Click here |
| C1 | Click here |
| C2 | Click here |