Skip to content

systemd-networkd network setup

Arch Linux networking

When starting my Arch Linux system setup, I was surprised at just how minimal the initial installation is. Networking is not set up in any way on a freshly installed system.

Of course, that's a bit of a problem if you don't know what you're doing (as was the case for me), and you need to have Internet access to be able to install a network manager.

Luckily Arch Linux has good documentation on how to get your network going, at least with a fixed IP, so you can get online to get the DHCP client and network manager you think you want or need.

NetworkManager and dhcpd

Coming from a legacy background, I knew nothing better than to install NetworkManager and dhcpd. This works, nothing wrong with it. I got it all configured fine, but since my hardware has four Ethernet ports, I still wanted to set it up so it could work as a network switch on the other ports.

So I did more research and found out that I don't need extra programs at all to handle any of this. systemd can take care of all of this stuff on its own!

systemd-networkd

Some people don't like systemd. I have never understood why exactly, since I've always found it to be superior in implementation, ease-of-use and configuration compared to the legacy solutions it attempts to replace.

From the point of view of embedded systems design, it is awesome to have a single tool that integrates all kinds of functionality versus needing a different program for everything.

It turns out I didn't need to get Internet access to install a network manager after all, a perfectly good network manager was already present on the freshly installed system in the form of systemd. So I uninstalled NetworkManager and dhcpd. All that was needed to get online was add a single file /etc/systemd/network/20-wired.network with the following contents:

[Match]
Name=enp2s0

[Network]
DHCP=yes

And then enable and start systemd-networkd:

# systemctl enable systemd-networkd
# systemctl start systemd-networkd

systemd-resolved

I also used another systemd service to handle DNS lookups. I wanted to have mDNS enabled so I could get easy access to the machine using [hostname].local.

This is the config I ended up with in /etc/systemd/resolved.conf:

[Resolve]
DNS=1.1.1.1
MulticastDNS=yes
DNSStubListener=no

It uses 1.1.1.1 as the default DNS lookup. MulticastDNS=yes turns on mDNS. DNSStubListener=no turned out to be important when I was trying to set up Pi-hole. Since Pi-hole will be our network's DNS server, this setting needs to be set to no so systemd-resolved doesn't start a DNS listener on port 53. Otherwise Pi-hole would complain that port 53 was alread in use.

And then enable and start systemd-resolved:

# systemctl enable systemd-resolved
# systemctl start systemd-resolved

Final config with network bridge

Now I had basic networking, it was time to figure out how to change my config so I could use the extra Ethernet ports to connect other devices to the network (use the PC as a network switch). As is often the case, the most difficult part of that was to figure out the correct search terms to use. I found numerous articles about how to set up a Linux system to be a router, but I did not want address translation. I wanted the devices connected to the PC to be on the same network as everything else.

Turns out the correct term for that is bridge. Once I figured that out I made progress with guides that just use the ip command. I needed to translate these to a working systemd-networkd configuration. Below is what I eventually ended up with (after removing the old config file).

First make a bridge device with the file /etc/systemd/network/10-br0.netdev, containing:

[NetDev]
Name=br0
Kind=bridge

Then set the network connection info on the bridge device. This was an important thing to figure out, things kept not working when I was trying to set up my uplink information on a physical network device! In this case I wanted a fixed IP address instead of DHCP and ended up with this file /etc/systemd/network/20-br0.network:

[Match]
Name=br0

[Network]
Address=192.168.1.201/24
Gateway=192.168.1.1
MulticastDNS=true
IPForward=true

[Link]
Multicast=true
AllMulticast=true
Promiscuous=true

Then I needed to add a third file /etc/systemd/network/30-bind.network to connect all physical Ethernet ports to the bridge:

[Match]
Name=enp*

[Network]
Bridge=br0

With this config, everything works as expected. The PC connects to my network, it doesn't even matter which port I use for the uplink. And any devices connected to the remaining Ethernet ports also connect to my network.