[arch-projects] [netcfg] Rethink systemd integration
Our current systemd units have a fatal flaw: They may fail because they are started before the needed devices show up. This patch series adds new units that fix that. However, the change is not transparent for the user and requires different configuration. I'd really like to deprecate netcfg.service, netcfg@.service and net-auto-wireless.service at some point, but that will break existing setups. I don't know if we should go ahead with this. Anyway, please comment on the patches.
This shouldn't be here, net-auto-wireless always has a process running. --- systemd/net-auto-wireless.service | 1 - 1 file changed, 1 deletion(-) diff --git a/systemd/net-auto-wireless.service b/systemd/net-auto-wireless.service index ab57ab9..a717070 100644 --- a/systemd/net-auto-wireless.service +++ b/systemd/net-auto-wireless.service @@ -7,7 +7,6 @@ Wants=network.target EnvironmentFile=/etc/conf.d/netcfg ExecStart=/usr/bin/netcfg-wpa_actiond $WIRELESS_INTERFACE ExecStop=/usr/bin/netcfg-wpa_actiond stop $WIRELESS_INTERFACE -RemainAfterExit=yes Type=forking [Install] -- 1.8.0
On Thu, Oct 25, 2012 at 12:27 AM, Thomas Bächler <thomas@archlinux.org> wrote:
This shouldn't be here, net-auto-wireless always has a process running.
Ack. -t
This has the advantage that we can (since systemd 195) have a proper dependency on the wireless device. --- systemd/net-auto-wireless@.service | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 systemd/net-auto-wireless@.service diff --git a/systemd/net-auto-wireless@.service b/systemd/net-auto-wireless@.service new file mode 100644 index 0000000..29a0efb --- /dev/null +++ b/systemd/net-auto-wireless@.service @@ -0,0 +1,14 @@ +[Unit] +Description=Provides automatic netcfg wireless connection +Before=network.target +Wants=network.target +BindsTo=sys-subsystem-net-devices-%i.device +After=sys-subsystem-net-devices-%i.device + +[Service] +ExecStart=/usr/bin/netcfg-wpa_actiond %i +ExecStop=/usr/bin/netcfg-wpa_actiond stop %i +Type=forking + +[Install] +WantedBy=multi-user.target -- 1.8.0
On Thu, Oct 25, 2012 at 12:27 AM, Thomas Bächler <thomas@archlinux.org> wrote:
This has the advantage that we can (since systemd 195) have a proper dependency on the wireless device.
Ack. -t
Until now, netcfg might fail to start because it is started too early (this actually happened to me quite regularly). To fix this, we need to make systemd aware of the dependencies of a profile. This commit adds a systemd generator that creates profiles with the names netcfg-profile-$PROFILE.service on boot. The ugly part: You cannot permanently enable such a profile, as it is generated during boot. To enable it, put it in NETWORKS=() in /etc/conf.d/netcfg and run systemctl enable netcfg-profiles.target If you add a new profile, you need to reload the systemd configuration so the service file shows up. While this scheme is less intuitive than netcfg@profilename.service, it is the only way to provide proper dependencies during boot. Due to a bug in systemd's dependency resolution with devices, this patch requires systemd v195 to work. --- Makefile | 2 ++ systemd/netcfg-generator | 58 ++++++++++++++++++++++++++++++++++++++++++ systemd/netcfg-profiles.target | 5 ++++ 3 files changed, 65 insertions(+) create mode 100755 systemd/netcfg-generator create mode 100644 systemd/netcfg-profiles.target diff --git a/Makefile b/Makefile index bbada3f..3a80c41 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,9 @@ install: install-docs install -d $(DESTDIR)/usr/lib/systemd/system install -m644 \ systemd/*.service \ + systemd/*.target \ $(DESTDIR)/usr/lib/systemd/system/ + install -Dm755 systemd/netcfg-generator /usr/lib/systemd/system-generators/netcfg-generator install-docs: docs install -d $(DESTDIR)/usr/share/man/{man5,man8} diff --git a/systemd/netcfg-generator b/systemd/netcfg-generator new file mode 100755 index 0000000..983dceb --- /dev/null +++ b/systemd/netcfg-generator @@ -0,0 +1,58 @@ +#!/bin/bash + +[[ -d $1 ]] || exit 1 + +. /usr/lib/network/network + +profile_tmpl_unit="[Unit] +Description=Netcfg networking service for profile @PROFILE@ +SourcePath=/etc/network.d/@PROFILE@ +Before=network.target +Wants=network.target" + +profile_tmpl_service="[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/netcfg check-iface @PROFILE@ +ExecStop=-/usr/bin/netcfg down @PROFILE@ +KillMode=none" + +for pf in /etc/network.d/*; do + [[ -f ${pf} && -r ${pf} ]] || continue + p=${pf#/etc/network.d/} + load_profile ${p} + systemd_devices= + case ${CONNECTION} in + bond) + for iface in ${SLAVE_INTERFACES[@]}; do + systemd_devices="${systemd_devices}sys-subsystem-net-devices-${iface}.device " + done + ;; + bridge) + for iface in ${BRIDGE_INTERFACES[@]}; do + systemd_devices="${systemd_devices}sys-subsystem-net-devices-${iface}.device " + done + ;; + ethernet|pppoe|wireless) + systemd_devices="sys-subsystem-net-devices-${INTERFACE}.device" + ;; + vlan) + systemd_devices="sys-subsystem-net-devices-${VLAN_PHYS_DEV}.device" + ;; + esac + systemd_devices=${systemd_devices% } + if [[ ${systemd_devices} ]]; then + bindsto="BindsTo=${systemd_devices}" + after="After=${systemd_devices}" + else + bindsto= + after= + fi + echo -e "${profile_tmpl_unit//@PROFILE@/$p}\n${bindsto}\n${after}\n\n${profile_tmpl_service//@PROFILE@/$p}" > $1/netcfg-profile-$p.service +done + +. /etc/conf.d/netcfg +mkdir $1/netcfg-profiles.target.wants +for network in "${NETWORKS[@]}"; do + ln -s $1/netcfg-profile-$p.service $1/netcfg-profiles.target.wants/netcfg-profile-$p.service +done diff --git a/systemd/netcfg-profiles.target b/systemd/netcfg-profiles.target new file mode 100644 index 0000000..ba310fa --- /dev/null +++ b/systemd/netcfg-profiles.target @@ -0,0 +1,5 @@ +[Unit] +Description=Netcfg network profiles + +[Install] +WantedBy=multi-user.target -- 1.8.0
On Thu, Oct 25, 2012 at 12:27:41AM +0200, Thomas Bächler wrote:
Until now, netcfg might fail to start because it is started too early (this actually happened to me quite regularly). To fix this, we need to make systemd aware of the dependencies of a profile.
This commit adds a systemd generator that creates profiles with the names netcfg-profile-$PROFILE.service on boot. The ugly part: You cannot permanently enable such a profile, as it is generated during boot. To enable it, put it in NETWORKS=() in /etc/conf.d/netcfg and run systemctl enable netcfg-profiles.target If you add a new profile, you need to reload the systemd configuration so the service file shows up.
While this scheme is less intuitive than netcfg@profilename.service, it is the only way to provide proper dependencies during boot.
Due to a bug in systemd's dependency resolution with devices, this patch requires systemd v195 to work. --- Makefile | 2 ++ systemd/netcfg-generator | 58 ++++++++++++++++++++++++++++++++++++++++++ systemd/netcfg-profiles.target | 5 ++++ 3 files changed, 65 insertions(+) create mode 100755 systemd/netcfg-generator create mode 100644 systemd/netcfg-profiles.target
diff --git a/Makefile b/Makefile index bbada3f..3a80c41 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,9 @@ install: install-docs install -d $(DESTDIR)/usr/lib/systemd/system install -m644 \ systemd/*.service \ + systemd/*.target \ $(DESTDIR)/usr/lib/systemd/system/ + install -Dm755 systemd/netcfg-generator /usr/lib/systemd/system-generators/netcfg-generator
install-docs: docs install -d $(DESTDIR)/usr/share/man/{man5,man8} diff --git a/systemd/netcfg-generator b/systemd/netcfg-generator new file mode 100755 index 0000000..983dceb --- /dev/null +++ b/systemd/netcfg-generator @@ -0,0 +1,58 @@ +#!/bin/bash + +[[ -d $1 ]] || exit 1 + +. /usr/lib/network/network + +profile_tmpl_unit="[Unit] +Description=Netcfg networking service for profile @PROFILE@ +SourcePath=/etc/network.d/@PROFILE@ +Before=network.target +Wants=network.target" + +profile_tmpl_service="[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/netcfg check-iface @PROFILE@ +ExecStop=-/usr/bin/netcfg down @PROFILE@ +KillMode=none" + +for pf in /etc/network.d/*; do + [[ -f ${pf} && -r ${pf} ]] || continue + p=${pf#/etc/network.d/}
I think you just want to use p=${pf##*/}.
+ load_profile ${p} + systemd_devices= + case ${CONNECTION} in + bond) + for iface in ${SLAVE_INTERFACES[@]}; do + systemd_devices="${systemd_devices}sys-subsystem-net-devices-${iface}.device "
Please use arrays for this... systemd_devices+=(....)
+ done + ;; + bridge) + for iface in ${BRIDGE_INTERFACES[@]}; do + systemd_devices="${systemd_devices}sys-subsystem-net-devices-${iface}.device " + done + ;; + ethernet|pppoe|wireless) + systemd_devices="sys-subsystem-net-devices-${INTERFACE}.device" + ;; + vlan) + systemd_devices="sys-subsystem-net-devices-${VLAN_PHYS_DEV}.device" + ;; + esac + systemd_devices=${systemd_devices% } + if [[ ${systemd_devices} ]]; then + bindsto="BindsTo=${systemd_devices}" + after="After=${systemd_devices}"
Array here too... extra_deps+=("BindsTo=${systemd_devices[*]}" "After=${systemd_devices[*]}")
+ else + bindsto= + after= + fi + echo -e "${profile_tmpl_unit//@PROFILE@/$p}\n${bindsto}\n${after}\n\n${profile_tmpl_service//@PROFILE@/$p}" > $1/netcfg-profile-$p.service
This is dirty (and pretty much unreadable). I suggest using a function along the lines of: write_template() { local profile=$1; shift cat <<EOF [Unit] Description=Netcfg profile for $profile SourcePath=/etc/network.d/$profile Before=network.target Wants=network.target EOF (( $# )) && printf '%s\n' "$@" '' cat <<EOF [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/netcfg check-iface $profile ExecStop=-/usr/bin/netcfg down $profile KillMode=none EOF } And then you can just do something like: write_template "$1" "${extra_deps[@]}" >"$1/netcfg-profile-$p.service"
+done + +. /etc/conf.d/netcfg +mkdir $1/netcfg-profiles.target.wants +for network in "${NETWORKS[@]}"; do + ln -s $1/netcfg-profile-$p.service $1/netcfg-profiles.target.wants/netcfg-profile-$p.service +done diff --git a/systemd/netcfg-profiles.target b/systemd/netcfg-profiles.target new file mode 100644 index 0000000..ba310fa --- /dev/null +++ b/systemd/netcfg-profiles.target @@ -0,0 +1,5 @@ +[Unit] +Description=Netcfg network profiles + +[Install] +WantedBy=multi-user.target -- 1.8.0
On Thu, Oct 25, 2012 at 12:27 AM, Thomas Bächler <thomas@archlinux.org> wrote:
Until now, netcfg might fail to start because it is started too early (this actually happened to me quite regularly). To fix this, we need to make systemd aware of the dependencies of a profile.
(Note: I know nothing about netcfg) Is there no way to teach netcfg to just wait for the devices to become available, so that there is no "too early"? This is how other network management daemons work...
This commit adds a systemd generator that creates profiles with the names netcfg-profile-$PROFILE.service on boot. The ugly part: You cannot permanently enable such a profile, as it is generated during boot. To enable it, put it in NETWORKS=() in /etc/conf.d/netcfg and run systemctl enable netcfg-profiles.target
Hmm... Not a big fan of having two levels of "on/off". Any reason not to do this like the other standard generators (for fstab and crypttab)? I.e., to make netcfg-profiles.target statically enabled, so that NETWORK=() is the one and only place to enable profiles?
If you add a new profile, you need to reload the systemd configuration so the service file shows up.
While this scheme is less intuitive than netcfg@profilename.service, it is the only way to provide proper dependencies during boot.
Makes sense to me, just make clear it is similar to how fstab/crypttab works, and there should be no room for confusion. -t
Am 25.10.2012 01:02, schrieb Tom Gundersen:
On Thu, Oct 25, 2012 at 12:27 AM, Thomas Bächler <thomas@archlinux.org> wrote:
Until now, netcfg might fail to start because it is started too early (this actually happened to me quite regularly). To fix this, we need to make systemd aware of the dependencies of a profile.
(Note: I know nothing about netcfg)
Is there no way to teach netcfg to just wait for the devices to become available, so that there is no "too early"? This is how other network management daemons work...
netcfg is simply a set of bash scripts. I actually don't want to reimplement something in bash that systemd can already do (including some timeout logic, proper display in systemctl status, ...)
This commit adds a systemd generator that creates profiles with the names netcfg-profile-$PROFILE.service on boot. The ugly part: You cannot permanently enable such a profile, as it is generated during boot. To enable it, put it in NETWORKS=() in /etc/conf.d/netcfg and run systemctl enable netcfg-profiles.target
Hmm... Not a big fan of having two levels of "on/off". Any reason not to do this like the other standard generators (for fstab and crypttab)? I.e., to make netcfg-profiles.target statically enabled, so that NETWORK=() is the one and only place to enable profiles?
This might actually be a good idea - we remove netcfg.service when we merge this, and everything will just keep working without reconfiguration, just ... better. However, this may cause problems with legacy configurations where people used rc.d/net-profiles before and then switched to netcfg@.service. The networks will still be listed in NETWORKS=(), but netcfg.service is not enabled, so this was ignored. Using this in combination with netcfg@.service will enable the profiles twice.
If you add a new profile, you need to reload the systemd configuration so the service file shows up.
While this scheme is less intuitive than netcfg@profilename.service, it is the only way to provide proper dependencies during boot.
Makes sense to me, just make clear it is similar to how fstab/crypttab works, and there should be no room for confusion.
It is.
On Thu, Oct 25, 2012 at 1:14 AM, Thomas Bächler <thomas@archlinux.org> wrote:
However, this may cause problems with legacy configurations where people used rc.d/net-profiles before and then switched to netcfg@.service. The networks will still be listed in NETWORKS=(), but netcfg.service is not enabled, so this was ignored. Using this in combination with netcfg@.service will enable the profiles twice.
Hm, so what we'd ideally have is that netcfg@.service goes away and that netcfg@$PROFILE.service is a symlink to netcfg-profile-$PROFILE.service? Don't know what's the most elegant way to achieve that... -t
Am 25.10.2012 01:32, schrieb Tom Gundersen:
On Thu, Oct 25, 2012 at 1:14 AM, Thomas Bächler <thomas@archlinux.org> wrote:
However, this may cause problems with legacy configurations where people used rc.d/net-profiles before and then switched to netcfg@.service. The networks will still be listed in NETWORKS=(), but netcfg.service is not enabled, so this was ignored. Using this in combination with netcfg@.service will enable the profiles twice.
Hm, so what we'd ideally have is that netcfg@.service goes away and that netcfg@$PROFILE.service is a symlink to netcfg-profile-$PROFILE.service?
Don't know what's the most elegant way to achieve that...
Conflicts=netcfg@PROFILE.service in the generated service file to fix the conflicts. Then a deprecation warning, and later the removal of netcfg@.service.
These descriptions are shown in "Starting" and "Started" notifications. --- systemd/net-auto-wired.service | 2 +- systemd/net-auto-wireless.service | 2 +- systemd/net-auto-wireless@.service | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/systemd/net-auto-wired.service b/systemd/net-auto-wired.service index 7bb885d..3aaa23d 100644 --- a/systemd/net-auto-wired.service +++ b/systemd/net-auto-wired.service @@ -1,5 +1,5 @@ [Unit] -Description=Provides automatic netcfg wired connection +Description=Automatic wired connection [Service] EnvironmentFile=/etc/conf.d/netcfg diff --git a/systemd/net-auto-wireless.service b/systemd/net-auto-wireless.service index a717070..365f18c 100644 --- a/systemd/net-auto-wireless.service +++ b/systemd/net-auto-wireless.service @@ -1,5 +1,5 @@ [Unit] -Description=Provides automatic netcfg wireless connection +Description=Automatic wireless connection Before=network.target Wants=network.target diff --git a/systemd/net-auto-wireless@.service b/systemd/net-auto-wireless@.service index 29a0efb..6754c60 100644 --- a/systemd/net-auto-wireless@.service +++ b/systemd/net-auto-wireless@.service @@ -1,5 +1,5 @@ [Unit] -Description=Provides automatic netcfg wireless connection +Description=Automatic wireless connection on %i Before=network.target Wants=network.target BindsTo=sys-subsystem-net-devices-%i.device -- 1.8.0
On Thu, Oct 25, 2012 at 12:39 AM, Thomas Bächler <thomas@archlinux.org> wrote:
These descriptions are shown in "Starting" and "Started" notifications.
Ack. -t
Am 25.10.2012 00:27, schrieb Thomas Bächler:
Our current systemd units have a fatal flaw: They may fail because they are started before the needed devices show up. This patch series adds new units that fix that. However, the change is not transparent for the user and requires different configuration.
I'd really like to deprecate netcfg.service, netcfg@.service and net-auto-wireless.service at some point, but that will break existing setups. I don't know if we should go ahead with this.
Anyway, please comment on the patches.
Don't apply this, I'll rewrite and resend the entire series later.
participants (3)
-
Dave Reisner
-
Thomas Bächler
-
Tom Gundersen