systemd-networkd: Configure VLAN, Bond and Bridge - 夜莺博客

systemd-networkd: Configure VLAN, Bond and Bridge

systemd-networkd is a lean network daemon that manages interfaces from declarative INI-style files instead of a GUI. It is the natural choice on servers, containers and headless hypervisors: no D-Bus GUI dependency, deterministic behavior at boot, and native support for VLANs, bonding and bridges built into the same configuration language. This guide switches a host from NetworkManager to networkd and builds production-ready .network and .netdev files covering static addressing, 802.3ad LACP bonding, bridges, and VLAN stacking, with the exact commands to apply and verify the configuration and the fixes for the problems that appear most often.

Switching to systemd-networkd

Disable NetworkManager and enable networkd only if networkd will own the interfaces - never let both daemons manage the same interface:

sudo systemctl disable --now NetworkManager
sudo systemctl enable --now systemd-networkd systemd-resolved

Two daemons managing one interface is the classic cause of an address that appears and disappears, or one that is assigned twice. If a host still needs NetworkManager for Wi-Fi or for a GUI, list the interfaces networkd should ignore with Unmanaged=yes under [Link], or set NetworkManager.conf to leave the wired devices alone. Pick one owner per interface and stick to it.

Every managed interface needs a matching file under /etc/systemd/network/. A .network file configures an interface; a .netdev file creates virtual devices such as bonds, bridges and VLANs. Files are read in lexical order, which is why the examples use numeric prefixes - the prefix is not required, but it makes the ordering explicit when a physical interface must be enslaved to a bridge that a lower-numbered file already created.

Static IP and DHCP with .network Files

Match by interface name, or by MAC address when names are unpredictable:

# /etc/systemd/network/10-eth0.network
[Match]
Name=eth0

[Network]
Address=192.168.1.50/24
Gateway=192.168.1.1
DNS=1.1.1.1 9.9.9.9
# /etc/systemd/network/10-server.network
[Match]
MACAddress=52:54:00:ab:cd:ef

[Network]
DHCP=yes

The [Match] section is evaluated first and decides whether the file applies at all. Matching on Name= is the common case on servers with predictable interface names; matching on MACAddress= or Path= survives renaming and is the more robust option on virtual machines whose NIC names vary with the PCI slot order. Address= accepts a CIDR suffix; adding a second Address= line configures a second address on the same interface. When both DHCP and a static address are present, networkd keeps whichever arrives and marks the acquired address as dynamic, which is occasionally useful for a management fallback address.

DNS behavior is worth a note. With systemd-resolved running, DNS= entries are pushed into the resolver's per-link table rather than written to /etc/resolv.conf directly, so a host can use a different resolver per interface. See the resolvectl guide linked below if name resolution behaves unexpectedly after the switch.

Bonding (LACP 802.3ad)

Create the bond device with a .netdev file, then attach the member interfaces in .network files. The switch ports must be configured for LACP or the bond will not come up:

# /etc/systemd/network/10-bond0.netdev
[NetDev]
Name=bond0
Kind=bond

[Bond]
Mode=802.3ad
TransmitHashPolicy=layer3+4
LACPTransmitRate=fast
MIIMonitorSec=100ms
# /etc/systemd/network/20-bond-eth0.network
[Match]
Name=eth0
[Network]
Bond=bond0

A second file does the same for eth1. MIIMonitorSec=100ms matches the miimon=100 convention in the kernel bonding driver and detects a failed member within a tenth of a second. LACPTransmitRate=fast asks the switch for one LACPDU per second instead of every thirty, which gives faster failover in exchange for a little more control-plane traffic. TransmitHashPolicy=layer3+4 hashes on IP and port, which is what spreads a small number of large flows across members evenly.

On hosts where the kernel bonding module auto-creates a bond0 that networkd refuses to touch, set options bonding max_bonds=0 in /etc/modprobe.d/bonding.conf and reload. Without that, the kernel may already own the name bond0 before networkd tries to create it, and networkctl reload reports a name conflict that does not name the module option.

Once the bond is up, address it in a third file rather than on the members:

# /etc/systemd/network/30-bond0.network
[Match]
Name=bond0
[Network]
Address=192.168.10.20/24
Gateway=192.168.10.1

VLANs on a Physical or Bonded Interface

Define the VLAN netdev and give it addressing in a separate .network file:

# /etc/systemd/network/20-vlan100.netdev
[NetDev]
Name=eth0.100
Kind=vlan

[VLAN]
Id=100
# /etc/systemd/network/30-eth0.network
[Match]
Name=eth0
[Network]
VLAN=eth0.100
# /etc/systemd/network/40-vlan100.network
[Match]
Name=eth0.100

[Network]
Address=10.100.0.5/24
Gateway=10.100.0.1

Three files cooperate: the .netdev declares the device and its VLAN ID, the parent's .network file lists it under VLAN= so networkd knows to create it when the parent comes up, and the child's .network file supplies the addressing. The naming convention is arbitrary but conventional: eth0.100 mirrors the kernel's own vconfig style. The parent can be a physical NIC, a bond, or a bridge - VLAN= works in all three cases, which is what makes stacking possible.

Bridges

A bridge is a virtual switch for containers or VMs; enslave the physical ports and address the bridge itself:

# /etc/systemd/network/10-br0.netdev
[NetDev]
Name=br0
Kind=bridge

[Bridge]
STP=no
ForwardDelaySec=0
# /etc/systemd/network/20-br0-port.network
[Match]
Name=eth1
[Network]
Bridge=br0
# /etc/systemd/network/30-br0.network
[Match]
Name=br0
[Network]
Address=192.168.1.50/24
Gateway=192.168.1.1

STP=no is the right default for a server bridge with a single uplink and no loops; leaving it on adds the usual forwarding delay every time a port changes state. The port file must not carry addressing - if both the bridge and the enslaved port have addresses, the host answers ARP on two interfaces in the same subnet and the return path becomes unpredictable. For VLAN-aware bridges in networkd, add VLANFiltering=true under [Bridge] and tag ports with BridgeVLAN entries; that arrangement maps directly onto the Proxmox pattern used elsewhere on this site.

Stacking Bond, Bridge and VLAN Together

The real value of networkd is that the same three file types compose. A typical hypervisor node is a bond with a VLAN-aware bridge on top and VLANs for host management:

10-bond0.netdev       Kind=bond, Mode=802.3ad
20-eth0.network       Bond=bond0
20-eth1.network       Bond=bond0
30-br0.netdev         Kind=bridge, VLANFiltering=true
40-bond0.network      Bridge=br0
50-vlan100.netdev     Kind=vlan, Id=100, Name=br0.100
60-br0.network        VLAN=br0.100
70-br0.100.network    Address=10.100.0.10/24

Reading the stack from the bottom: eth0 and eth1 join bond0; bond0 joins br0; br0.100 is a VLAN on the bridge that carries the host management address. Guests are attached to br0 externally with their own tags. Every layer is one file, and the dependency order is expressed by the numeric prefix rather than by scripted ip commands.

networkd Compared with NetworkManager and ifupdown

Choosing networkd is a deliberate trade. NetworkManager is the better fit for laptops, Wi-Fi, VPN profiles and anything with a GUI or a user who expects a connection editor; it is event-driven and reacts to link changes with profiles that can be switched at runtime. The traditional ifupdown pair (/etc/network/interfaces) is simpler but has no runtime model worth the name: a change means ifdown and ifup, and ifupdown does not understand bonds, bridges or VLANs without external helpers such as ifupdown2. Networkd sits between them - declarative like /etc/network/interfaces, but with a live reload, native virtual devices, and a status tool that tells you which file owns which link.

Migration is mostly mechanical but two details catch people out. First, networkd does not manage an interface it has no .network file for, so a host switched over with an incomplete file set loses the interfaces it forgot; write every file before disabling NetworkManager. Second, DHCP option handling differs: networkd can send a client identifier (ClientIdentifier=mac or duid) and request specific options, but the server-side reservation tied to the old client's identifier may need updating. On a host that also runs containers or a hypervisor, confirm that bridge and bond names match what the virtualization layer expects, because networkd will happily create a br0 that shadows one the hypervisor was using.

Applying and Verifying the Configuration

sudo networkctl reload
networkctl status
networkctl status eth0
ip addr show
ip route show
cat /proc/net/bonding/bond0

networkctl reload re-reads the files and applies changes to running links without a reboot; networkctl reload --restart is not a real flag, so when a change genuinely needs a device recreated, delete and recreate it with networkctl down and networkctl up. networkctl status with no argument prints every managed link, its state, its addresses and which file configured it - the last detail is what makes it more useful than ip addr when debugging. cat /proc/net/bonding/bond0 shows the bond's mode, the state of each member, and whether LACP negotiated successfully.

Troubleshooting Common networkd Problems

  • Interface shows unmanaged. networkd only manages interfaces with a matching .network file - check the [Match] name or MAC, and remember that an unmatched interface is left alone rather than configured with defaults.
  • Address is lost after reboot. A file names the interface but the interface is renamed later. Match on MACAddress= or Path= instead.
  • Bond members stay down. The switch is not running LACP, or the mode mismatch between bond-netdev and the switch port-channel means no member ever reaches up.
  • VLAN has no carrier. The parent's .network file is missing the VLAN= line, so networkd never created the child device.
  • Name conflict on bond0 or br0. The kernel module created the device first; set max_bonds=0 for bonding and remove any leftover br0 from another tool.
  • DNS stops working. systemd-resolved is not enabled, or /etc/resolv.conf still points at an old stub; re-link it to /run/systemd/resolve/stub-resolv.conf.

Validate files before applying them in production. An INI syntax error makes networkd ignore the whole file silently, which looks identical to a [Match] that never fires. networkctl status naming the config file that governs each link is the quickest way to tell the two apart.

Related articles

Next steps: nmcli guide: static IP with NetworkManager connections, systemd-resolved and resolvectl: DNS troubleshooting, Linux network bonding modes and LACP, and Linux VLAN tagging with ip link 8021q.

原文链接:https://linuxjunkies.org/guides/configure-systemd-networkd