Joachim Breitner

Switching to systemd-networkd

Published 2014-10-14 in sections English, Debian.

Ever since I read about systemd-networkd being in the making I was looking forward to try it out. I kept watching for the package to appear in Debian, or at least ITP bugs. A few days ago, by accident, I noticed that I already have systemd-networkd on my machine: It is simply shipped with the systemd package!

My previous setup was a combination of ifplugd to detect when I plug or unplug the ethernet cable with a plain DHCP entry in /etc/network/interface. A while ago I was using guessnet to do a static setup depending on where I am, but I don’t need this flexibility any more, so the very simple approach with systemd-networkd is just fine with me. So after stopping ifplugd and

$ cat > /etc/systemd/network/eth.network <<__END__
[Match]
Name=eth0
[Network]
DHCP=yes
__END__
$ systemctl enable systemd-networkd
$ systemctl start systemd-networkd

I was ready to go. Indeed, systemd-networkd, probably due to the integrated dhcp client, felt quite a bit faster than the old setup. And what’s more important (and my main motivation for the switch): It did the right thing when I put it to sleep in my office, unplug it there, go home, plug it in and wake it up. ifplugd failed to detect this change and I often had to manually run ifdown eth0 && ifup eth0; this now works.

But then I was bitten by what I guess some people call the viral nature of systemd: systemd-networkd would not update /etc/resolv.conf, but rather relies on systemd-resolved. And that requires me to change /etc/resolv.conf to be a symlink to /run/systemd/resolve/resolv.conf. But of course I also use my wireless adapter, which, at that point, was still managed using ifupdown, which would use dhclient which updates /etc/resolv.conf directly.

So I investigated if I can use systemd-networkd also for my wireless account. I am not using NetworkManager or the like, but rather keep wpa_supplicant running in roaming mode, controlled from ifupdown (not sure how that exactly works and what controls what, but it worked). I found out that this setup works just fine with systemd-networkd: I start wpa_supplicant with this service file (which I found in the wpa_supplicant repo, but not yet in the Debian package)(which comes with the Debian package since version 2.5-1):

[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
Type=simple
ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I

[Install]
Alias=multi-user.target.wants/wpa_supplicant@%i.service

After enabling this with systemctl enable wpa_supplicant@wlan0.service, systemd starts wpa_supplicant and wpa_supplicant will get the interface up and down as it goes, while systemd-networkd, equipped with

[Match]
Name=wlan0
[Network]
DHCP=yes

does the rest.

So suddenly I have a system without /etc/init.d/networking and without ifup. Feels a bit strange, but also makes sense. I still need to migrate how I manage my UMTS modem device to that model.

The only thing that I’m missing so far is a way to trigger actions when the network configuration has changes, like I could with /etc/network/if-up.d/ etc. I want to run things like killall -ALRM tincd and exim -qf. If you know how to do that, please tell me, or answer over at Stack Exchange.

Comments

The fact that hooks are missing from this design is scary and it spells the end of system administration as we know it. I have also been trying to find ways to do stuff on my system e.g. when I press certain keys or close the lid, and unless systemd provides the behaviour you want, you are out of luck.

And it confirms my theory: systemd sends Unix down the line of Windows: we know the best way to do things, and you don't need any hooks.

#1 martin f krafft am 2014-10-15

It looks like networkd has no support for hooks. However, the systemd-networkd code contains some interesting comments:

   /* Always create the directories people can create inotify
     * watches in. */
    r = mkdir_safe_label("/run/systemd/netif", 0755, uid, gid);
    if (r < 0)
            log_error("Could not create runtime directory: %s",
                      strerror(-r));

    r = mkdir_safe_label("/run/systemd/netif/links", 0755, uid, gid);
    if (r < 0)
            log_error("Could not create runtime directory 'links': %s",
                      strerror(-r));

    r = mkdir_safe_label("/run/systemd/netif/leases", 0755, uid, gid);
    if (r < 0)
            log_error("Could not create runtime directory 'leases': %s",
                      strerror(-r));

In particular, there is /run/systemd/netif/state, which contains something like:

# This is private data. Do not parse.
 OPER_STATE=routable

Now, you can always ignore the warning about parsing and add a small hack by setting up an inotify watch (or a path-activated unit) and trigger actions whenever your network transitions to routable.

#2 Apollon Oikonomopoulos am 2014-10-18

The intention is to expose the network state per link via the files in /run that you found. However, the official API will be a C library (sd-network), rather than the files themselves (which allows us some liberty in changing the implementation later on).

The library has not been exposed yet (still need to go through another round of review I think), but you can find the headers in src/systemd/sd-network.h if you want to have a look. It exposes change events (internally over inotify) and introspection of the files.

#3 Tom Gundersen am 2014-10-19

This is a very late comment, but /etc/resolv.conf was constantly misspelled in the blog post. But I guess that wasn't part of the problem?

#4 Jens Stimpfle am 2015-01-26

No, I do not think it was. But thanks for the notice, I fixed the blog post :-)

#5 Joachim Breitner am 2015-01-26

You can use your modem in combination with systemd-networkd like that:

# First, mask NetworkManager (if not done already)
systemctl mask NetworkManager

# Unmask, enable and start ModemManager
systemctl unmask ModemManager
systemctl enable ModemManager
systemctl start ModemManager

# Add a .network file for your modem network interface:
cat /etc/systemd/network/wwp0s20u6c2i12.network:

[Match]
Name=wwp0s20u6c2i12
[Network]
DHCP=both

# restart systemd-networkd:
systemctl restart systemd-networkd


# Scripts to enable and disable the modem and the corresponding network
# interface:

cat /usr/local/bin/modem-connect:

#!/bin/sh
mmcli -m 0 --simple-connect="apn=APN_HERE"
# also enter ,pin= if needed
ifconfig wwp0s20u6c2i12 up


cat /usr/local/bin/modem-disconnect:

#!/bin/sh
ifconfig wwp0s20u6c2i12 down
mmcli -m 0 --simple-disconnect

It would also make sense to adjust the RouteMetric parameter in the [DHCP] section of the .network file so that the modem connection is not used when other default routes are present. However, this didn't work for me yet.

#6 Florian Klink am 2015-02-10

I was following that blog and discovered that wpa_supplicant service file is now present in Debian wpa_supplicant package (wpa_supplicant@.service). Maybe worth mentioning in the blog.

#7 Eugene Zhukov am 2016-08-12

Have something to say? You can post a comment by sending an e-Mail to me at <mail@joachim-breitner.de>, and I will include it here.