1

Debian 11 by default appears configures the network using systemd and ifupdown. I'm interested in how systemd gets to network-online.target.

# systemctl show network-online.target | grep -E 'After|Wants'
Wants=networking.service
After=networking.service network.target [email protected]

I can see there's a dependency on networking.service, and the target is ordered after [email protected].

# systemctl show networking.service | grep ExecStart
ExecStart={ path=/sbin/ifup ; argv[]=/sbin/ifup -a --read-environment ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }
ExecStart={ path=/bin/sh ; argv[]=/bin/sh -c if [ -f /run/network/restart-hotplug ]; then /sbin/ifup -a --read-environment --allow=hotplug; fi ; ignore_errors=yes ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }
ExecStartEx={ path=/sbin/ifup ; argv[]=/sbin/ifup -a --read-environment ; flags= ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }
ExecStartEx={ path=/bin/sh ; argv[]=/bin/sh -c if [ -f /run/network/restart-hotplug ]; then /sbin/ifup -a --read-environment --allow=hotplug; fi ; flags=ignore-failure ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }

The dependency basically just runs ifup -a.

If I check out [email protected], I see that its an instantiated service:

# systemctl cat [email protected]
# /lib/systemd/system/[email protected]
[Unit]
Description=ifup for %I
After=local-fs.target network-pre.target apparmor.service systemd-sysctl.service
Before=network.target shutdown.target network-online.target
Conflicts=shutdown.target
BindsTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
DefaultDependencies=no
IgnoreOnIsolate=yes

[Service]
# avoid stopping on shutdown via stopping system-ifup.slice
Slice=system.slice
ExecStart=/bin/sh -ec 'ifup --allow=hotplug %I; ifquery --state %I'
ExecStop=/sbin/ifdown %I
RemainAfterExit=true
TimeoutStartSec=5min

and that it is ordered after, and bound to sys-subsystem-net-devices-ens192.device, but there's no actual file for this unit:

# systemctl show sys-subsystem-net-devices-ens192.device | grep ens192
SysFSPath=/sys/devices/pci0000:00/0000:00:16.0/0000:0b:00.0/net/ens192
Id=sys-subsystem-net-devices-ens192.device
Names=sys-subsystem-net-devices-ens192.device
[email protected]
[email protected]

# systemctl cat sys-subsystem-net-devices-ens192.device
No files found for sys-subsystem-net-devices-ens192.device.

I can see from man systemd.device that these get created automatically via udev, but there's no mention of how they get bound to or ordered around the instantiated service.

I'm left with these two questions I can't seem to find an answer to:

  1. Where is the file/configuration that tells systemd to use [email protected] for the BoundBy and Before in the device unit? 2.There is no ordering between networking.service and [email protected]; why do both exist, and why is it that the [email protected] is the one that ultimately runs dhclient, and not networking.service?

Thanks!

3 Answers 3

1

and that it is ordered after, and bound to sys-subsystem-net-devices-ens192.device, but there's no actual file for this unit:

.device units are virtual and represent udev state. Each device that is tagged with TAG+="systemd" by an udev rule causes a .device unit to show up – the .device unit becomes 'active' when udev rule processing is finished for that particular device.

.device units can have dependencies set by udev properties, e.g. ENV{SYSTEMD_WANTS}+="..." would add a Wants= dependency from the corresponding unit.

But also, even though .device units do not "exist", they can have dependencies set by .wants/ symlinks; e.g. it is possible to have sys-foo.device.wants/ (maybe in /run/systemd/generator) just like there is multi-user.target.wants/.

(For network interfaces specifically, the whole "/sys/subsystem" is an alias brought into existence by ENV{SYSTEMD_ALIAS} from an udev rule, too. There were plans to make /sys/subsystem exist in the kernel, but they didn't pass.)

I can see from man systemd.device that these get created automatically via udev, but there's no mention of how they get bound to or ordered around the instantiated service.

If the device has "BoundBy", that just means that the other unit has a BindsTo= for that device.

"BoundBy=", "WantedBy=", "RequiredBy=" are not real settings – they are never set explicitly, neither via udev nor otherwise; they only reflect the inbound dependencies, namely BindsTo=, Wants=, and Requires=.

You have something similar with Before= and After=. The device unit reports a "Before=ifup@" because ifup@ has "After=device"; the Before= is not set explicitly.

There is no ordering between networking.service and [email protected]; why do both exist

networking.service exists because people are used to having /etc/init.d/networking from older Debian versions – ifupdown includes it so that people can just "restart networking".

and why is it that the [email protected] is the one that ultimately runs dhclient, and not networking.service

One .service can only monitor one "main" process. Since ifupdown has no central overseer process but only a bunch of independent dhclient instances, each of them needs to be its own .service. (Keeping them separate also helps with hardware dependencies, because the interfaces don't all show up at the same time – you could perfectly well have some that are available on boot and some that are connected later.)

2
  • Thanks! Any suggestions about where to learn more about udev? How do I see the udev tags?
    – Kayson
    Commented Jul 15, 2023 at 19:47
  • 1
    udevadm info /sys/class/net/eth0 would show the current properties and tags (but if there's a .device unit you can literally assume it has a systemd tag). Note that udevadm only takes "real" /dev or /sys paths; it won't recognize the systemd-specific /sys/subsystem/net alias. Commented Jul 15, 2023 at 19:53
2

Where is the file/configuration that tells systemd to use [email protected]?

It seems like your /etc/network/interfaces file configures ens192 using allow-hotplug as opposed to auto. Debian has udev rules (look for ifupdown.rules in /lib/udev/rules.d) that cause it to run /lib/udev/ifupdown-hotplug , which starts ifup@ens192 . In the ifupdown-hotplug script, look for

        exec systemctl --no-block start $(systemd-escape --template [email protected] $TARGET_IFACE)

There is no ordering between networking.service and [email protected]; why do both exist, and why is it that the [email protected] is the one that ultimately runs dhclient, and not networking.service

I'm not an expert, but from taking a cursory look at the code my understanding is that [email protected] sets up interfaces configured with "allow-hotplug", whereas networking.service sets up interfaces configured with "auto". Try switching ens192 from allow-hotplug to auto in /etc/network/interfaces and check which service starts dhclient to confirm.

1
  • +1 because it really answers the question of what creates the ifup@... service instance in the first place. I was trying to disable ifupdown in favor of systemd-networkd, and I noticed that even with networking.service disabled, dhclient was still started by this ifup@... service instance, and like OP, after analyzing services dependencies with various systemd tools for hours, I couldn't find why. This answer really and perfectly explains how and where the instance is created. It really should be the accepted answer.
    – MoonSweep
    Commented Jan 16 at 0:59
0

Regarding your question

why is it that the /lib/systemd/system/[email protected] is the one that ultimately runs dhclient, and not networking.service?

TL;DR: IMHO, this is because of Debian 11 installing the dhclient executable by default; /lib/systemd/system/[email protected] executes ifup. If ifup has to do DHCP-related stuff, and dhclient is installed, ifup will prefer using dhclient over any other possibly available "dhcp tool".

Explanation

/lib/systemd/system/[email protected] looks like this on my Debian 11 bullseye system:

[Unit]
Description=ifup for %I
After=local-fs.target network-pre.target apparmor.service systemd-sysctl.service
Before=network.target shutdown.target network-online.target
Conflicts=shutdown.target
BindsTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
DefaultDependencies=no
IgnoreOnIsolate=yes

[Service]
# avoid stopping on shutdown via stopping system-ifup.slice
Slice=system.slice
ExecStart=/bin/sh -ec 'ifup --allow=hotplug %I; ifquery --state %I'
ExecStop=/sbin/ifdown %I
RemainAfterExit=true
TimeoutStartSec=5min

So ExecStart=... executes the ifup command.

man 8 ifup says the following:

The ifup and ifdown commands may be used to configure (or, respectively, deconfigure) network interfaces based on interface definitions in the file /etc/network/interfaces.

On my system, /etc/network/interfaces includes the following:

# ...

source /etc/network/interfaces.d/*

# ...

# The primary network interface
allow-hotplug enp0s3
iface enp0s3 inet dhcp

# ...

Regarding the ... dhcp in iface enp0s3 inet dhcp, man 5 interfaces provides this information:

[The dhcp] method may be used to obtain an address via DHCP with any of the tools: dhclient, pump, udhcpc, dhcpcd. (They have been listed in their order of precedence.) If you have a complicated DHCP setup you should note that some of these clients use their own configuration files and do not obtain their configuration information via ifup.

To my observation, when I install Debian 11 using the debian-11.6.0-amd64-netinst.iso bootable ISO image installer, the pristine installation already includes /sbin/dhclient (and due to /sbin being a symlink to /usr/sbin/, it's actually located at /usr/sbin/dhclient).

Using

for pid in $(pidof dhclient); do ps -fp $pid; pstree -lapstc $pid; echo; done

I can see /sbin/dhclient being spawned by systemd (in my case because of two interfaces, there are two running dhclient processes, hence the for-loop to show detailed information for each).

dpkg -S /sbin/dhclient shows that /sbin/dhclient is provided by apt package isc-dhcp-client, which was installed during the initial Debian installation.

1
  • Thanks! Still curious about the udev stuff...
    – Kayson
    Commented Jul 13, 2023 at 18:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .