In modern IPv6 network deployments, Internet Service Providers (ISPs) rarely assign static multi-prefix blocks to edge routers. Instead, upstream networks dynamically allocate a routing prefix (typically a /56, /60, or /64 block) to the edge WAN interface via Dynamic Host Configuration Protocol for IPv6 Prefix Delegation (DHCPv6-PD, RFC 8415). When deploying an Ubuntu server as a dual-stack gateway, router, or container host, the system must receive the delegated prefix, partition it into /64 subnets across internal LAN or virtual bridge interfaces, and broadcast IPv6 Router Advertisements (RA) to downstream clients. With systemd-networkd, this entire workflow is managed natively without external routing daemons.
Understanding DHCPv6-PD and Router Advertisement Architecture
The native IPv6 prefix delegation pipeline in systemd-networkd coordinates three distinct subsystem stages:
- DHCPv6 Client on Uplink (WAN): Sends an explicit Prefix Delegation hint (e.g., requesting a
/56prefix) to the upstream ISP gateway. - Subnet Slicing and Assignment: Systemd-networkd assigns a designated
/64slice of the delegated pool to each configured internal interface (LAN, DMZ, or bridge). - IPv6 Router Advertisements (NDP / SLAAC): Emits periodic ICMPv6 Type 134 Router Advertisement messages across the LAN. Connected client devices (workstations, smartphones, IoT nodes) read the delegated prefix and autonomously generate their own globally routable IPv6 addresses via Stateless Address Autoconfiguration (SLAAC).
Enabling IPv6 Packet Forwarding
Before routing delegated prefixes between WAN and LAN interfaces, enable kernel IPv6 packet forwarding in Ubuntu:
# Enable IPv6 packet forwarding in real time
sudo sysctl -w net.ipv6.conf.all.forwarding=1
# Persist the configuration across reboots
echo "net.ipv6.conf.all.forwarding = 1" | sudo tee -a /etc/sysctl.d/99-ipv6-routing.conf
sudo sysctl --system
Configuring the WAN Interface for Prefix Delegation
Create a network definition file for your public uplink interface (e.g., eth0 or enp3s0) under /etc/systemd/network/10-wan.network:
# Create and edit the WAN configuration file
sudo nano /etc/systemd/network/10-wan.network
Insert the following configuration:
[Match]
Name=eth0
[Network]
DHCP=ipv6
IPv6AcceptRA=yes
[DHCPv6]
WithoutRA=solicit
PrefixDelegationHint=::/56
The PrefixDelegationHint=::/56 directive informs the upstream ISP that the gateway router intends to subnet and manage downstream networks.
Configuring the Internal LAN Interface to Receive Delegated Prefixes
Next, configure the internal LAN interface (e.g., eth1) to consume a delegated subnet from the WAN pool and broadcast Router Advertisements:
# Create the internal LAN network definition
sudo nano /etc/systemd/network/20-lan.network
Define the subnet allocation and router advertisement flags:
[Match]
Name=eth1
[Network]
# Request a delegated prefix from upstream WAN
DHCPPrefixDelegation=yes
# Broadcast ICMPv6 Router Advertisements
IPv6SendRA=yes
[DHCPPrefixDelegation]
# Subnet ID index (e.g., subnet 1 of the delegated block)
SubnetId=1
Assign=yes
[IPv6SendRA]
Managed=no
OtherInformation=yes
RouterLifetimeSec=1800
[IPv6PREF64Prefix]
# Enables NAT64 prefix advertisement if deployed
Key parameters:
DHCPPrefixDelegation=yes:Informssystemd-networkdto automatically bind a/64subnet carved from the WAN prefix to this interface.SubnetId=1:Distributes subnet index 1 toeth1. Secondary interfaces (e.g.,eth2for IoT) would specifySubnetId=2.IPv6SendRA=yes:Enables the kernel ICMPv6 router advertisement daemon.
Restarting systemd-networkd and Applying Configuration
Apply the new network configuration files and restart the network engine:
# Validate syntax and restart the daemon
sudo systemctl restart systemd-networkd
# Confirm operational status
systemctl status systemd-networkd
Auditing and Validating Delegated Prefixes via networkctl
To confirm that the upstream ISP granted the prefix delegation and that the LAN interface successfully bound its assigned subnet, query networkctl:
# Inspect the operational state of network interfaces
networkctl status eth0
networkctl status eth1
The output for eth1 will report an assigned global IPv6 address derived from the delegated block (e.g., 2001:db8:1234:1::1/64) and confirm IPv6SendRA: yes.
Verify global routing and address bindings on the server:
# Inspect configured IPv6 addresses
ip -6 addr show dev eth1
# Inspect active IPv6 kernel routing tables
ip -6 route show
Capturing Router Advertisement Frames on the LAN
To verify that downstream clients receive SLAAC prefix announcements, capture ICMPv6 packets using tcpdump on the internal interface:
# Capture Router Advertisement (Type 134) packets on the LAN
sudo tcpdump -i eth1 -nn -vvv "icmp6 and ip6[40] == 134" -c 5
The trace decodes the autonomous address configuration (A-flag), prefix lifetime, and valid lifetime, confirming that clients can immediately negotiate global IPv6 connectivity.
Configuring DHCPv6-PD natively in systemd-networkd eliminates third-party dependencies like radvd or dibbler, delivering high-performance, dynamic IPv6 routing across Ubuntu server environments.