[systemd-commits] 3 commits - Makefile.am src/network src/systemd

Tom Gundersen tomegun at kemper.freedesktop.org
Thu Jul 17 14:01:28 PDT 2014


 Makefile.am                                |    5 
 src/network/networkd-link.c                |    5 
 src/network/networkd-wait-online-link.c    |  156 ++++++++++++++
 src/network/networkd-wait-online-link.h    |   46 ++++
 src/network/networkd-wait-online-manager.c |  304 +++++++++++++++++++++++++++++
 src/network/networkd-wait-online.c         |  188 +----------------
 src/network/networkd-wait-online.h         |   19 +
 src/network/sd-network.c                   |  116 +++--------
 src/systemd/sd-network.h                   |   28 --
 9 files changed, 589 insertions(+), 278 deletions(-)

New commits:
commit 6dcaa6f59a39dd4acc67fc2e4873c37e2ed46430
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed Jul 16 11:05:25 2014 +0200

    sd-network: fixup api
    
    Do not expose link_is_loopback, people should just get this from rtnl directly.
    Do not expose NTP servers as IP addresses, these must be strings.
    Expose ifindex as int, not unsigned. This is what the kernel (mostly) and glibc uses.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 94683a5..328c4d8 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -2506,9 +2506,8 @@ int link_save(Link *link) {
         fprintf(f,
                 "# This is private data. Do not parse.\n"
                 "ADMIN_STATE=%s\n"
-                "OPER_STATE=%s\n"
-                "FLAGS=%u\n",
-                admin_state, oper_state, link->flags);
+                "OPER_STATE=%s\n",
+                admin_state, oper_state);
 
         if (link->network) {
                 serialize_addresses(f, "DNS", link->network->dns);
diff --git a/src/network/sd-network.c b/src/network/sd-network.c
index 50e5d9b..0844e58 100644
--- a/src/network/sd-network.c
+++ b/src/network/sd-network.c
@@ -35,46 +35,14 @@
 #include "network-internal.h"
 #include "dhcp-lease-internal.h"
 
-static int link_get_flags(unsigned index, unsigned *flags) {
+_public_ int sd_network_get_link_state(int ifindex, char **state) {
         _cleanup_free_ char *s = NULL, *p = NULL;
         int r;
 
-        assert(index);
-        assert(flags);
-
-        if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE, "FLAGS", &s, NULL);
-        if (r == -ENOENT)
-                return -ENODATA;
-        else if (r < 0)
-                return r;
-        else if (!s)
-                return -EIO;
-
-        return safe_atou(s, flags);
-}
-
-_public_ int sd_network_link_is_loopback(unsigned index) {
-        unsigned flags;
-        int r;
-
-        r = link_get_flags(index, &flags);
-        if (r < 0)
-                return 0;
-
-        return flags & IFF_LOOPBACK;
-}
-
-_public_ int sd_network_get_link_state(unsigned index, char **state) {
-        _cleanup_free_ char *s = NULL, *p = NULL;
-        int r;
-
-        assert_return(index, -EINVAL);
+        assert_return(ifindex > 0, -EINVAL);
         assert_return(state, -EINVAL);
 
-        if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
+        if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
                 return -ENOMEM;
 
         r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
@@ -115,14 +83,14 @@ _public_ int sd_network_get_operational_state(char **state) {
         return 0;
 }
 
-_public_ int sd_network_get_link_operational_state(unsigned index, char **state) {
+_public_ int sd_network_get_link_operational_state(int ifindex, char **state) {
         _cleanup_free_ char *s = NULL, *p = NULL;
         int r;
 
-        assert_return(index, -EINVAL);
+        assert_return(ifindex > 0, -EINVAL);
         assert_return(state, -EINVAL);
 
-        if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
+        if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
                 return -ENOMEM;
 
         r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
@@ -139,15 +107,15 @@ _public_ int sd_network_get_link_operational_state(unsigned index, char **state)
         return 0;
 }
 
-_public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
+_public_ int sd_network_get_dhcp_lease(int ifindex, sd_dhcp_lease **ret) {
         _cleanup_free_ char *p = NULL, *s = NULL;
         sd_dhcp_lease *lease = NULL;
         int r;
 
-        assert_return(index, -EINVAL);
+        assert_return(ifindex > 0, -EINVAL);
         assert_return(ret, -EINVAL);
 
-        if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
+        if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
                 return -ENOMEM;
 
         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
@@ -166,14 +134,14 @@ _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
         return 0;
 }
 
-static int network_get_in_addr(const char *key, unsigned index, struct in_addr **addr) {
+static int network_get_in_addr(const char *key, int ifindex, struct in_addr **addr) {
         _cleanup_free_ char *p = NULL, *s = NULL;
         int r;
 
-        assert_return(index, -EINVAL);
+        assert_return(ifindex > 0, -EINVAL);
         assert_return(addr, -EINVAL);
 
-        if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
+        if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
                 return -ENOMEM;
 
         r = parse_env_file(p, NEWLINE, key, &s, NULL);
@@ -185,22 +153,18 @@ static int network_get_in_addr(const char *key, unsigned index, struct in_addr *
         return deserialize_in_addrs(addr, s);
 }
 
-_public_ int sd_network_get_dns(unsigned index, struct in_addr **addr) {
-        return network_get_in_addr("DNS", index, addr);
-}
-
-_public_ int sd_network_get_ntp(unsigned index, struct in_addr **addr) {
-        return network_get_in_addr("NTP", index, addr);
+_public_ int sd_network_get_dns(int ifindex, struct in_addr **addr) {
+        return network_get_in_addr("DNS", ifindex, addr);
 }
 
-static int network_get_in6_addr(const char *key, unsigned index, struct in6_addr **addr) {
+static int network_get_in6_addr(const char *key, int ifindex, struct in6_addr **addr) {
         _cleanup_free_ char *p = NULL, *s = NULL;
         int r;
 
-        assert_return(index, -EINVAL);
+        assert_return(ifindex > 0, -EINVAL);
         assert_return(addr, -EINVAL);
 
-        if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
+        if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
                 return -ENOMEM;
 
         r = parse_env_file(p, NEWLINE, key, &s, NULL);
@@ -212,21 +176,17 @@ static int network_get_in6_addr(const char *key, unsigned index, struct in6_addr
         return deserialize_in6_addrs(addr, s);
 }
 
-_public_ int sd_network_get_dns6(unsigned index, struct in6_addr **addr) {
-        return network_get_in6_addr("DNS", index, addr);
-}
-
-_public_ int sd_network_get_ntp6(unsigned index, struct in6_addr **addr) {
-        return network_get_in6_addr("NTP", index, addr);
+_public_ int sd_network_get_dns6(int ifindex, struct in6_addr **addr) {
+        return network_get_in6_addr("DNS", ifindex, addr);
 }
 
-static int network_get_boolean(const char *key, unsigned index) {
+static int network_get_boolean(const char *key, int ifindex) {
         _cleanup_free_ char *p = NULL, *s = NULL;
         int r;
 
-        assert_return(index, -EINVAL);
+        assert_return(ifindex > 0, -EINVAL);
 
-        if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
+        if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
                 return -ENOMEM;
 
         r = parse_env_file(p, NEWLINE, key, &s, NULL);
@@ -238,19 +198,19 @@ static int network_get_boolean(const char *key, unsigned index) {
         return parse_boolean(s);
 }
 
-_public_ int sd_network_dhcp_use_dns(unsigned index) {
-        return network_get_boolean("DHCP_USE_DNS", index);
+_public_ int sd_network_dhcp_use_dns(int ifindex) {
+        return network_get_boolean("DHCP_USE_DNS", ifindex);
 }
 
-_public_ int sd_network_dhcp_use_ntp(unsigned index) {
-        return network_get_boolean("DHCP_USE_NTP", index);
+_public_ int sd_network_dhcp_use_ntp(int ifindex) {
+        return network_get_boolean("DHCP_USE_NTP", ifindex);
 }
 
-_public_ int sd_network_get_ifindices(unsigned **indices) {
+_public_ int sd_network_get_ifindices(int **ifindices) {
         _cleanup_closedir_ DIR *d;
         int r = 0;
         unsigned n = 0;
-        _cleanup_free_ uid_t *l = NULL;
+        _cleanup_free_ int *l = NULL;
 
         d = opendir("/run/systemd/netif/links/");
         if (!d)
@@ -259,7 +219,7 @@ _public_ int sd_network_get_ifindices(unsigned **indices) {
         for (;;) {
                 struct dirent *de;
                 int k;
-                unsigned index;
+                int ifindex;
 
                 errno = 0;
                 de = readdir(d);
@@ -274,16 +234,16 @@ _public_ int sd_network_get_ifindices(unsigned **indices) {
                 if (!dirent_is_file(de))
                         continue;
 
-                k = safe_atou(de->d_name, &index);
+                k = safe_atoi(de->d_name, &ifindex);
                 if (k < 0)
                         continue;
 
-                if (indices) {
+                if (ifindices) {
                         if ((unsigned) r >= n) {
-                                unsigned *t;
+                                int *t;
 
                                 n = MAX(16, 2*r);
-                                t = realloc(l, sizeof(unsigned) * n);
+                                t = realloc(l, sizeof(int) * n);
                                 if (!t)
                                         return -ENOMEM;
 
@@ -291,13 +251,13 @@ _public_ int sd_network_get_ifindices(unsigned **indices) {
                         }
 
                         assert((unsigned) r < n);
-                        l[r++] = index;
+                        l[r++] = ifindex;
                 } else
                         r++;
         }
 
-        if (indices) {
-                *indices = l;
+        if (ifindices) {
+                *ifindices = l;
                 l = NULL;
         }
 
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index 3f79482..0f32c44 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -57,14 +57,14 @@ _SD_BEGIN_DECLARATIONS;
  *   -ENODATA: networkd is not aware of the link
  *   -EBUSY: udev is still processing the link, networkd does not yet know if it will manage it
  */
-int sd_network_get_link_state(unsigned ifindex, char **state);
+int sd_network_get_link_state(int ifindex, char **state);
 
 /* Get operatinal state from ifindex.
  * Possible states: unknown, dormant, carrier, degraded, routable
  * Possible return codes:
  *   -ENODATA: networkd is not aware of the link
  */
-int sd_network_get_link_operational_state(unsigned ifindex, char **state);
+int sd_network_get_link_operational_state(int ifindex, char **state);
 
 /* Get overall opeartional state
  * Possible states: unknown, dormant, carrier, degraded, routable
@@ -73,33 +73,24 @@ int sd_network_get_link_operational_state(unsigned ifindex, char **state);
  */
 int sd_network_get_operational_state(char **state);
 
-/* Returns true if link exists and is loopback, and false otherwise */
-int sd_network_link_is_loopback(unsigned ifindex);
-
 /* Get DHCPv4 lease from ifindex. */
-int sd_network_get_dhcp_lease(unsigned ifindex, sd_dhcp_lease **ret);
+int sd_network_get_dhcp_lease(int ifindex, sd_dhcp_lease **ret);
 
 /* Returns true if link is configured to respect DNS entries received by DHCP */
-int sd_network_dhcp_use_dns(unsigned ifindex);
+int sd_network_dhcp_use_dns(int ifindex);
 
 /* Returns true if link is configured to respect NTP entries received by DHCP */
-int sd_network_dhcp_use_ntp(unsigned ifindex);
+int sd_network_dhcp_use_ntp(int ifindex);
 
 /* Get IPv4 DNS entries statically configured for the link */
-int sd_network_get_dns(unsigned ifindex, struct in_addr **addr);
-
-/* Get IPv4 NTP entries statically configured for the link */
-int sd_network_get_ntp(unsigned ifindex, struct in_addr **addr);
+int sd_network_get_dns(int ifindex, struct in_addr **addr);
 
 /* Get IPv6 DNS entries statically configured for the link */
-int sd_network_get_dns6(unsigned ifindex, struct in6_addr **addr);
-
-/* Get IPv6 NTP entries statically configured for the link */
-int sd_network_get_ntp6(unsigned ifindex, struct in6_addr **addr);
+int sd_network_get_dns6(int ifindex, struct in6_addr **addr);
 
 /* Get all network interfaces' indices, and store them in *indices. Returns
  * the number of indices. If indices is NULL, only returns the number of indices. */
-int sd_network_get_ifindices(unsigned **ifindices);
+int sd_network_get_ifindices(int **ifindices);
 
 /* Monitor object */
 typedef struct sd_network_monitor sd_network_monitor;

commit 7de12ae764e73730df0658f9fb04bcf42add48e2
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed Jul 16 10:52:47 2014 +0200

    networkd-wait-online: track links
    
    Rather than refetching the link information on ever event, we liston to
    rtnl to track them. Much code stolen from resolved.
    
    This will allow us to simplify the sd-network api and don't expose
    information available over rtnl.

diff --git a/Makefile.am b/Makefile.am
index 88f468c..2b22869 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4818,8 +4818,11 @@ systemd_networkd_wait_online_CFLAGS = \
 
 systemd_networkd_wait_online_SOURCES = \
 	src/libsystemd-network/network-internal.h \
+	src/network/networkd-wait-online.h \
+	src/network/networkd-wait-online-link.h \
 	src/network/networkd-wait-online.c \
-	src/network/networkd-wait-online.h
+	src/network/networkd-wait-online-manager.c \
+	src/network/networkd-wait-online-link.c
 
 systemd_networkd_wait_online_LDADD = \
 	libsystemd-network.la \
diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c
new file mode 100644
index 0000000..9dc95f5
--- /dev/null
+++ b/src/network/networkd-wait-online-link.c
@@ -0,0 +1,156 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+  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/>.
+***/
+
+#include <net/if.h>
+
+#include "sd-network.h"
+#include "strv.h"
+
+#include "networkd-wait-online-link.h"
+
+int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
+        _cleanup_(link_freep) Link *l = NULL;
+        int r;
+
+        assert(m);
+        assert(ifindex > 0);
+
+        r = hashmap_ensure_allocated(&m->links, NULL, NULL);
+        if (r < 0)
+                return r;
+
+        r = hashmap_ensure_allocated(&m->links_by_name,
+                                     string_hash_func, string_compare_func);
+        if (r < 0)
+                return r;
+
+        l = new0(Link, 1);
+        if (!l)
+                return -ENOMEM;
+
+        l->manager = m;
+
+        l->ifname = strdup(ifname);
+        if (!l->ifname)
+                return -ENOMEM;
+
+        r = hashmap_put(m->links_by_name, l->ifname, l);
+        if (r < 0)
+                return r;
+
+        l->ifindex = ifindex;
+
+        r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
+        if (r < 0)
+                return r;
+
+        if (ret)
+                *ret = l;
+        l = NULL;
+
+        return 0;
+}
+
+Link *link_free(Link *l) {
+
+        if (!l)
+                return NULL;
+
+        if (l->manager) {
+                hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
+                hashmap_remove(l->manager->links_by_name, l->ifname);
+        }
+
+        free(l->ifname);
+        free(l);
+        return NULL;
+ }
+
+int link_update_rtnl(Link *l, sd_rtnl_message *m) {
+        char *ifname;
+        int r;
+
+        assert(l);
+        assert(l->manager);
+        assert(m);
+
+        r = sd_rtnl_message_link_get_flags(m, &l->flags);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
+        if (r < 0)
+                return r;
+
+        if (!streq(l->ifname, ifname)) {
+                char *new_ifname;
+
+                new_ifname = strdup(ifname);
+                if (!new_ifname)
+                        return -ENOMEM;
+
+                hashmap_remove(l->manager->links_by_name, l->ifname);
+                free(l->ifname);
+                l->ifname = new_ifname;
+
+                r = hashmap_put(l->manager->links_by_name, l->ifname, l);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int link_update_monitor(Link *l) {
+        assert(l);
+
+        free(l->operational_state);
+        l->operational_state = NULL;
+
+        sd_network_get_link_operational_state(l->ifindex, &l->operational_state);
+
+        free(l->state);
+        l->state = NULL;
+
+        sd_network_get_link_state(l->ifindex, &l->state);
+
+        return 0;
+}
+
+bool link_relevant(Link *l) {
+        assert(l);
+
+        /* A link is relevant if it isn't a loopback device and has at
+         * least one relevant IP address */
+
+        if (l->flags & IFF_LOOPBACK)
+                return false;
+/*
+        if (l->operational_state && !STR_IN_SET(l->operational_state, "unknown", "degraded", "routable"))
+                return false;
+
+        LIST_FOREACH(addresses, a, l->addresses)
+                if (link_address_relevant(a))
+                        return true;
+*/
+        return true;
+}
diff --git a/src/network/networkd-wait-online-link.h b/src/network/networkd-wait-online-link.h
new file mode 100644
index 0000000..90ea6b3
--- /dev/null
+++ b/src/network/networkd-wait-online-link.h
@@ -0,0 +1,46 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+  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/>.
+***/
+
+typedef struct Link Link;
+
+#include "networkd-wait-online.h"
+
+struct Link {
+        Manager *manager;
+
+        int ifindex;
+        char *ifname;
+        unsigned flags;
+
+        char *operational_state;
+        char *state;
+};
+
+int link_new(Manager *m, Link **ret, int ifindex, const char *ifname);
+Link *link_free(Link *l);
+int link_update_rtnl(Link *l, sd_rtnl_message *m);
+int link_update_monitor(Link *l);
+bool link_relevant(Link *l);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free);
diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c
new file mode 100644
index 0000000..649a21c
--- /dev/null
+++ b/src/network/networkd-wait-online-manager.c
@@ -0,0 +1,304 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at 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/>.
+***/
+
+#include <netinet/ether.h>
+#include <linux/if.h>
+
+#include "rtnl-util.h"
+
+#include "network-util.h"
+#include "network-internal.h"
+#include "networkd-wait-online-link.h"
+#include "networkd-wait-online.h"
+
+#include "util.h"
+
+bool manager_all_configured(Manager *m) {
+        Iterator i;
+        Link *l;
+        char **ifname;
+        bool one_ready = false;
+
+        /* wait for all the links given on the commandline to appear */
+        STRV_FOREACH(ifname, m->interfaces) {
+                l = hashmap_get(m->links_by_name, *ifname);
+                if (!l) {
+                        log_debug("still waiting for %s", *ifname);
+                        return false;
+                }
+        }
+
+        /* wait for all links networkd manages to be in admin state 'configured'
+           and at least one link to gain a carrier */
+        HASHMAP_FOREACH(l, m->links, i) {
+                if (!link_relevant(l)) {
+                        log_info("ignore irrelevant link: %s", l->ifname);
+                        continue;
+                }
+
+                if (!l->state) {
+                        log_debug("link %s has not yet been processed by udev",
+                                  l->ifname);
+                        return false;
+                }
+
+                if (streq(l->state, "configuring")) {
+                        log_debug("link %s is being processed by networkd",
+                                  l->ifname);
+                        return false;
+                }
+
+                if (l->operational_state &&
+                    STR_IN_SET(l->operational_state, "degraded", "routable"))
+                        /* we wait for at least one link to be ready,
+                           regardless of who manages it */
+                        one_ready = true;
+        }
+
+        return one_ready;
+}
+
+static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
+        Manager *m = userdata;
+        uint16_t type;
+        Link *l;
+        char *ifname;
+        int ifindex, r;
+
+        assert(rtnl);
+        assert(m);
+        assert(mm);
+
+        r = sd_rtnl_message_get_type(mm, &type);
+        if (r < 0)
+                goto fail;
+
+        r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
+        if (r < 0)
+                goto fail;
+
+        r = sd_rtnl_message_read_string(mm, IFLA_IFNAME, &ifname);
+        if (r < 0)
+                goto fail;
+
+        l = hashmap_get(m->links, INT_TO_PTR(ifindex));
+
+        switch (type) {
+
+        case RTM_NEWLINK:
+                if (!l) {
+                        log_debug("Found link %i", ifindex);
+
+                        r = link_new(m, &l, ifindex, ifname);
+                        if (r < 0)
+                                goto fail;
+
+                        r = link_update_monitor(l);
+                        if (r < 0)
+                                goto fail;
+                }
+
+                r = link_update_rtnl(l, mm);
+                if (r < 0)
+                        goto fail;
+
+                break;
+
+        case RTM_DELLINK:
+                if (l) {
+                        log_debug("Removing link %i", l->ifindex);
+                        link_free(l);
+                }
+
+                break;
+        }
+
+        return 0;
+
+fail:
+        log_warning("Failed to process RTNL link message: %s", strerror(-r));
+        return 0;
+}
+
+static int on_rtnl_event(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
+        Manager *m = userdata;
+        int r;
+
+        r = manager_process_link(rtnl, mm, m);
+        if (r < 0)
+                return r;
+
+        if (manager_all_configured(m))
+                sd_event_exit(m->event, 0);
+
+        return 1;
+}
+
+static int manager_rtnl_listen(Manager *m) {
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+        sd_rtnl_message *i;
+        int r;
+
+        assert(m);
+
+        /* First, subscibe to interfaces coming and going */
+        r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, on_rtnl_event, m);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, on_rtnl_event, m);
+        if (r < 0)
+                return r;
+
+        /* Then, enumerate all links */
+        r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_message_request_dump(req, true);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_call(m->rtnl, req, 0, &reply);
+        if (r < 0)
+                return r;
+
+        for (i = reply; i; i = sd_rtnl_message_next(i)) {
+                r = manager_process_link(m->rtnl, i, m);
+                if (r < 0)
+                        return r;
+        }
+
+        return r;
+}
+
+static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        Manager *m = userdata;
+        Iterator i;
+        Link *l;
+        int r;
+
+        assert(m);
+
+        sd_network_monitor_flush(m->network_monitor);
+
+        HASHMAP_FOREACH(l, m->links, i) {
+                r = link_update_monitor(l);
+                if (r < 0)
+                        log_warning("Failed to update monitor information for %i: %s", l->ifindex, strerror(-r));
+        }
+
+        if (manager_all_configured(m))
+                sd_event_exit(m->event, 0);
+
+        return 0;
+}
+
+static int manager_network_monitor_listen(Manager *m) {
+        int r, fd, events;
+
+        assert(m);
+
+        r = sd_network_monitor_new(&m->network_monitor, NULL);
+        if (r < 0)
+                return r;
+
+        fd = sd_network_monitor_get_fd(m->network_monitor);
+        if (fd < 0)
+                return fd;
+
+        events = sd_network_monitor_get_events(m->network_monitor);
+        if (events < 0)
+                return events;
+
+        r = sd_event_add_io(m->event, &m->network_monitor_event_source,
+                            fd, events, &on_network_event, m);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int manager_new(Manager **ret, char **interfaces) {
+        _cleanup_(manager_freep) Manager *m = NULL;
+        int r;
+
+        assert(ret);
+
+        m = new0(Manager, 1);
+        if (!m)
+                return -ENOMEM;
+
+        m->interfaces = interfaces;
+
+        r = sd_event_default(&m->event);
+        if (r < 0)
+                return r;
+
+        sd_event_add_signal(m->event, NULL, SIGTERM, NULL,  NULL);
+        sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+
+        sd_event_set_watchdog(m->event, true);
+
+        r = manager_network_monitor_listen(m);
+        if (r < 0)
+                return r;
+
+        r = manager_rtnl_listen(m);
+        if (r < 0)
+                return r;
+
+        *ret = m;
+        m = NULL;
+
+        return 0;
+}
+
+void manager_free(Manager *m) {
+        Link *l;
+
+        if (!m)
+                return;
+
+        while ((l = hashmap_first(m->links)))
+               link_free(l);
+        hashmap_free(m->links);
+        hashmap_free(m->links_by_name);
+
+        sd_event_source_unref(m->network_monitor_event_source);
+        sd_network_monitor_unref(m->network_monitor);
+
+        sd_event_source_unref(m->rtnl_event_source);
+        sd_rtnl_unref(m->rtnl);
+
+        sd_event_unref(m->event);
+        free(m);
+
+        return;
+}
diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c
index c4783ca..d588935 100644
--- a/src/network/networkd-wait-online.c
+++ b/src/network/networkd-wait-online.c
@@ -1,4 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
 /***
   This file is part of systemd.
@@ -19,23 +18,13 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <netinet/ether.h>
-#include <linux/if.h>
 #include <getopt.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 "network-internal.h"
+
 #include "networkd-wait-online.h"
 
-#include "conf-parser.h"
 #include "strv.h"
-#include "util.h"
 #include "build.h"
 
 static bool arg_quiet = false;
@@ -106,129 +95,16 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
-static bool all_configured(Manager *m) {
-        _cleanup_free_ unsigned *indices = NULL;
-        char **ifname;
-        bool one_ready = false;
-        int r, n, i;
-
-        n = sd_network_get_ifindices(&indices);
-        if (n <= 0)
-                return false;
-
-        /* wait for networkd to be aware of all the links given on the commandline */
-        STRV_FOREACH(ifname, arg_interfaces) {
-                _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("could 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;
-                }
-        }
-
-        /* wait for all links networkd manages to be in admin state 'configured'
-           and at least one link to gain a carrier */
-        for (i = 0; i < n; i++) {
-                _cleanup_free_ char *state = NULL, *oper_state = NULL;
-
-                if (sd_network_link_is_loopback(indices[i]))
-                        /* ignore loopback devices */
-                        continue;
-
-                r = sd_network_get_link_state(indices[i], &state);
-                if (r == -EBUSY || (r >= 0 && !streq(state, "configured")))
-                        /* not yet processed by udev, or managed by networkd, but not yet configured */
-                        return false;
-
-                r = sd_network_get_link_operational_state(indices[i], &oper_state);
-                if (r >= 0 &&
-                    (streq(oper_state, "degraded") ||
-                     streq(oper_state, "routable")))
-                        /* we wait for at least one link to be ready,
-                           regardless of who manages it */
-                        one_ready = true;
-        }
-
-        return one_ready;
-}
-
-static int monitor_event_handler(sd_event_source *s, int fd, uint32_t revents,
-                         void *userdata) {
-        Manager *m = userdata;
-
-        assert(m);
-        assert(m->event);
-
-        if (all_configured(m))
-                sd_event_exit(m->event, 0);
-
-        sd_network_monitor_flush(m->monitor);
-
-        return 1;
-}
-
-void manager_free(Manager *m) {
-        if (!m)
-                return;
-
-        sd_event_unref(m->event);
-        sd_rtnl_unref(m->rtnl);
-
-        free(m);
-}
-
 int main(int argc, char *argv[]) {
-        _cleanup_manager_free_ Manager *m = NULL;
-        _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
-        int r, fd, events;
-
-        umask(0022);
+        _cleanup_(manager_freep) Manager *m = NULL;
+        int r;
 
+        log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
         log_open();
 
+        umask(0022);
+
         r = parse_argv(argc, argv);
         if (r <= 0)
                 return r;
@@ -236,50 +112,17 @@ int main(int argc, char *argv[]) {
         if (arg_quiet)
                 log_set_max_level(LOG_WARNING);
 
-        m = new0(Manager, 1);
-        if (!m)
-                return log_oom();
+        assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
 
-        r = sd_event_new(&m->event);
+        r = manager_new(&m, arg_interfaces);
         if (r < 0) {
-                log_error("Could not create event: %s", strerror(-r));
-                goto out;
+                log_error("Could not create manager: %s", strerror(-r));
+                goto finish;
         }
 
-        r = sd_rtnl_open(&m->rtnl, 0);
-        if (r < 0) {
-                log_error("Could not create rtnl: %s", strerror(-r));
-                goto out;
-        }
-
-        r = sd_network_monitor_new(&m->monitor, NULL);
-        if (r < 0) {
-                log_error("Could not create monitor: %s", strerror(-r));
-                goto out;
-        }
-
-        fd = sd_network_monitor_get_fd(m->monitor);
-        if (fd < 0) {
-                log_error("Could not get monitor fd: %s", strerror(-r));
-                goto out;
-        }
-
-        events = sd_network_monitor_get_events(m->monitor);
-        if (events < 0) {
-                log_error("Could not get monitor events: %s", strerror(-r));
-                goto out;
-        }
-
-        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 (all_configured(m)) {
+        if (manager_all_configured(m)) {
                 r = 0;
-                goto out;
+                goto finish;
         }
 
         sd_notify(false,
@@ -289,12 +132,11 @@ int main(int argc, char *argv[]) {
         r = sd_event_loop(m->event);
         if (r < 0) {
                 log_error("Event loop failed: %s", strerror(-r));
-                goto out;
+                goto finish;
         }
 
-out:
-        sd_notify(false,
-                  "STATUS=All interfaces configured...");
+finish:
+        sd_notify(false, "STATUS=All interfaces configured...");
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h
index e894351..c57f902 100644
--- a/src/network/networkd-wait-online.h
+++ b/src/network/networkd-wait-online.h
@@ -23,16 +23,29 @@
 
 #include "sd-event.h"
 #include "sd-rtnl.h"
+#include "sd-network.h"
 
 #include "util.h"
+#include "hashmap.h"
 
 typedef struct Manager {
-        sd_event *event;
+        Hashmap *links;
+        Hashmap *links_by_name;
+
+        char **interfaces;
+
         sd_rtnl *rtnl;
-        sd_network_monitor *monitor;
+        sd_event_source *rtnl_event_source;
+
+        sd_network_monitor *network_monitor;
+        sd_event_source *network_monitor_event_source;
+
+        sd_event *event;
 } Manager;
 
 void manager_free(Manager *m);
+int manager_new(Manager **ret, char **interfaces);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
-#define _cleanup_manager_free_ _cleanup_(manager_freep)
+
+bool manager_all_configured(Manager *m);

commit 560852ced07a647e2d288ce2932aaf608712867d
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu Jul 17 16:49:39 2014 +0200

    sd-network: expose 'unmanaged' as a regular state
    
    This is useful to save in the consumer of the lib, unlike ENODATA/EBUSY which
    means that the user should wait until a useful state is available.

diff --git a/src/network/sd-network.c b/src/network/sd-network.c
index 1b7518f..50e5d9b 100644
--- a/src/network/sd-network.c
+++ b/src/network/sd-network.c
@@ -85,9 +85,7 @@ _public_ int sd_network_get_link_state(unsigned index, char **state) {
         else if (!s)
                 return -EIO;
 
-        if (streq(s, "unmanaged"))
-                return -EUNATCH;
-        else if (streq(s, "initializing"))
+        if (streq(s, "initializing"))
                 return -EBUSY;
 
         *state = s;
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index 45fd3ce..3f79482 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -52,10 +52,9 @@
 _SD_BEGIN_DECLARATIONS;
 
 /* Get state from ifindex.
- * Possible states: failed, configuring, configured
+ * Possible states: failed, configuring, configured, unmanaged
  * Possible return codes:
  *   -ENODATA: networkd is not aware of the link
- *   -EUNATCH: networkd is not managing this link
  *   -EBUSY: udev is still processing the link, networkd does not yet know if it will manage it
  */
 int sd_network_get_link_state(unsigned ifindex, char **state);



More information about the systemd-commits mailing list