chiark / gitweb /
networkd-wait-online: track links
authorTom Gundersen <teg@jklm.no>
Wed, 16 Jul 2014 08:52:47 +0000 (10:52 +0200)
committerTom Gundersen <teg@jklm.no>
Thu, 17 Jul 2014 20:53:35 +0000 (22:53 +0200)
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.

Makefile.am
src/network/networkd-wait-online-link.c [new file with mode: 0644]
src/network/networkd-wait-online-link.h [new file with mode: 0644]
src/network/networkd-wait-online-manager.c [new file with mode: 0644]
src/network/networkd-wait-online.c
src/network/networkd-wait-online.h

index 88f468c..2b22869 100644 (file)
@@ -4818,8 +4818,11 @@ systemd_networkd_wait_online_CFLAGS = \
 
 systemd_networkd_wait_online_SOURCES = \
        src/libsystemd-network/network-internal.h \
 
 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.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 \
 
 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 (file)
index 0000000..9dc95f5
--- /dev/null
@@ -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 (file)
index 0000000..90ea6b3
--- /dev/null
@@ -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 (file)
index 0000000..649a21c
--- /dev/null
@@ -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@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;
+}
index c4783ca..d588935 100644 (file)
@@ -1,4 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
 /***
   This file is part of systemd.
 
 /***
   This file is part of systemd.
   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 <getopt.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-daemon.h"
-#include "sd-network.h"
-#include "network-util.h"
-#include "network-internal.h"
+
 #include "networkd-wait-online.h"
 
 #include "networkd-wait-online.h"
 
-#include "conf-parser.h"
 #include "strv.h"
 #include "strv.h"
-#include "util.h"
 #include "build.h"
 
 static bool arg_quiet = false;
 #include "build.h"
 
 static bool arg_quiet = false;
@@ -106,129 +95,16 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
         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[]) {
 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();
 
         log_parse_environment();
         log_open();
 
+        umask(0022);
+
         r = parse_argv(argc, argv);
         if (r <= 0)
                 return r;
         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);
 
         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) {
         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;
                 r = 0;
-                goto out;
+                goto finish;
         }
 
         sd_notify(false,
         }
 
         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));
         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;
 }
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index e894351..c57f902 100644 (file)
 
 #include "sd-event.h"
 #include "sd-rtnl.h"
 
 #include "sd-event.h"
 #include "sd-rtnl.h"
+#include "sd-network.h"
 
 #include "util.h"
 
 #include "util.h"
+#include "hashmap.h"
 
 typedef struct Manager {
 
 typedef struct Manager {
-        sd_event *event;
+        Hashmap *links;
+        Hashmap *links_by_name;
+
+        char **interfaces;
+
         sd_rtnl *rtnl;
         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);
 } Manager;
 
 void manager_free(Manager *m);
+int manager_new(Manager **ret, char **interfaces);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
-#define _cleanup_manager_free_ _cleanup_(manager_freep)
+
+bool manager_all_configured(Manager *m);