Carry IPv4 routes over IPv6 sessions with IPv6 next hops (RFC 8950)

For a link that has only IPv6 addresses.

- The Extended Next Hop capability is offered on every session over IPv6
  whose families include IPv4 unicast, and used if the peer offers it too.
  Nothing to configure.
- On such a session our IPv4 routes go out in MP_REACH_NLRI with the
  session's IPv6 address as next hop, and are withdrawn in
  MP_UNREACH_NLRI. Without the agreement they are not sent, as before.
- IPv4 routes are read with an IPv6 next hop, global or global with
  link-local.
- The kernel installer resolves an IPv4 route's IPv6 next hop like any
  other and installs it: by way of an IPv6 nexthop object, or with RTA_VIA
  where routes carry their own gateway.

Tested against a real kernel in both modes, with a link-local next hop
too, and in the lab against FRR and BIRD: the new `v6only` phase takes
the IPv4 addresses off the exchange LAN, runs one IPv6 session with each
router for both families, and pings IPv4 across.

Sessions between link-local addresses are not supported yet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Rayhaan JaufeerallyandClaude Fable 5.1 committed 2026-10-02 17:58:03 +02:00
1 parent 321af51e4b
commit 92e013ca01
14 files changed
+511 -23

No files matched your search

+23 -1
View File
@@ -168,6 +168,26 @@ peers {
}
```
## IPv4 over a link that has only IPv6 addresses (RFC 8950)
A session over IPv6 carries IPv4 routes too, with IPv6 next hops, if the
peer agrees: the daemon offers the Extended Next Hop capability on every
session over IPv6 whose address families include IPv4 unicast, and nothing
has to be configured for it on this side. (On FRR it is `neighbor ...
capability extended-nexthop`, on BIRD `extended next hop on` in the IPv4
channel.) The peers table on the status page says "IPv4 with IPv6 next
hops" for a session that agreed on it.
Our IPv4 routes then go out with the session's own IPv6 address as next
hop, and the peer's arrive with its IPv6 address, or with a global and a
link-local one. In the kernel such a route is an IPv4 route by way of an
IPv6 neighbor (`10.2.0.0/24 via inet6 2001:db8::2 dev eth0`, Linux 5.2 and
later).
The session's addresses have to be global ones (or unique local): a peer
configured by a link-local address (`fe80::...`), which needs the
interface named with it, is not supported yet.
## Forwarding: routes in the kernel (Linux)
With `kernel {}` in the configuration the daemon puts the best route of every
@@ -272,13 +292,15 @@ Routinator 0.15.2. What it covers:
| `restart` | The daemon stopped in good order (kernel emptied, peers told) and killed (routes kept, stale one cleared by the next start) |
| `scale` | A table from BIRD (`SCALE_ROUTES`, a million for the Internet's size) into the table and the kernel; the daemon killed and restarted under it; the table withdrawn |
| `limits` | A peer whose role does not fit gets no session; a peer over its prefix limit gets Cease / Maximum Number of Prefixes and is held down |
| `v6only` | The exchange LAN without IPv4 addresses: one IPv6 session with each router for both families, IPv4 routes with IPv6 next hops (RFC 8950) in BGP and in the kernel, IPv4 pings across |
`scripts/interop/real-rpki.sh` checks the RTR client against a Routinator
that has the real RPKI, ASPAs included: the daemon has to end up with as
many VRPs and ASPAs as the validator says it has.
Not covered: routers other than FRR and BIRD; IPv6 routes over an IPv4
session (the daemon does not send them); long runs.
session (the daemon does not send them); sessions between link-local
addresses; long runs.
## Finding a route