Commit e43a8221 authored by Jouke Witteveen's avatar Jouke Witteveen
Browse files

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.
parent b8f194cd
......@@ -7,7 +7,7 @@ pkgdesc='Profile based systemd network management'
url='http://projects.archlinux.org/netctl.git/'
license=('GPL')
groups=('base')
depends=('coreutils' 'iproute2' 'openresolv' 'systemd')
depends=('coreutils' 'iproute2' 'openresolv' 'systemd>=233')
# The source tarball includes pre-built (using asciidoc) documentation.
makedepends=('pkg-config')
optdepends=('dialog: for the menu based wifi assistant'
......
......@@ -25,10 +25,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) ]] &&
compopt -o filenames &&
mapfile -t COMPREPLY < <(IFS=$'\n'; compgen -W "$(_netctl_profiles)" -- "$cur")
;;
......
......@@ -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 $'*\n*' -not -name '*.action' -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
}
......
......@@ -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
-----------
......
......@@ -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,15 @@ 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+. If a timeout occurs, the service enters a failed state.
SEE ALSO
......
......@@ -7,10 +7,10 @@ Before=network.target
Wants=network.target
[Service]
Type=forking
RemainAfterExit=yes
ExecStart=/usr/bin/netctl-auto start %I
ExecStop=/usr/bin/netctl-auto stop %I
RemainAfterExit=yes
Type=forking
[Install]
WantedBy=multi-user.target
......@@ -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]
......
[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
......@@ -6,7 +6,8 @@ Before=network.target netctl.service
Wants=network.target
[Service]
Type=oneshot
Type=notify
NotifyAccess=exec
RemainAfterExit=yes
ExecStart=/usr/lib/network/network start %I
ExecStop=/usr/lib/network/network stop %I
......@@ -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"
......
......@@ -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
......
......@@ -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 :
......
......@@ -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
......
......@@ -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 --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 --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
......
......@@ -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;;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment