[arch-projects] [netctl][PATCH 2/3] Distinguish between network{, -online}.target (FS#50476)
The netctl@ service now yields before obtaining an IP address. This prevents holding up network.target unnecessarily. Waiting for profiles to obtain an IP address is possible through 1) The netctl-wait-online service This service waits until all enabled profiles have obtained an address. It is ordered before network-online.target so that this target is now correctly implemented in netctl. 2) The wait-online <PROFILE> subcommand to netctl This command waits for a started profile to obtain an address. --- contrib/bash-completion | 4 ++-- contrib/zsh-completion | 3 ++- docs/netctl.1.txt | 4 ++++ docs/netctl.special.7.txt | 16 +++++++++++--- services/netctl-ifplugd@.service | 1 + services/netctl-wait-online.service | 13 +++++++++++ services/netctl@.service | 3 ++- src/lib/connections/mobile_ppp | 3 +++ src/lib/connections/pppoe | 1 + src/lib/globals | 6 ++++++ src/lib/ip | 2 ++ src/lib/network | 40 ++++++++++++++++++++++++++++------ src/netctl.in | 43 ++++++++++++++++++++++++------------- 13 files changed, 111 insertions(+), 28 deletions(-) create mode 100644 services/netctl-wait-online.service diff --git a/contrib/bash-completion b/contrib/bash-completion index 2ab6acb..5f78355 100644 --- a/contrib/bash-completion +++ b/contrib/bash-completion @@ -23,10 +23,10 @@ _netctl() case $COMP_CWORD in 1) - COMPREPLY=( $(compgen -W "--help --version list store restore stop-all start stop restart switch-to is-active status enable disable reenable is-enabled edit" -- "$cur") ) + COMPREPLY=( $(compgen -W "--help --version list store restore stop-all start stop restart switch-to is-active status enable disable reenable is-enabled edit wait-online" -- "$cur") ) ;; 2) - [[ ${COMP_WORDS[COMP_CWORD-1]} = @(start|stop|restart|switch-to|is-active|status|enable|disable|reenable|is-enabled|edit) ]] && + [[ ${COMP_WORDS[COMP_CWORD-1]} = @(start|stop|restart|switch-to|is-active|status|enable|disable|reenable|is-enabled|edit|wait-online) ]] && mapfile -t COMPREPLY < <(IFS=$'\n'; compgen -W "$(_netctl_profiles)" -- "$cur") ;; esac diff --git a/contrib/zsh-completion b/contrib/zsh-completion index f583526..00cef81 100644 --- a/contrib/zsh-completion +++ b/contrib/zsh-completion @@ -11,7 +11,7 @@ _wireless_interfaces() { (( $+function[_netctl_command] )) || _netctl_command() { - [[ $words[1] = (start|stop|restart|switch-to|is-active|status|enable|disable|reenable|is-enabled|edit) ]] && + [[ $words[1] = (start|stop|restart|switch-to|is-active|status|enable|disable|reenable|is-enabled|edit|wait-online) ]] && compadd "${(f)$(find -L /etc/netctl -maxdepth 1 -type f -not -name '.*' -not -name '*~' -not -name '*.conf' -not -name '*.service' -printf "%f\n")}" } @@ -34,6 +34,7 @@ _netctl_commands() { 'reenable:Reenable the systemd unit for a profile' 'is-enabled:Check whether a profile is enabled' 'edit:Edit a profile' + 'wait-online:Wait for a profile to finish connecting' ) _describe "netctl commands" _commands } diff --git a/docs/netctl.1.txt b/docs/netctl.1.txt index 4fe87ca..0f63de4 100644 --- a/docs/netctl.1.txt +++ b/docs/netctl.1.txt @@ -84,6 +84,10 @@ The following commands are understood: Open the file of the specified profile in an editor. This does not reenable or restart any profiles. +*wait-online [+PROFILE+]*:: + Wait until the interface of the profile has a routable IP address of + some kind. + EXIT STATUS ----------- diff --git a/docs/netctl.special.7.txt b/docs/netctl.special.7.txt index a4e0911..da1c2ec 100644 --- a/docs/netctl.special.7.txt +++ b/docs/netctl.special.7.txt @@ -8,7 +8,8 @@ netctl.special - Special netctl systemd units SYNOPSIS -------- -netctl.service, netctl-auto.service, netctl-ifplugd.service +netctl.service, netctl-auto.service, netctl-ifplugd.service, +netctl-wait-online.service DESCRIPTION @@ -23,7 +24,7 @@ SPECIAL UNITS netctl.service:: When started, this unit tries to start the profiles that were running when the unit was last stopped. In some cases, the interface - a profile binds to might not be available yet, when netctl.service + a profile binds to might not be available yet, when 'netctl.service' tries to bring a profile up. A simple, hackish, solution is to do: -------------------------------------------------------------------- echo "[[ -t 0 ]] || sleep 3" > /etc/netctl/interfaces/<interface> @@ -56,7 +57,16 @@ netctl-ifplugd@<interface>.service:: This unit starts ifplugd on the interface it is used for. It will try to start a netctl profile whenever a cable is plugged into the interface and stop the profile when the cable is unplugged. Note - that this unit does not provide network.target. + that this unit does not provide 'network.target'. + +netctl-wait-online.service:: + When activated, this unit waits for all enabled netctl profiles to + come online. Enabling this unit causes 'network-online.target' to + only be reached once all enabled netctl profiles are fully + connected. The maximum time, in seconds, to wait for profiles can be + passed to this unit via 'TIMEOUT_ONLINE='. The default value is + +120+, but the service itself may time out sooner. If a timeout + occurs, the service enters a failed state. SEE ALSO diff --git a/services/netctl-ifplugd@.service b/services/netctl-ifplugd@.service index 2cea97b..76993b9 100644 --- a/services/netctl-ifplugd@.service +++ b/services/netctl-ifplugd@.service @@ -5,6 +5,7 @@ BindsTo=sys-subsystem-net-devices-%i.device After=sys-subsystem-net-devices-%i.device network-pre.target [Service] +NotifyAccess=all ExecStart=/usr/bin/ifplugd -i %I -r /etc/ifplugd/netctl.action -bfIns [Install] diff --git a/services/netctl-wait-online.service b/services/netctl-wait-online.service new file mode 100644 index 0000000..64ca06d --- /dev/null +++ b/services/netctl-wait-online.service @@ -0,0 +1,13 @@ +[Unit] +Description=Wait for the enabled netctl profiles to come online +Documentation=man:netctl.special(7) +After=network.target +Before=network-online.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/network/network wait-online + +[Install] +WantedBy=network-online.target diff --git a/services/netctl@.service b/services/netctl@.service index b8a19c2..d9c637d 100644 --- a/services/netctl@.service +++ b/services/netctl@.service @@ -6,7 +6,8 @@ Before=network.target netctl.service Wants=network.target [Service] -Type=oneshot +Type=notify +NotifyAccess=all RemainAfterExit=yes ExecStart=/usr/lib/network/network start %I ExecStop=/usr/lib/network/network stop %I diff --git a/src/lib/connections/mobile_ppp b/src/lib/connections/mobile_ppp index 78851f3..0890373 100644 --- a/src/lib/connections/mobile_ppp +++ b/src/lib/connections/mobile_ppp @@ -12,6 +12,9 @@ quote_word() { mobile_ppp_up() { local options_dir="$STATE_DIR/mobile_ppp.$Interface.$Profile" + + network_ready + mkdir -p "$options_dir" if [[ -z $ChatScript ]]; then ChatScript="$options_dir/modem.chat" diff --git a/src/lib/connections/pppoe b/src/lib/connections/pppoe index 36746a8..15e4db5 100644 --- a/src/lib/connections/pppoe +++ b/src/lib/connections/pppoe @@ -18,6 +18,7 @@ pppoe_up() { report_error "Failed to bring interface '$Interface' up" return 1 fi + network_ready mkdir -p "$(dirname "$options")" cat >> "$options" << EOF diff --git a/src/lib/globals b/src/lib/globals index a9e9751..f4e64a3 100644 --- a/src/lib/globals +++ b/src/lib/globals @@ -141,6 +141,12 @@ sd_call() { systemctl $command $(systemd-escape --template=netctl@.service "$@") } +## Retrieves the status string from the unit for a profile +# $1: profile name +sd_status_text() { + sd_call status "$1" | sed -n 's/^ *Status: "\(.*\)"$/\1/p' +} + # Set a restrictive umask do_readable : diff --git a/src/lib/ip b/src/lib/ip index 2dc67fc..71c7fa2 100644 --- a/src/lib/ip +++ b/src/lib/ip @@ -38,6 +38,8 @@ resolvconf_add() { ip_set() { local addr line route interface_sysctl=${Interface/.//} + network_ready + if [[ -z $IP && -z $IP6 ]]; then report_error "Neither IP, nor IP6 was specified" return 1 diff --git a/src/lib/network b/src/lib/network index adea2a2..8a43ce2 100755 --- a/src/lib/network +++ b/src/lib/network @@ -56,17 +56,33 @@ bring_interface_down() { timeout_wait "${TimeoutUp:-5}" '! interface_is_up "$interface"' } +## Indicate that the network stack for the profile is up +network_ready() { + if ! is_yes "${NETWORK_READY:-no}"; then + do_debug systemd-notify --pid --ready + NETWORK_READY=yes + fi +} + +## Describe the status of the service for the profile +# $1: status string, should be "online" when the profile gets connected +network_status() { + do_debug systemd-notify --pid --status="$1" +} + -if [[ $# -ne 2 || $1 != @(start|stop) ]]; then - exit_error "Usage: $0 {start|stop} <profile>" -fi ensure_root netctl # Ensure we are not in a transient directory cd / -# Expose the profile name -Profile=$2 -load_profile "$Profile" +if [[ $# -eq 2 && $1 == @(start|stop) ]]; then + # Expose the profile name + Profile=$2 + load_profile "$Profile" +elif [[ $# -ne 1 || $1 != "wait-online" ]]; then + exit_error "Usage: $0 {start|stop|wait-online} [profile]" +fi + case $1 in start) report_notice "Starting network profile '$Profile'..." @@ -79,6 +95,7 @@ case $1 in report_error "Failed to bring the network up for profile '$Profile'" exit 1 fi + network_ready # Sandbox the eval if ! ( eval $ExecUpPost ); then report_error "ExecUpPost failed for network profile '$Profile'" @@ -86,6 +103,7 @@ case $1 in "${Connection}_down" exit 1 fi + network_status "online" report_notice "Started network profile '$Profile'" ;; stop) @@ -100,6 +118,7 @@ case $1 in report_error "Failed to bring the network down for profile '$Profile'" exit 1 fi + network_status "" if is_interface "$Interface" && interface_is_up "$Interface" && \ ! is_yes "${ForceConnect:-no}"; then report_error "The interface of network profile '$Profile' did not go down" @@ -107,6 +126,15 @@ case $1 in fi report_notice "Stopped network profile '$Profile'" ;; + wait-online) + mapfile -t Profiles < <(list_profiles) + i=0 + ## Wait for all enabled profiles to come online within a single timeout + timeout_wait "${TIMEOUT_ONLINE:-120}" \ + '! until [[ $(sd_call is-enabled "${Profiles[i]}") == "enabled" && + $(sd_status_text "${Profiles[i]}") != "online" ]]; do + (( ++i < ${#Profiles[@]} )) || return 0; done' + ;; esac diff --git a/src/netctl.in b/src/netctl.in index 0df3759..fcb40f4 100644 --- a/src/netctl.in +++ b/src/netctl.in @@ -9,21 +9,22 @@ Usage: netctl {COMMAND} [PROFILE] [--help|--version] Commands: - list List available profiles - store Save which profiles are active - restore Load saved profiles - stop-all Stops all profiles - start [PROFILE] Start a profile - stop [PROFILE] Stop a profile - restart [PROFILE] Restart a profile - switch-to [PROFILE] Switch to a profile - is-active [PROFILE] Check whether a profile is active - status [PROFILE] Show runtime status of a profile - enable [PROFILE] Enable the systemd unit for a profile - disable [PROFILE] Disable the systemd unit for a profile - reenable [PROFILE] Reenable the systemd unit for a profile - is-enabled [PROFILE] Check whether a profile is enabled - edit [PROFILE] Edit a profile + list List available profiles + store Save which profiles are active + restore Load saved profiles + stop-all Stops all profiles + start [PROFILE] Start a profile + stop [PROFILE] Stop a profile + restart [PROFILE] Restart a profile + switch-to [PROFILE] Switch to a profile + is-active [PROFILE] Check whether a profile is active + status [PROFILE] Show runtime status of a profile + enable [PROFILE] Enable the systemd unit for a profile + disable [PROFILE] Disable the systemd unit for a profile + reenable [PROFILE] Reenable the systemd unit for a profile + is-enabled [PROFILE] Check whether a profile is enabled + edit [PROFILE] Edit a profile + wait-online [PROFILE] Wait for a profile to finish connecting END } @@ -122,6 +123,16 @@ unit_disable() { do_debug rm "$unit" } +wait_online() { + local profile="$1" + if sd_call "is-active --quiet" "$profile"; then + timeout_wait "${TIMEOUT_ONLINE:-120}" \ + '[[ $(sd_status_text "$profile") == "online" ]]' + else + return 1 + fi +} + case $# in 1) @@ -162,6 +173,8 @@ case $# in fi;; edit) exec ${EDITOR:-nano} "$PROFILE_DIR/$2";; + wait-online) + wait_online "$2";; *) exit_error "$(usage)";; esac;; -- 2.10.0
participants (1)
-
Jouke Witteveen