An Overview and Cheat Sheet for systemd networkd configurations

2023-09-23

This is a short cheat sheet for things that I often need to do with systemd-networkd, the network configuraton component of systemd. This post assumes some basic knowledge about systemd-networkd and is primarily a collection of examples.

CLI overview

The CLI tool for systemd-networkd is networkctl.

networkctl shows a short status over all interfaces

networkctl reload reloads and applies the configuration of all interfaces.

networkctl status shows a general status as well as the logs. Check the logs if something does not work as intended. Syntax errors and the like are logged here.

The logs can also be accessed via the journal, usually with journalctl -xef -u systemd-networkd

Configuration Files

systemd-networkd is configured via files usually located in /etc/systemd/network/. There are 3 kinds of files

  • .link-files that are used for renaming interfaces (Documentation)
  • .netdev-files that are creating interfaces (Documentation)
  • .network-files that handle the L3-behaviour of those interfaces (Documentation)

The files are loaded sorted by their name, so it is a good practice to name them starting with numbers to define their order.

Interface renaming

To rename a interface we can first match on some parameters and then give it a new name:

# 00-iface42.link
[Match]
MACAddress=11:22:33:44:55:66
Type=ether
[Link]
Name=iface42

The Type=ether is important when you want to create VLAN interfaces on the renamed interface. By default the VLAN Interfaces would have the same MAC addresses as the main interface. If only the MAC address is matched then the main interface and the VLAN interfaces would all be renamed, leading to hard to find errors. The Type=ether matches only on the ethernet interface, because the VLAN interfaces have vlan as their type. Source: systemd-devel mailing list

VLAN Interfaces

First we have to create the VLAN Interface eth1.102 and assign it the VLAN-ID 102

# 10-eth1.102.netdev
[NetDev]
Name=eth1.102
Kind=vlan

[VLAN]
Id=102

Note that the name of the interface can be chosen arbitrarily and does not have to contain the vlan id.

Then we can assign the VLAN to an other interface:

# 10-eth1.network 
[Match]
Name=eth1

[Network]
VLAN=eth1.102

VRFs

Each VRF needs a routing table assigned to it. In this example it is table 102.

# 10-vrf-uplink-1.netdev
[NetDev]
Name=vrf-uplink-1
Kind=vrf

[VRF]
TableId=102

To bring the VRFs up you need a network file for them. You can use the same file for all your VRFs. An easy example would be

# 99-vrf.network
[Match]
Kind=vrf

[Link]
ActivationPolicy=up
RequiredForOnline=no

Some manuals suggest to match the name here, e.g. Name=vrf-*, however this requires all your vrfs to start with vrf- which might not be the case.

To assign an interface to a VRF, create a network file for that interface:

# 20-eth2.network
[Match]
Name=eth2

[Network]
VRF=vrf-uplink-1

Assigning IP Addresses

SLAAC + DHCP

To run SLAAC for IPv6 and DHCP for legacy IP a network file is added:

[Match]
Name=eth0

[Network]
DHCP=yes
IPv6AcceptRA=yes
IPv6PrivacyExtensions=yes

The handling of IPv6 RAs is a bit complicated, check the documentation for IPv6AcceptRA for details. The IPv6PrivacyExtensions=yes enables IPv6 privacy extensions.

The set the route metric (this is relevant if you have multiple interfaces and e.g. want to prefer your wired over your wireless interface) add the following lines:

...
[DHCPv4]
RouteMetric=200

[IPv6AcceptRA]
RouteMetric=200

Static Addresses

[Match]
Name=wg-1

[Network]
Address=2a0a:4587:2001:1015::/127

Routes

Static routes can be added with the [Route] config section in the network files. To add more routes, simply add more [Route] config sections.

[Route]
Destination=10.42.123.0/28
Gateway=192.0.2.1

[Route]
Destination=2001:db8:101::/46
Gateway: 2001:db8::1

Wireguard Tunnels

For Wireguard a keypair is needed which can be generated with

mkdir -p /etc/wireguard
cd /etc/wireguard
wg genkey | tee privatekey | wg pubkey > publickey

Then the netdev looks like this

[NetDev]
Name=wg-1
Kind=wireguard

[WireGuard]
PrivateKeyFile=/etc/wireguard/privkey
ListenPort=51820

# for a client we only want to listen for but not actively connect to
[WireGuardPeer]
PublicKey=<peers public key here>
AllowedIPs=::/0, 0.0.0.0/0

# for a peer to which we want to connect to
[WireGuardPeer]
PublicKey=<peers public key here>
AllowedIPs=::/0, 0.0.0.0/0
Endpoint=[2001:db8::1234]:51821

Additionally a network file is needed:

[Match]
Name=wg-1

[Network]
Address=172.16.44.1/31