#1098708 ifupdown: systemd kills child processes (pppd/hostapd) if ifup -a in networking.service returns failure code

Package:
ifupdown
Source:
ifupdown
Description:
high level tools to configure network interfaces
Submitter:
Frank Bormann
Date:
2025-02-23 10:00:01 UTC
Severity:
normal
Tags:
#1098708#5
Date:
2025-02-23 03:07:12 UTC
From:
To:
Dear Maintainer,

For an advanced home router setup, I have ifupdown configure over a dozen network interfaces at startup. These include the home network's main VSDL2 Internet connection, using the ppp method which has ifupdown spawn a pppd process for pppoe in the background, as well as multiple WiFi access points, using the hostapd option that the hostapd package installs as an ifupdown plugin which spawns hostapd processes in the background.

I am facing the issue that I make any mistakes in the network configuration, even if it is in interface stanzas completely unrelated to the ppp or wlan ap interfaces, and the call from networking.service to ifup -a --read-environment returns an error code, ifup will still have brought both the pppoe as well as the wlan ap interfaces up, however systemd now considers networking.service failed and therefore stopped and terminates any processes spawned by ifup for other network interfaces that were successfully configured, such as pppd and hostapd processes. As we result, the Internet connection and WiFi access points, that were initially brought up correctly, are being terminated again. Also, this produces a system inconsistency as ifupdown still considers these interface up and running as it is not aware of systemd having killed the supporting pppd and hostapd processes.

If you look at networking.service, it says in the [Service] section:

ExecStart=/sbin/ifup -a --read-environment
ExecStart=-/bin/sh -c 'if [ -f /run/network/restart-hotplug ]; then /sbin/ifup -a --read-environment --allow=hotplug; fi'

As you can see, it is designed to not tolerate errors bringing up interfaces classified as "auto", but it does tolerate errors for interfaces classified as "hotplug", as the minus prefix in the 2nd ExecStart line tells systemd to ignore failure return codes in the call to ifup for hotplug devices. I am wondering, why the difference in behaviour for "auto" and "hotplug" interfaces. As if I change the above to

ExecStart=-/sbin/ifup -a --read-environment
ExecStart=-/bin/sh -c 'if [ -f /run/network/restart-hotplug ]; then /sbin/ifup -a --read-environment --allow=hotplug; fi'

I am getting the desired behaviour (for me) of systemd no longer killing pppd and hostapd processes as the service is still considered running even if ifup fails to bring up any of the other network interface not related to Internet connection and WiFi access points. Should this be change for the next release of ifupdown?
--- /etc/network/interfaces.d/*:
auto wan0 wan0.40
iface wan0 inet manual
	mtu 1508
iface wan0.40 inet manual
	mtu 1508

auto provider
iface provider inet ppp
	unit 0
	provider provider

auto wlan0
iface wlan0 inet manual
	hostapd /etc/hostapd/wlan0.conf

auto wlan1
iface wlan1 inet manual
	hostapd /etc/hostapd/wlan1.conf

auto wlan2
iface wlan2 inet manual
	hostapd /etc/hostapd/wlan2.conf

auto eth1
iface eth1 inet static
	address 192.168.178.1/25
	bridge-ports eth0 wlan1
	bridge_hw eth0
	bridge_stp off
	bridge_maxwait 0
	bridge_fd 0
	post-up iptables -t nat -w -I POSTROUTING 1 -s 192.168.178.0/25 -o ppp0 -j MASQUERADE
	pre-down iptables -t nat -w -D POSTROUTING -s 192.168.178.0/25 -o ppp0 -j MASQUERADE

# introduce deliberate error
auto eth2
iface eth2 inet static
	address 192.168.179.1/25
	bridge-ports eth0.2
	bridge_hw eth0
	bridge_stp off
	bridge_maxwait 0
	bridge_fd 0
	post-up false
--- up and down scripts installed: /etc/network/if-down.d: total 8 lrwxrwxrwx 1 root root 29 Jan 25 2023 bridge -> /lib/bridge-utils/ifupdown.sh -rwxr-xr-x 1 root root 372 Jan 25 2023 openvpn -rwxr-xr-x 1 root root 759 Dec 9 2022 resolved lrwxrwxrwx 1 root root 32 Aug 5 2024 wpasupplicant -> ../../wpa_supplicant/ifupdown.sh /etc/network/if-post-down.d: total 4 lrwxrwxrwx 1 root root 29 Jan 25 2023 bridge -> /lib/bridge-utils/ifupdown.sh lrwxrwxrwx 1 root root 25 Aug 5 2024 hostapd -> ../../hostapd/ifupdown.sh -rwxr-xr-x 1 root root 1409 Mar 7 2020 wireless-tools lrwxrwxrwx 1 root root 32 Aug 5 2024 wpasupplicant -> ../../wpa_supplicant/ifupdown.sh /etc/network/if-pre-up.d: total 12 lrwxrwxrwx 1 root root 29 Jan 25 2023 bridge -> /lib/bridge-utils/ifupdown.sh -rwxr-xr-x 1 root root 344 Dec 20 2022 ethtool lrwxrwxrwx 1 root root 25 Aug 5 2024 hostapd -> ../../hostapd/ifupdown.sh -rwxr-xr-x 1 root root 4191 Mar 7 2020 wireless-tools lrwxrwxrwx 1 root root 32 Aug 5 2024 wpasupplicant -> ../../wpa_supplicant/ifupdown.sh /etc/network/if-up.d: total 16 -rwxr-xr-x 1 root root 1685 Dec 20 2022 ethtool -rwxr-xr-x 1 root root 385 Jan 25 2023 openvpn -rwxr-xr-x 1 root root 4663 Dec 9 2022 resolved lrwxrwxrwx 1 root root 32 Aug 5 2024 wpasupplicant -> ../../wpa_supplicant/ifupdown.sh
#1098708#10
Date:
2025-02-23 09:56:42 UTC
From:
To:
Hi Frank,

Thanks for the insightful report.
individual services instead of spawning long-running processes directly.

I can see two ways to satisfy systemd's lust for control:

 1) Arrange for networking.service to start individual ifup@$IFACE services
    using systemd-run(1) instead of bringing everything up in one go. This
    would contain systemd's blast radius to one iface.

 2) Change ifupdown scripts of things like ppp/hostapd to use systemd-run.

The former seems preferable since it's a change that's contained to
ifupdown and doesn't need us to bring other maintainers on board with this.

One caveat to the whole thing: I belive ifupdown is used outside of a
systemd context aswell so we'd have to figure out how to detect if systemd
is in use and forgoe the systemd-run wrapper in that case. Is that
something you could look into?

While I can't think of a truly really good reason networking.service should
ever have to inidcate a failure under normal circumstances I'm not
comfortable doing this. Think of the case where /etc/network/interfaces
simply has a syntax error. Shouldn't it be able to indicate failure then?

We could ofc. cover that case by adding an ExecCondition to check the
syntax, but unexpected failures (crashes and whatnot) do happen and hiding
them is bad.