summaryrefslogtreecommitdiffstats
path: root/docs/NETWORK_ONLINE.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/NETWORK_ONLINE.md')
-rw-r--r--docs/NETWORK_ONLINE.md261
1 files changed, 261 insertions, 0 deletions
diff --git a/docs/NETWORK_ONLINE.md b/docs/NETWORK_ONLINE.md
new file mode 100644
index 0000000..5e01ab6
--- /dev/null
+++ b/docs/NETWORK_ONLINE.md
@@ -0,0 +1,261 @@
+---
+title: Running Services After the Network Is Up
+category: Networking
+layout: default
+SPDX-License-Identifier: LGPL-2.1-or-later
+---
+
+# Network Configuration Synchronization Points
+
+systemd provides three target units related to network configuration:
+
+## Network pre-configuration: `network-pre.target`
+
+`network-pre.target` is used to order services before any network interfaces
+start to be configured. Its primary purpose is for usage with firewall services
+that want to establish a firewall *before* any network interface is up.
+
+`network-pre.target` is a passive unit: it cannot be started directly and it is
+not pulled in by the the network management service, but instead a service that
+wants to run before it must pull it in. Network management services hence
+should set `After=network-pre.target`, but not `Wants=network-pre.target` or
+`Requires=network-pre.target`. Services that want to be run before the network
+is configured should use `Before=network-pre.target` and
+`Wants=network-pre.target`. This way, unless there's actually a service that
+needs to be ordered before the network is up, this target is not pulled in,
+avoiding an unnecessary synchronization point.
+
+## Network management services: `network.target`
+
+`network.target` indicates that the network management stack has been started.
+Ordering after it it has little meaning during start-up: whether any network
+interfaces are already configured when it is reached is not defined.
+
+Its primary purpose is for ordering things properly at shutdown: since the
+shutdown ordering of units in systemd is the reverse of the startup ordering,
+any unit that has `After=network.target` can be sure that it is *stopped*
+before the network is shut down when the system is going down. This allows
+services to cleanly terminate connections before going down, instead of losing
+ongoing connections leaving the other side in an undefined state.
+
+Note that `network.target` is a passive unit: you cannot start it directly and
+it is not pulled in by any services that want to make use of the network.
+Instead, it is pulled in by the network management services
+themselves. Services using the network should hence simply place an
+`After=network.target` stanza in their unit files, without
+`Wants=network.target` or `Requires=network.target`.
+
+## Network connectivity has been estabilished: `network-online.target`
+
+`network-online.target` is a target that actively waits until the network is
+"up", where the definition of "up" is defined by the network management
+software. Usually it indicates a configured, routable IP address of some
+kind. Its primary purpose is to actively delay activation of services until the
+network has been set up.
+
+It is an active target, meaning that it may be pulled in by the services
+requiring the network to be up, but is not pulled in by the network management
+service itself. By default all remote mounts defined in `/etc/fstab` make use
+of this service, in order to make sure the network is up before attempts to
+connect to a network share are made. Note that normally, if no service requires
+it and if no remote mount point is configured, this target is not pulled into
+the boot, thus avoiding any delays during boot should the network not be
+available. It is strongly recommended not to make use of this target too
+liberally: for example network server software should generally not pull this
+in (since server software generally is happy to accept local connections even
+before any routable network interface is up). Its primary purpose is network
+client software that cannot operate without network.
+
+For more details about those targets, see the
+[systemd.special(7)](https://www.freedesktop.org/software/systemd/man/systemd.special.html)
+man page.
+
+## Compatibility with SysV init
+
+LSB defines a `$network` dependency for legacy init scripts. Whenever systemd
+encounters a `$network` dependency in LSB headers of init scripts it will
+translate this to `Wants=` and `After=` dependencies on
+`network-online.target`, staying relatively close to traditional LSB behaviour.
+
+# Discussion
+
+The meaning of `$network` is defined [only very
+unprecisely](http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/facilname.html)
+and people tend to have different ideas what it is supposed to mean. Here are a
+couple of ideas people came up with so far:
+
+* The network management software is up.
+* All "configured" network interfaces are up and an IP address has been assigned to each.
+* All discovered local hardware interfaces that have a link beat have an IP address assigned, independently whether there is actually any explicit local configuration for them.
+* The network has been set up precisely to the level that a DNS server is reachable.
+* Same, but some specific site-specific server is reachable.
+* Same, but "the Internet" is reachable.
+* All "configured" ethernet devices are up, but all "configured" PPP links which are supposed to also start at boot don't have to be yet.
+* A certain "profile" is enabled and some condition of the above holds. If another "profile" is enabled a different condition would have to be checked.
+* Based on the location of the system a different set of configuration should be up or checked for.
+* At least one global IPv4 address is configured.
+* At least one global IPv6 address is configured.
+* At least one global IPv4 or IPv6 address is configured.
+* And so on and so on.
+
+All these are valid approaches to the question "When is the network up?", but
+none of them would be useful to be good as generic default.
+
+Modern networking tends to be highly dynamic: machines are moved between
+networks, network configuration changes, hardware is added and removed, virtual
+networks are set up, reconfigured, and shut down again. Network connectivity is
+not unconditionally and continuously available, and a machine is connected to
+different networks at different times. This is particularly true for mobile
+hardware such as handsets, tablets, and laptops, but also for embedded and
+servers. Software that is written under the assumption that network
+connectivity is available continuously and never changes is hence not
+up-to-date with reality. Well-written software should be able to handle dynamic
+configuration changes. It should react to changing network configuration and
+make the best of it. If it cannot reach a server it must retry. If network
+configuration connectivity is lost it must not fail catastrophically. Reacting
+to local network configuration changes in daemon code is not particularly
+hard. In fact many well-known network-facing services running on Linux have
+been doing this for decades. A service written like this is robust, can be
+started at any time, and will always do the best of the circumstances it is
+running in.
+
+`$network` / `network-online.target` is a mechanism that is required only to
+deal with software that assumes continuous network is available (i.e. of the
+simple not-well-written kind). Which facet of it it requires is undefined. An
+IMAP server might just require a certain IP to be assigned so that it can
+listen on it. OTOH a network file system client might need DNS up, and the
+service to contact up, as well. What precisely is required is not obvious and
+can be different things depending on local configuration.
+
+A robust system boots up independently of external services. More specifically,
+if a network DHCP server does not react, this should not slow down boot on most
+setups, but only for those where network connectivity is strictly needed (for
+example, because the host actually boots from the network).
+
+# FAQ
+
+## How do I make sure that my service starts after the network is *really* online?
+
+That depends on your setup and the services you plan to run after it (see
+above). If you need to delay you service after network connectivity has been
+established, include
+
+```ini
+After=network-online.target
+Wants=network-online.target
+```
+
+in the `.service` file.
+
+This will delay boot until the network management software says the network is "up".
+For details, see the next question.
+
+## What does "up" actually mean?
+
+The services that are ordered before `network-online.target` define its
+meaning. *Usually* means that all configured network devices are up and have an
+IP address assigned, but details may vary. In particular, configuration may
+affect which interfaces are taken into account.
+
+`network-online.target` will time out after 90s. Enabling this might
+considerably delay your boot even if the timeout is not reached.
+
+The right "wait" service must be enabled:
+`NetworkManager-wait-online.service` if `NetworkManager` is used to configure
+the network, `systemd-networkd-wait-online.service` if `systemd-networkd` is
+used, etc. `systemd-networkd.service` has
+`Also=systemd-networkd-wait-online.service` in its `[Install]` section, so when
+`systemd-networkd.service` is enabled, `systemd-networkd-wait-online.service`
+will be enabled too, which means that `network-online.target` will include
+`systemd-networkd-wait-online.service` when and only when
+`systemd-networkd.service` is enabled. `NetworkManager-wait-online.service` is
+set up similarly. This means that the "wait" services do not need to be enabled
+explicitly. They will be enabled automatically when the "main" service is
+enabled, though they will not be *used* unless something else pulls in
+`network-online.target`.
+
+To verify that the right service is enabled (usually only one should be):
+```console
+$ systemctl is-enabled NetworkManager-wait-online.service systemd-networkd-wait-online.service
+disabled
+enabled
+```
+
+## Should `network-online.target` be used?
+
+Please note that `network-online.target` means that the network connectivity
+*has been* reached, not that it is currently available. By the very nature and
+design of the network, connectivity may briefly or permanently disappear, so
+for reasonable user experience, services need to handle temporary lack of
+connectivity.
+
+If you are a developer, instead of wondering what to do about `network.target`,
+please just fix your program to be friendly to dynamically changing network
+configuration. That way you will make your users happy because things just
+start to work, and you will get fewer bug reports. You also make the boot
+faster by not delaying services until network connectivity has been
+established. This is particularly important for folks with slow address
+assignment replies from a DHCP server.
+
+Here are a couple of possible approaches:
+
+1. Watch rtnetlink and react to network configuration changes as they
+ happen. This is usually the nicest solution, but not always the easiest.
+2. If you write a server: listen on `[::]`, `[::1]`, `0.0.0.0`, and `127.0.0.1`
+ only. These pseudo-addresses are unconditionally available. If you always
+ bind to these addresses you will have code that doesn't have to react to
+ network changes, as all you listen on is catch-all and private addresses.
+3. If you write a server: if you want to listen on other, explicitly configured
+ addresses, consider using the `IP_FREEBIND` sockopt functionality of the
+ Linux kernel. This allows your code to bind to an address even if it is not
+ actually (yet or ever) configured locally. This also makes your code robust
+ towards network configuration changes. This is provided as `FreeBind=`
+ for systemd services, see
+ [systemd.socket(5)](https://www.freedesktop.org/software/systemd/man/systemd.socket.html).
+
+An exception to the above recommendations is services which require network
+connectivity, but do not delay system startup. An example may be a service
+which downloads package updates into a cache (to be used at some point in the
+future by the package management software). Such a service may even start
+during boot, and pull in and be ordered after `network-online.target`, but as
+long as it is not ordered before any unit that is part of the default target,
+it does not delay boot. It is usually easier to write such a service in a
+"simplistic" way, where it doesn't try to wait for the network connectivity to
+be (re-)established, but is instead started when the network has connectivity,
+and if the network goes away, it fails and relies on the system manager to
+restart it if appropriate.
+
+## Modyfing the meaning of `network-online.target`
+
+As described above, the meaning of this target is defined first by which
+implementing services are enabled (`NetworkManager-wait-online.service`,
+`systemd-networkd-wait-online.service`, …), and second by the configuration
+specific to those services.
+
+For example, `systemd-networkd-wait-online.service` will wait until all
+interfaces that are present and managed by
+[systemd-networkd.service(8)](https://www.freedesktop.org/software/systemd/man/systemd-networkd.service.html).
+are fully configured or failed and at least one link is online; see
+[systemd-networkd-wait-online.service(8)](https://www.freedesktop.org/software/systemd/man/systemd-networkd-wait-online.service.html)
+for details. Those conditions are affected by the presence of configuration
+that matches various links, but also by settings like
+`Unmanaged=`, `RequiredForOnline=`, `RequiredFamilyForOnline=`; see
+[systemd.network(5)](https://www.freedesktop.org/software/systemd/man/systemd.network.html).
+
+It is also possible to plug in additional checks for network state. For
+example, to delay `network-online.target` until some a specific host is
+reachable (the name can be resolved over DNS and the appropriate route has been
+established), the following simple service could be used:
+
+```ini
+[Unit]
+DefaultDependencies=no
+After=nss-lookup.target
+Before=network-online.target
+
+[Service]
+ExecStart=sh -c 'while ! ping -c 1 example.com; do sleep 1; done'
+
+[Install]
+WantedBy=network-online.target
+```