TTR Networks

Intermediate · IPv4 over an IPv6-only core (RFC 8950) · section 6 of 8

The data plane

✓ Lab-tested 17 October 2026 on VyOS 2026.10.16-0024-rolling, FRR 10.2.1

Control plane done. Now the real test: can C1 reach C2 over IPv4, across a router with no IPv4 address?

C1's own route to 203.0.113.0/24 points at R1's link-local address, and a ping from C1's loopback to C2's loopback works. C2 is entirely unaware of any of this. It has an ordinary IPv4 route with next hop 192.0.2.1, because R2 speaks plain IPv4 BGP to it.

On the wire it's plain IPv4. A capture on the R1–R2 link shows ordinary IP echo requests and replies: no IPv6 header around them, no tunnel, no translation. The only IPv6 involvement is how R1 found the destination MAC address. Its IPv6 neighbour table maps R2's link-local next hop (fe80::5054:ff:fe02:1) to R2's MAC address (52:54:00:02:00:01), and that's the address the IPv4 frames are sent to. R1 never resolves an IPv4 neighbour with ARP. (The neighbour table also has entries for Docker's own interfaces on these networks, which you can ignore.)

What traceroute shows: 192.0.0.8

Traceroute from C1 shows three hops, and the first is 192.0.0.8. That's R1. To send a "time exceeded" message, a router needs an IPv4 source address, and R1 has none. Linux handles this by using 192.0.0.8, the "IPv4 dummy address" that RFC 7600 reserves for exactly this situation.

In a real IPv6-only core, every core hop shows as 192.0.0.8. Traceroute still shows how many hops there are and their latency, but not which router is which. If you need to identify hops, give each router a loopback IPv4 address after all (it doesn't need to be routed anywhere), or use IPv6 traceroute between the routers' own addresses.

One more consequence: 192.0.0.0/24 is IANA special-purpose space, and some bogon filters drop it. A firewall that drops packets from 192.0.0.8 also drops the ICMP errors that IPv4 path MTU discovery and traceroute depend on.

From C1 (real output)
c1# ip -4 route
blackhole 198.51.100.0/24 proto 196 metric 20
203.0.113.0/24 nhid 13 via inet6 fe80::5054:ff:fe01:1 dev eth0 proto bgp metric 20
c1# ping -c 3 -I 198.51.100.1 203.0.113.1
PING 203.0.113.1 (203.0.113.1) from 198.51.100.1: 56 data bytes
64 bytes from 203.0.113.1: seq=0 ttl=62 time=2.931 ms
64 bytes from 203.0.113.1: seq=1 ttl=62 time=4.399 ms
64 bytes from 203.0.113.1: seq=2 ttl=62 time=3.345 ms

--- 203.0.113.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 2.931/3.558/4.399 ms
c1# traceroute -n -s 198.51.100.1 203.0.113.1
traceroute to 203.0.113.1 (203.0.113.1) from 198.51.100.1, 30 hops max, 46 byte packets
 1  192.0.0.8  5.510 ms  0.338 ms  0.179 ms
 2  192.0.2.1  3.012 ms  1.106 ms  0.548 ms
 3  203.0.113.1  0.777 ms  0.669 ms  0.534 ms
  • Line 3: C1's route to C2: via R1's link-local address.
  • Lines 4–12: IPv4, loopback to loopback, across R1.
  • Line 15: Hop 1 is R1, answering from 192.0.0.8.
  • Line 16: R2 answers from its real IPv4 address.
C2 knows nothing about it (real output)
c2# ip -4 route
192.0.2.0/30 dev eth0 proto kernel scope link src 192.0.2.2
198.51.100.0/24 nhid 13 via 192.0.2.1 dev eth0 proto bgp metric 20
blackhole 203.0.113.0/24 proto 196 metric 20
c2# vtysh -c 'show ip bgp'
[... 7 header lines trimmed ...]

     Network          Next Hop            Metric LocPrf Weight Path
 *>  198.51.100.0/24  192.0.2.1                              0 64501 64500 64512 i
 *>  203.0.113.0/24   0.0.0.0                  0         32768 i

Displayed 2 routes and 2 total paths
  • Line 3: An ordinary IPv4 route.
  • Line 9: AS path through the IPv6-only core, with an IPv4 next hop.
On the R1–R2 link (real output)
vyos@R1:~$ monitor traffic interface eth1 filter icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
01:26:49.326510 IP 198.51.100.1 > 203.0.113.1: ICMP echo request, id 111, seq 0, length 64
01:26:49.327824 IP 203.0.113.1 > 198.51.100.1: ICMP echo reply, id 111, seq 0, length 64
01:26:50.327728 IP 198.51.100.1 > 203.0.113.1: ICMP echo request, id 111, seq 1, length 64
01:26:50.329262 IP 203.0.113.1 > 198.51.100.1: ICMP echo reply, id 111, seq 1, length 64
01:26:51.331728 IP 198.51.100.1 > 203.0.113.1: ICMP echo request, id 111, seq 2, length 64
01:26:51.333776 IP 203.0.113.1 > 198.51.100.1: ICMP echo reply, id 111, seq 2, length 64
01:26:52.338481 IP 198.51.100.1 > 203.0.113.1: ICMP echo request, id 111, seq 3, length 64
01:26:52.342541 IP 203.0.113.1 > 198.51.100.1: ICMP echo reply, id 111, seq 3, length 64
01:26:53.336106 IP 198.51.100.1 > 203.0.113.1: ICMP echo request, id 111, seq 4, length 64
01:26:53.336886 IP 203.0.113.1 > 198.51.100.1: ICMP echo reply, id 111, seq 4, length 64
01:26:54.339484 IP 198.51.100.1 > 203.0.113.1: ICMP echo request, id 111, seq 5, length 64
01:26:54.341178 IP 203.0.113.1 > 198.51.100.1: ICMP echo reply, id 111, seq 5, length 64
^C
12 packets captured
12 packets received by filter
0 packets dropped by kernel
  • Lines 4–15: Plain IPv4 packets: no tunnel, no translation.
Where the MAC address comes from (real output)
vyos@R1:~$ show ipv6 neighbors
Address                    Interface    Link layer address    State
-------------------------  -----------  --------------------  ---------
fe80::4887:f5ff:fe42:31b4  eth1         4a:87:f5:42:31:b4     STALE
fe80::5054:ff:fe01:1       eth0         52:54:00:01:00:01     STALE
fe80::5054:ff:fe02:1       eth1         52:54:00:02:00:01     REACHABLE
fe80::d094:c9ff:fe61:8e6a  eth1         d2:94:c9:61:8e:6a     STALE
fe80::5054:ff:fe01:101     eth1         52:54:00:01:01:01     STALE
fe80::a408:a3ff:fef7:b5d2  eth0         a6:08:a3:f7:b5:d2     STALE
2001:db8:0:2::2            eth1         52:54:00:02:00:01     STALE
fe80::f060:2ff:fe38:6b9c   eth1         f2:60:02:38:6b:9c     STALE
fe80::78c8:f1ff:fe05:427   eth0         7a:c8:f1:05:04:27     REACHABLE
2001:db8:0:1::2            eth0         7a:c8:f1:05:04:27     DELAY
  • Line 6: R2's link-local next hop, resolved by Neighbor Discovery to R2's MAC address.
  • Line 12: C1's, the same way.
R1's ARP table (real output)
vyos@R1:~$ show arp
Address      Interface    Link layer address    State
-----------  -----------  --------------------  ---------
169.254.0.1  eth1         52:54:00:01:01:01     PERMANENT
  • Line 4: Not real ARP: no IPv4 neighbour was ever resolved. FRR keeps a 169.254.0.1 placeholder entry for peers it learns from Router Advertisements; here it carries R1's own MAC, most likely from Docker reflecting R1's RA back to it. Forwarding doesn't use it: the kernel routes are via inet6.

Check your understanding

A traceroute across an IPv6-only core shows 192.0.0.8 at several hops. What does that mean?

  • Those routers have no IPv4 address, so they send ICMP errors from the RFC 7600 dummy address
  • Traffic is being NATed
  • A loop through one router
  • Packets are being dropped