chiark / gitweb /
networkd-wait-online: improve interoptability and enable by default
authorTom Gundersen <teg@jklm.no>
Wed, 23 Apr 2014 15:42:55 +0000 (17:42 +0200)
committerTom Gundersen <teg@jklm.no>
Wed, 23 Apr 2014 22:23:07 +0000 (00:23 +0200)
To make sure we don't delay boot on systems where (some) network links are managed by someone else
we don't block if something else has successfully brought up a link.

We will still block until all links we are aware of that are  managed by networkd have been
configured, but if no such links exist, and someone else have configured a link sufficiently
that it has a carrier, it may be that the link is ready so we should no longer block.

Note that in all likelyhood the link is not ready (no addresses/routes configured),
so whatever network managment daemon configured it should provide a similar wait-online
service to block network-online.target until it is ready.

The aim is to block as long as we know networking is not fully configured, but no longer. This
will allow systemd-networkd-wait-online.service to be enabled on any system, even if we don't
know whether networkd is the main/only network manager.

Even in the case networking is fully configured by networkd, the default behavior may not be
sufficient: if two links need to be configured, but the first is fully configured before the
second one appears we will assume the network is up. To work around that, we allow specifying
specific devices to wait for before considering the network up.

This unit is enabled by default, just like systemd-networkd, but will only be pulled in if
anyone pulls in network-online.target.

16 files changed:
Makefile-man.am
Makefile.am
man/networkd-wait-online.conf.xml [new file with mode: 0644]
man/systemd-networkd-wait-online.service.xml [new file with mode: 0644]
man/systemd-networkd.service.xml
src/libsystemd-network/network-internal.c
src/libsystemd-network/network-internal.h
src/network/.gitignore
src/network/networkd-link.c
src/network/networkd-wait-online-gperf.gperf [new file with mode: 0644]
src/network/networkd-wait-online.c
src/network/networkd-wait-online.conf [new file with mode: 0644]
src/network/networkd-wait-online.h [new file with mode: 0644]
units/.gitignore
units/systemd-networkd-wait-online.service.in [new file with mode: 0644]
units/systemd-networkd.service.in

index 90d32c52126b3e93b15d104368a1d7de08567700..db66e020c0bd8073332d587fd3d0eb2c3927814f 100644 (file)
@@ -1039,12 +1039,17 @@ endif
 if ENABLE_NETWORKD
 MANPAGES += \
        man/systemd-networkd.service.8 \
 if ENABLE_NETWORKD
 MANPAGES += \
        man/systemd-networkd.service.8 \
+       man/systemd-networkd-wait-online.service.8 \
+       man/networkd-wait-online.conf.5 \
        man/systemd.netdev.5 \
        man/systemd.network.5
 MANPAGES_ALIAS += \
        man/systemd.netdev.5 \
        man/systemd.network.5
 MANPAGES_ALIAS += \
-       man/systemd-networkd.8
+       man/systemd-networkd.8 \
+       man/systemd-networkd-wait-online.8
 man/systemd-networkd.8: man/systemd-networkd.service.8
 man/systemd-networkd.html: man/systemd-networkd.service.html
 man/systemd-networkd.8: man/systemd-networkd.service.8
 man/systemd-networkd.html: man/systemd-networkd.service.html
+man/systemd-networkd-wait-online.8: man/systemd-networkd-wait-online.service.8
+man/systemd-networkd-wait-online.html: man/systemd-networkd-wait-online.service.html
        $(html-alias)
 
 endif
        $(html-alias)
 
 endif
index 6967b6f28906c65df2364454b70f63ee9f0ffb55..f261c476daa73783b2a2ed9f3c8e7b93b9454166 100644 (file)
@@ -4134,6 +4134,7 @@ noinst_LTLIBRARIES += \
        libsystemd-networkd-core.la
 
 libsystemd_networkd_core_la_SOURCES = \
        libsystemd-networkd-core.la
 
 libsystemd_networkd_core_la_SOURCES = \
+       src/libsystemd-network/network-internal.h \
        src/network/networkd.h \
        src/network/networkd-link.c \
        src/network/networkd-netdev.c \
        src/network/networkd.h \
        src/network/networkd-link.c \
        src/network/networkd-netdev.c \
@@ -4154,16 +4155,23 @@ libsystemd_networkd_core_la_LIBADD = \
        libsystemd-shared.la
 
 nodist_systemunit_DATA += \
        libsystemd-shared.la
 
 nodist_systemunit_DATA += \
-       units/systemd-networkd.service
+       units/systemd-networkd.service \
+       units/systemd-networkd-wait-online.service
 
 GENERAL_ALIASES += \
 
 GENERAL_ALIASES += \
-       $(systemunitdir)/systemd-networkd.service $(pkgsysconfdir)/system/multi-user.target.wants/systemd-networkd.service
+       $(systemunitdir)/systemd-networkd.service $(pkgsysconfdir)/system/multi-user.target.wants/systemd-networkd.service \
+       $(systemunitdir)/systemd-networkd.service $(pkgsysconfdir)/system/network-online.target.wants/systemd-networkd-wait-online.service
 
 rootlibexec_PROGRAMS += \
        systemd-networkd-wait-online
 
 systemd_networkd_wait_online_SOURCES = \
 
 rootlibexec_PROGRAMS += \
        systemd-networkd-wait-online
 
 systemd_networkd_wait_online_SOURCES = \
-       src/network/networkd-wait-online.c
+       src/libsystemd-network/network-internal.h \
+       src/network/networkd-wait-online.c \
+       src/network/networkd-wait-online.h
+
+nodist_systemd_networkd_wait_online_SOURCES = \
+       src/network/networkd-wait-online-gperf.c
 
 systemd_networkd_wait_online_LDADD = \
        libsystemd-internal.la \
 
 systemd_networkd_wait_online_LDADD = \
        libsystemd-internal.la \
@@ -4178,14 +4186,19 @@ test_network_LDADD = \
 tests += \
        test-network
 
 tests += \
        test-network
 
+dist_pkgsysconf_DATA += \
+       src/network/networkd-wait-online.conf
+
 EXTRA_DIST += \
        src/network/networkd-network-gperf.gperf \
        src/network/networkd-netdev-gperf.gperf \
 EXTRA_DIST += \
        src/network/networkd-network-gperf.gperf \
        src/network/networkd-netdev-gperf.gperf \
+       src/network/networkd-wait-online-gperf.gperf \
        units/systemd-networkd.service.in
 
 CLEANFILES += \
        src/network/networkd-network-gperf.c \
        units/systemd-networkd.service.in
 
 CLEANFILES += \
        src/network/networkd-network-gperf.c \
-       src/network/networkd-netdev-gperf.c
+       src/network/networkd-netdev-gperf.c \
+       src/network/networkd-wait-online-gperf.c
 endif
 
 # ------------------------------------------------------------------------------
 endif
 
 # ------------------------------------------------------------------------------
diff --git a/man/networkd-wait-online.conf.xml b/man/networkd-wait-online.conf.xml
new file mode 100644 (file)
index 0000000..821b0ef
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="networkd-wait-online.conf" conditional='ENABLE_NETWORKD'>
+        <refentryinfo>
+                <title>networkd-wait-online.conf</title>
+                <productname>systemd</productname>
+
+                <authorgroup>
+                        <author>
+                                <contrib>Developer</contrib>
+                                <firstname>Tom</firstname>
+                                <surname>Gundersen</surname>
+                                <email>teg@jklm.no</email>
+                        </author>
+                </authorgroup>
+        </refentryinfo>
+
+        <refmeta>
+                <refentrytitle>networkd-wait-online.conf</refentrytitle>
+                <manvolnum>5</manvolnum>
+        </refmeta>
+
+        <refnamediv>
+                <refname>networkd-wait-online.conf</refname>
+                <refpurpose>Network manager configuration file</refpurpose>
+        </refnamediv>
+
+        <refsynopsisdiv>
+                <para><filename>/etc/systemd/networkd-wait-online.conf</filename></para>
+        </refsynopsisdiv>
+
+        <refsect1>
+                <title>Description</title>
+
+                <para>This file configures various parameters of the systemd network manager's wait-online service, <citerefentry><refentrytitle>systemd-networkd-wait-online.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+        </refsect1>
+
+        <refsect1>
+                <title>Options</title>
+
+                <para>All options are configured in the
+                <literal>[WaitOnline]</literal> section:</para>
+
+                <variablelist>
+
+                        <varlistentry>
+                                <term><varname>After=</varname></term>
+
+                                <listitem><para>Takes a white-space
+                                separated list of network interface
+                                names. Configures which network interfaces
+                                to wait for before deciding if the machine
+                                is considered to be online. The default is
+                                to wait for at least one that is managed by
+                                <citerefentry><refentrytitle>systemd-networkd.service
+                                </refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+                                or one other which is brought up by someone else.
+                                </para></listitem>
+                        </varlistentry>
+
+                </variablelist>
+        </refsect1>
+
+        <refsect1>
+                  <title>See Also</title>
+                  <para>
+                          <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+                          <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+                  </para>
+        </refsect1>
+
+</refentry>
diff --git a/man/systemd-networkd-wait-online.service.xml b/man/systemd-networkd-wait-online.service.xml
new file mode 100644 (file)
index 0000000..d8f2226
--- /dev/null
@@ -0,0 +1,81 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="systemd-networkd-wait-online.service" conditional='ENABLE_NETWORKD'>
+
+        <refentryinfo>
+                <title>systemd-networkd.service</title>
+                <productname>systemd</productname>
+
+                <authorgroup>
+                        <author>
+                                <contrib>Developer</contrib>
+                                <firstname>Tom</firstname>
+                                <surname>Gundersen</surname>
+                                <email>teg@jklm.no</email>
+                        </author>
+                </authorgroup>
+        </refentryinfo>
+
+        <refmeta>
+                <refentrytitle>systemd-networkd-wait-online.service</refentrytitle>
+                <manvolnum>8</manvolnum>
+        </refmeta>
+
+        <refnamediv>
+                <refname>systemd-networkd-wait-online.service</refname>
+                <refname>systemd-networkd-wait-online</refname>
+                <refpurpose>Wait for network to become online</refpurpose>
+        </refnamediv>
+
+        <refsynopsisdiv>
+                <para><filename>systemd-networkd-wait-online.service</filename></para>
+                <para><filename>/usr/lib/systemd/systemd-networkd-wait-online</filename></para>
+        </refsynopsisdiv>
+
+        <refsect1>
+                <title>Description</title>
+
+                <para><command>systemd-networkd-wait-online</command> is a
+                one-shot system service that waits for the network to be configured.
+                It will wait for all links managed by
+                <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+                to be fully configured. It will wait for at least one link managed by
+                systemd-networkd to appear, or for a link to be brought up by someone else.
+
+                To wait for a specific set of links, see
+                <citerefentry><refentrytitle>systemd-networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+                This may be necessary on systems with more than one active link.
+                </para>
+        </refsect1>
+
+        <refsect1>
+                <title>See Also</title>
+                <para>
+                        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>systemd-networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+                </para>
+        </refsect1>
+
+</refentry>
index bcdd9adae024a5feb0fa31d996ea8133adf2f91b..ca35a8850b0ef6081f192e41bc9d2a6a7f7afa93 100644 (file)
                         <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>
                         <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+                        <citerefentry><refentrytitle>systemd-network-wait-online.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
                 </para>
         </refsect1>
 
                 </para>
         </refsect1>
 
index 52e614c4eab38dbc80b1160275b8d373643c9146..e7ba628fc71e8ef2030d0986c9f5d71a4b0cb5f1 100644 (file)
@@ -326,3 +326,17 @@ int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
 
         return 0;
 }
 
         return 0;
 }
+
+bool link_has_carrier(unsigned flags, uint8_t operstate) {
+        /* see Documentation/networking/operstates.txt in the kernel sources */
+
+        if (operstate == IF_OPER_UP)
+                return true;
+
+        if (operstate == IF_OPER_UNKNOWN)
+                /* operstate may not be implemented, so fall back to flags */
+                if ((flags & IFF_LOWER_UP) && !(flags & IFF_DORMANT))
+                        return true;
+
+        return false;
+}
index 836472a776fd0a09b783c6de5227969a482af596..ef3cb8b91d0f72c0b556bbe9e03fc19ce28652f8 100644 (file)
@@ -65,3 +65,5 @@ int config_parse_ifalias(const char *unit, const char *filename, unsigned line,
 int net_parse_inaddr(const char *address, unsigned char *family, void *dst);
 
 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]);
 int net_parse_inaddr(const char *address, unsigned char *family, void *dst);
 
 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]);
+
+bool link_has_carrier(unsigned flags, uint8_t operstate);
index 8858596489610f1cd9cd7fca968dd310b7f88c7b..e3b86e2d4ae2e90d4d092cb178f464ac1d8ff67f 100644 (file)
@@ -1,2 +1,3 @@
 /networkd-network-gperf.c
 /networkd-netdev-gperf.c
 /networkd-network-gperf.c
 /networkd-netdev-gperf.c
+/networkd-wait-online-gperf.c
index 310b9f54f96c7cd6aa42f5a1d0613692632dd38c..015a82d0d6022e4f83270afdc8eb3c9b9e1cc0d0 100644 (file)
@@ -30,6 +30,7 @@
 #include "bus-util.h"
 #include "network-internal.h"
 
 #include "bus-util.h"
 #include "network-internal.h"
 
+#include "network-util.h"
 #include "dhcp-lease-internal.h"
 
 static int ipv4ll_address_update(Link *link, bool deprecate);
 #include "dhcp-lease-internal.h"
 
 static int ipv4ll_address_update(Link *link, bool deprecate);
@@ -1098,20 +1099,6 @@ static int link_acquire_conf(Link *link) {
         return 0;
 }
 
         return 0;
 }
 
-static bool link_has_carrier(unsigned flags, uint8_t operstate) {
-        /* see Documentation/networking/operstates.txt in the kernel sources */
-
-        if (operstate == IF_OPER_UP)
-                return true;
-
-        if (operstate == IF_OPER_UNKNOWN)
-                /* operstate may not be implemented, so fall back to flags */
-                if ((flags & IFF_LOWER_UP) && !(flags & IFF_DORMANT))
-                        return true;
-
-        return false;
-}
-
 static int link_update_flags(Link *link, sd_rtnl_message *m) {
         unsigned flags, flags_added, flags_removed, generic_flags;
         uint8_t operstate;
 static int link_update_flags(Link *link, sd_rtnl_message *m) {
         unsigned flags, flags_added, flags_removed, generic_flags;
         uint8_t operstate;
diff --git a/src/network/networkd-wait-online-gperf.gperf b/src/network/networkd-wait-online-gperf.gperf
new file mode 100644 (file)
index 0000000..0a5e5ee
--- /dev/null
@@ -0,0 +1,17 @@
+%{
+#include <stddef.h>
+#include "conf-parser.h"
+#include "networkd-wait-online.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name wait_online_gperf_hash
+%define lookup-function-name wait_online_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+WaitOnline.ExpectedLinks,               config_parse_strv,          0, offsetof(Manager, expected_links)
index e62859e1cf9c8b229204a2e853329173026f7c0e..6a7c62feae544c1c191ebd0609d4aa7ee728be52 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <netinet/ether.h>
+#include <linux/if.h>
+
 #include "sd-event.h"
 #include "event-util.h"
 #include "sd-event.h"
 #include "event-util.h"
+#include "sd-rtnl.h"
+#include "rtnl-util.h"
 #include "sd-daemon.h"
 #include "sd-network.h"
 #include "network-util.h"
 #include "sd-daemon.h"
 #include "sd-network.h"
 #include "network-util.h"
+#include "network-internal.h"
+#include "networkd-wait-online.h"
 
 
+#include "conf-parser.h"
+#include "strv.h"
 #include "util.h"
 
 #include "util.h"
 
-static bool all_configured(void) {
+static bool all_configured(Manager *m) {
         _cleanup_free_ unsigned *indices = NULL;
         _cleanup_free_ unsigned *indices = NULL;
+        char **ifname;
         bool one_ready = false;
         int r, n, i;
 
         bool one_ready = false;
         int r, n, i;
 
@@ -36,35 +46,168 @@ static bool all_configured(void) {
         if (n <= 0)
                 return false;
 
         if (n <= 0)
                 return false;
 
+        STRV_FOREACH(ifname, m->expected_links) {
+                _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
+                bool found = false;
+                int index;
+
+                r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, 0);
+                if (r < 0) {
+                        log_warning("colud not create GETLINK message: %s", strerror(-r));
+                        return false;
+                }
+
+                r = sd_rtnl_message_append_string(message, IFLA_IFNAME, *ifname);
+                if (r < 0) {
+                        log_warning("could not attach ifname to GETLINK message: %s", strerror(-r));
+                        return false;
+                }
+
+                r = sd_rtnl_call(m->rtnl, message, 0, &reply);
+                if (r < 0) {
+                        if (r != -ENODEV)
+                                log_warning("could not get link info for %s: %s", *ifname,
+                                            strerror(-r));
+
+                        /* link does not yet exist */
+                        return false;
+                }
+
+                r = sd_rtnl_message_link_get_ifindex(reply, &index);
+                if (r < 0) {
+                        log_warning("could not get ifindex: %s", strerror(-r));
+                        return false;
+                }
+
+                if (index <= 0) {
+                        log_warning("invalid ifindex %d for %s", index, *ifname);
+                        return false;
+                }
+
+                for (i = 0; i < n; i++) {
+                        if (indices[i] == (unsigned) index) {
+                                found = true;
+                                break;
+                        }
+                }
+
+                if (!found)
+                        /* link exists, but networkd is not yet aware of it */
+                        return false;
+        }
+
         for (i = 0; i < n; i++) {
                 _cleanup_free_ char *state = NULL;
 
                 r = sd_network_get_link_state(indices[i], &state);
         for (i = 0; i < n; i++) {
                 _cleanup_free_ char *state = NULL;
 
                 r = sd_network_get_link_state(indices[i], &state);
-                if (r == -EUNATCH)
+                if (r == -EUNATCH) {
+                        _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
+                        unsigned flags;
+                        uint8_t operstate;
+
+                        r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, indices[i]);
+                        if (r < 0) {
+                                log_warning("could not create GETLINK message: %s", strerror(-r));
+                                return false;
+                        }
+
+                        r = sd_rtnl_call(m->rtnl, message, 0, &reply);
+                        if (r < 0) {
+                                log_debug("could not get link %u: %s", indices[i], strerror(-r));
+                                continue;
+                        }
+
+                        r = sd_rtnl_message_link_get_flags(reply, &flags);
+                        if (r < 0) {
+                                log_warning("could not get link flags: %s", strerror(-r));
+                                return false;
+                        }
+
+                        r = sd_rtnl_message_read_u8(reply, IFLA_OPERSTATE, &operstate);
+                        if (r < 0) {
+                                log_debug("could not get link operational state: %s", strerror(-r));
+                                operstate = IF_OPER_UNKNOWN;
+                        }
+                        
+                        if (!(flags & IFF_LOOPBACK) &&
+                            link_has_carrier(flags, operstate)) {
+                                /* this link is not managed by us,
+                                   but something else may have
+                                   made it ready, so don't block */
+                                one_ready = true;
+                        }
+
                         continue;
                         continue;
-                if (r < 0 || !streq(state, "configured"))
+                } else if (r < 0 || !streq(state, "configured"))
                         return false;
 
                         return false;
 
+                /* we wait for at least one link to appear */
                 one_ready = true;
         }
 
         return one_ready;
 }
 
                 one_ready = true;
         }
 
         return one_ready;
 }
 
-static int event_handler(sd_event_source *s, int fd, uint32_t revents,
+static int monitor_event_handler(sd_event_source *s, int fd, uint32_t revents,
                          void *userdata) {
                          void *userdata) {
-        sd_event *event = userdata;
+        Manager *m = userdata;
+
+        assert(m);
+        assert(m->event);
+
+        if (all_configured(m))
+                sd_event_exit(m->event, 0);
+
+        return 1;
+}
 
 
-        assert(event);
+static int newlink_event_handler(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
+        Manager *m = userdata;
 
 
-        if (all_configured())
-                sd_event_exit(event, 0);
+        assert(m);
+        assert(m->event);
+
+        if (all_configured(m))
+                sd_event_exit(m->event, 0);
 
         return 1;
 }
 
 
         return 1;
 }
 
+static int parse_config_file(Manager *m) {
+        static const char fn[] = "/etc/systemd/networkd-wait-online.conf";
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        f = fopen(fn, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_warning("Failed to open configuration file %s: %m", fn);
+                return -errno;
+        }
+
+        r = config_parse(NULL, fn, f, "WaitOnline\0", config_item_perf_lookup,
+                         (void*) wait_online_gperf_lookup, false, false, m);
+        if (r < 0)
+                log_warning("Failed to parse configuration file: %s", strerror(-r));
+
+        return r;
+}
+
+void manager_free(Manager *m) {
+        if (!m)
+                return;
+
+        sd_event_unref(m->event);
+        sd_rtnl_unref(m->rtnl);
+        strv_free(m->expected_links);
+
+        free(m);
+}
+
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
-        _cleanup_event_unref_ sd_event *event = NULL;
+        _cleanup_manager_free_ Manager *m = NULL;
         _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
         _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
         int r, fd, events;
         _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
         _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
         int r, fd, events;
@@ -81,13 +224,21 @@ int main(int argc, char *argv[]) {
                 goto out;
         }
 
                 goto out;
         }
 
+        m = new0(Manager, 1);
+        if (!m)
+                return log_oom();
+
+        r = parse_config_file(m);
+        if (r < 0)
+                goto out;
+
         r = sd_network_monitor_new(NULL, &monitor);
         if (r < 0) {
                 log_error("Could not create monitor: %s", strerror(-r));
                 goto out;
         }
 
         r = sd_network_monitor_new(NULL, &monitor);
         if (r < 0) {
                 log_error("Could not create monitor: %s", strerror(-r));
                 goto out;
         }
 
-        r = sd_event_new(&event);
+        r = sd_event_new(&m->event);
         if (r < 0) {
                 log_error("Could not create event: %s", strerror(-r));
                 goto out;
         if (r < 0) {
                 log_error("Could not create event: %s", strerror(-r));
                 goto out;
@@ -105,14 +256,30 @@ int main(int argc, char *argv[]) {
                 goto out;
         }
 
                 goto out;
         }
 
-        r = sd_event_add_io(event, &event_source, fd, events, &event_handler,
-                            event);
+        r = sd_event_add_io(m->event, &event_source, fd, events, &monitor_event_handler,
+                            m);
         if (r < 0) {
                 log_error("Could not add io event source: %s", strerror(-r));
                 goto out;
         }
 
         if (r < 0) {
                 log_error("Could not add io event source: %s", strerror(-r));
                 goto out;
         }
 
-        if (all_configured()) {
+        r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK);
+        if (r < 0) {
+                log_error("Could not create rtnl: %s", strerror(-r));
+                goto out;
+        }
+
+        r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
+        if (r < 0) {
+                log_error("Could not attach event to rtnl: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, newlink_event_handler, m);
+        if (r < 0)
+                return r;
+
+        if (all_configured(m)) {
                 r = 0;
                 goto out;
         }
                 r = 0;
                 goto out;
         }
@@ -121,7 +288,7 @@ int main(int argc, char *argv[]) {
                   "READY=1\n"
                   "STATUS=Waiting for network connections...");
 
                   "READY=1\n"
                   "STATUS=Waiting for network connections...");
 
-        r = sd_event_loop(event);
+        r = sd_event_loop(m->event);
         if (r < 0) {
                 log_error("Event loop failed: %s", strerror(-r));
                 goto out;
         if (r < 0) {
                 log_error("Event loop failed: %s", strerror(-r));
                 goto out;
diff --git a/src/network/networkd-wait-online.conf b/src/network/networkd-wait-online.conf
new file mode 100644 (file)
index 0000000..fa3d92f
--- /dev/null
@@ -0,0 +1,11 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+#
+# See networkd-wait-online.conf(5) for details
+
+[WaitOnline]
+#ExpectedLinks=
diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h
new file mode 100644 (file)
index 0000000..463df16
--- /dev/null
@@ -0,0 +1,41 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include "sd-event.h"
+#include "sd-rtnl.h"
+
+#include "util.h"
+
+typedef struct Manager {
+        sd_event *event;
+        sd_rtnl *rtnl;
+        char **expected_links;
+} Manager;
+
+void manager_free(Manager *m);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+#define _cleanup_manager_free_ _cleanup_(manager_freep)
+
+/* gperf lookup function */
+const struct ConfigPerfItem* wait_online_gperf_lookup(const char *key, unsigned length);
index 94876ed71f7c9b6b8356ae26359bb8e59406ef7d..3bae4b46b6801ad1faa08b9127c1fa346da09a8f 100644 (file)
@@ -39,6 +39,7 @@
 /systemd-machined.service
 /systemd-modules-load.service
 /systemd-networkd.service
 /systemd-machined.service
 /systemd-modules-load.service
 /systemd-networkd.service
+/systemd-networkd-wait-online.service
 /systemd-nspawn@.service
 /systemd-poweroff.service
 /systemd-quotacheck.service
 /systemd-nspawn@.service
 /systemd-poweroff.service
 /systemd-quotacheck.service
diff --git a/units/systemd-networkd-wait-online.service.in b/units/systemd-networkd-wait-online.service.in
new file mode 100644 (file)
index 0000000..a9bad7a
--- /dev/null
@@ -0,0 +1,23 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=Wait for Network to be Configured
+Documentation=man:systemd-networkd-wait-online.service(8)
+DefaultDependencies=no
+Conflicts=shutdown.target
+Requisite=systemd-networkd.service
+After=systemd-networkd.service
+Before=network-online.target
+
+[Service]
+Type=oneshot
+ExecStart=@rootlibexecdir@/systemd-networkd-wait-online
+RemainAfterExit=yes
+
+[Install]
+WantedBy=network-online.target
index 7fd31cf667f214df08c85b8b59211e865b0e1e69..8dd37ff769e78b76383ba92ed4aea090c449f65f 100644 (file)
@@ -23,4 +23,5 @@ CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_N
 WatchdogSec=1min
 
 [Install]
 WatchdogSec=1min
 
 [Install]
+Also=systemd-networkd-wait-online.service
 WantedBy=multi-user.target
 WantedBy=multi-user.target