TTR Networks

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

Build the lab yourself

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

Two VyOS VMs and two FRR containers. Put ./vyos (from the Packets That Never Come Back lesson's get-vyos.sh) and FRR's daemons file (with bgpd=yes) next to these files, run docker compose up -d --build, then ./setup.sh. Apply the VyOS configuration blocks in the order the lesson shows them.

lab-compose.yaml
# Needs ./vyos (from the tcpdump-and-vyos lesson's get-vyos.sh) and ./daemons (copy /etc/frr/daemons out of the FRR image, set bgpd=yes).
# Then: docker compose up -d --build && ./setup.sh
name: vyos-rfc8950-lab
x-frr: &frr
  image: quay.io/frrouting/frr:10.2.1
  privileged: true
x-vyos: &vyos
  build:
    context: .
    dockerfile_inline: |
      FROM debian:bookworm-slim
      RUN apt-get update && apt-get install -y --no-install-recommends qemu-system-x86 iproute2 socat
      COPY start-vyos.sh /usr/local/bin/start-vyos.sh
      CMD ["/usr/local/bin/start-vyos.sh"]
  cap_add: [NET_ADMIN]
  devices: ["/dev/net/tun:/dev/net/tun"]
  volumes: ["./vyos:/vyos:ro"]
services:
  r1:
    <<: *vyos
    environment: { VYOS_MEM: "1536", VYOS_SMP: "1", VM_ID: "01" }
    networks: { c1-r1: { interface_name: eth0 }, r1-r2: { interface_name: eth1 } }
  r2:
    <<: *vyos
    environment: { VYOS_MEM: "1536", VYOS_SMP: "1", VM_ID: "02" }
    networks: { r1-r2: { interface_name: eth0 }, r2-c2: { interface_name: eth1 } }
  c1:
    <<: *frr
    volumes: ["./daemons:/etc/frr/daemons:ro", "./c1.conf:/etc/frr/frr.conf"]
    networks: { c1-r1: { interface_name: eth0, driver_opts: { com.docker.network.endpoint.sysctls: "net.ipv6.conf.IFNAME.disable_ipv6=0" } } }
  c2:
    <<: *frr
    volumes: ["./daemons:/etc/frr/daemons:ro", "./c2.conf:/etc/frr/frr.conf"]
    networks: { r2-c2: { interface_name: eth0, driver_opts: { com.docker.network.endpoint.sysctls: "net.ipv6.conf.IFNAME.disable_ipv6=0" } } }
# IPv4-only Docker networks: Docker adds no IPv6 at all. setup.sh removes Docker's IPv4 from the FRR containers.
networks:
  c1-r1: { ipam: { config: [{ subnet: "172.31.60.0/24" }] } }
  r1-r2: { ipam: { config: [{ subnet: "172.31.61.0/24" }] } }
  r2-c2: { ipam: { config: [{ subnet: "172.31.62.0/24" }] } }
  • Lines 19–26: Two VyOS VMs, each with a unique ID.
  • Lines 27–34: Docker enables IPv6 on the FRR containers' interfaces without adding any IPv6 addresses.
  • Lines 35–39: IPv4-only Docker networks, so Docker adds no IPv6 of its own.
setup.sh
#!/bin/sh
# Remove only Docker's IPv4 (172.31.x) from the FRR containers; FRR's config provides the real addressing.
# accept_ra=0: FRR sends RAs for extended-nexthop peers, and C1 must not autoconfigure from its own reflected RA.
cd "$(dirname "$0")"
for c in c1 c2; do
  docker compose exec -T $c sh -c 'sysctl -qw net.ipv6.conf.eth0.accept_ra=0; for a in $(ip -4 -o addr show dev eth0 | awk "/172\.31\./{print \$4}"); do ip addr del $a dev eth0; done; ip -4 route del default 2>/dev/null; ip -6 addr flush dev eth0 scope global dynamic; true'
done
echo setup done
  • Lines 2–3: Why the setup is needed.
  • Line 6: Remove Docker's IPv4 and stop C1 autoconfiguring from its own reflected RAs.
start-vyos.sh
#!/bin/sh
# Bridge every container interface (eth0, eth1, …) to a tap, then boot VyOS with one virtio NIC per tap.
# Each VM gets a fixed SMBIOS UUID: VyOS derives its DHCPv6 DUID from it, and without one DHCPv6 clients fail.
# VM NIC n gets MAC 52:54:00:<VM_ID>:0n:01, so VyOS's ethN matches the container's ethN. Give each VM its own VM_ID.
set -e
NETDEVS=""
n=0
for ifc in $(ls /sys/class/net | grep -E '^eth[0-9]+$' | sort -V); do
  ip link add "br$n" type bridge
  ip link set "$ifc" master "br$n"
  ip tuntap add "tap$n" mode tap
  ip link set "tap$n" master "br$n"
  ip link set "tap$n" up
  ip link set "br$n" up
  # Pin the VM's MAC to its tap and stop learning on the Docker side: Docker reflects the VM's
  # broadcasts back, which would otherwise teach the bridge the VM's MAC on the wrong port.
  bridge link set dev "$ifc" learning off
  bridge fdb replace "52:54:00:${VM_ID:-00}:0$n:01" dev "tap$n" master static
  NETDEVS="$NETDEVS -netdev tap,id=n$n,ifname=tap$n,script=no,downscript=no -device virtio-net-pci,netdev=n$n,mac=52:54:00:${VM_ID:-00}:0$n:01"
  n=$((n + 1))
done
exec qemu-system-x86_64 -m "${VYOS_MEM:-2048}" -smp "${VYOS_SMP:-2}" -cpu max -accel tcg,thread=multi \
  -uuid "00000000-0000-4000-8000-0000000000${VM_ID:-00}" \
  -kernel /vyos/vmlinuz -initrd /vyos/initrd.img \
  -append "boot=live components hostname=vyos username=live nopersistence noautologin nonetworking union=overlay console=ttyS0,115200 net.ifnames=0 biosdevname=0" \
  -cdrom /vyos/vyos.iso $NETDEVS \
  -display none -serial unix:/run/console.sock,server=on,wait=off -monitor none
  • Line 3: Each VM gets a UUID (needed for DHCPv6, harmless here).

Where next

  • IPv6 on VyOS: setup and routingPrerequisite · Beginner · 55 min

    Number a site from an ISP's /48 on VyOS: WAN and blackhole routes, SLAAC with Router Advertisements, handing a /56 to a downstream router statically and with DHCPv6 prefix delegation, and the forward firewall IPv6 needs because there's no NAT. Every output comes from a real two-router VyOS lab.

  • BGP FundamentalsPrerequisite · Intermediate · 75 min

    How the Border Gateway Protocol glues the internet together: autonomous systems, sessions, path attributes, best-path selection, iBGP scaling and a hands-on eBGP lab with real FRR configuration.

  • BGP on loopbacks vs interface addressesAlso covers BGP · Intermediate · 45 min

    Why BGP sessions between loopbacks survive link failures and use parallel links, and what they need to work: an IGP or static routes, update-source, the eBGP connected check, and BFD. Every failure is reproduced on two real VyOS routers.

  • OSPF on VyOS: costs and OSPFv3Also covers IPv6 · Intermediate · 30 min

    OSPF the VyOS way: interface-based configuration, reading the interface and database output, steering traffic with costs (and the asymmetric routing that follows), and OSPFv3 for IPv6 over link-local addresses. Captured on the three-router edge/core lab.