How to Configure DHCPv6 Prefix Delegation and Router Advertisements in Ubuntu Using systemd-networkd

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 /56 prefix) to the upstream ISP gateway.
  • Subnet Slicing and Assignment: Systemd-networkd assigns a designated /64 slice 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: Informs systemd-networkd to automatically bind a /64 subnet carved from the WAN prefix to this interface.
  • SubnetId=1: Distributes subnet index 1 to eth1. Secondary interfaces (e.g., eth2 for IoT) would specify SubnetId=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.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.