chiark / gitweb /
tmpfiles: Fix parse_acl error message
[elogind.git] / src / network / networkd-wait-online-manager.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/ether.h>
23 #include <linux/if.h>
24 #include <fnmatch.h>
25
26 #include "rtnl-util.h"
27
28 #include "network-util.h"
29 #include "network-internal.h"
30 #include "networkd-wait-online-link.h"
31 #include "networkd-wait-online.h"
32
33 #include "util.h"
34 #include "time-util.h"
35
36 bool manager_ignore_link(Manager *m, Link *link) {
37         char **ignore;
38
39         assert(m);
40         assert(link);
41
42         if (link->flags & IFF_LOOPBACK)
43                 return true;
44
45         STRV_FOREACH(ignore, m->ignore)
46                 if (fnmatch(*ignore, link->ifname, 0) == 0)
47                         return true;
48
49         return false;
50 }
51
52 bool manager_all_configured(Manager *m) {
53         Iterator i;
54         Link *l;
55         char **ifname;
56         bool one_ready = false;
57
58         /* wait for all the links given on the command line to appear */
59         STRV_FOREACH(ifname, m->interfaces) {
60                 l = hashmap_get(m->links_by_name, *ifname);
61                 if (!l) {
62                         log_debug("still waiting for %s", *ifname);
63                         return false;
64                 }
65         }
66
67         /* wait for all links networkd manages to be in admin state 'configured'
68            and at least one link to gain a carrier */
69         HASHMAP_FOREACH(l, m->links, i) {
70                 if (manager_ignore_link(m, l)) {
71                         log_info("ignoring: %s", l->ifname);
72                         continue;
73                 }
74
75                 if (!l->state) {
76                         log_debug("link %s has not yet been processed by udev",
77                                   l->ifname);
78                         return false;
79                 }
80
81                 if (streq(l->state, "configuring")) {
82                         log_debug("link %s is being processed by networkd",
83                                   l->ifname);
84                         return false;
85                 }
86
87                 if (l->operational_state &&
88                     STR_IN_SET(l->operational_state, "degraded", "routable"))
89                         /* we wait for at least one link to be ready,
90                            regardless of who manages it */
91                         one_ready = true;
92         }
93
94         return one_ready;
95 }
96
97 static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
98         Manager *m = userdata;
99         uint16_t type;
100         Link *l;
101         const char *ifname;
102         int ifindex, r;
103
104         assert(rtnl);
105         assert(m);
106         assert(mm);
107
108         r = sd_rtnl_message_get_type(mm, &type);
109         if (r < 0)
110                 goto fail;
111
112         r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
113         if (r < 0)
114                 goto fail;
115
116         r = sd_rtnl_message_read_string(mm, IFLA_IFNAME, &ifname);
117         if (r < 0)
118                 goto fail;
119
120         l = hashmap_get(m->links, INT_TO_PTR(ifindex));
121
122         switch (type) {
123
124         case RTM_NEWLINK:
125                 if (!l) {
126                         log_debug("Found link %i", ifindex);
127
128                         r = link_new(m, &l, ifindex, ifname);
129                         if (r < 0)
130                                 goto fail;
131
132                         r = link_update_monitor(l);
133                         if (r < 0)
134                                 goto fail;
135                 }
136
137                 r = link_update_rtnl(l, mm);
138                 if (r < 0)
139                         goto fail;
140
141                 break;
142
143         case RTM_DELLINK:
144                 if (l) {
145                         log_debug("Removing link %i", l->ifindex);
146                         link_free(l);
147                 }
148
149                 break;
150         }
151
152         return 0;
153
154 fail:
155         log_warning_errno(r, "Failed to process RTNL link message: %m");
156         return 0;
157 }
158
159 static int on_rtnl_event(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
160         Manager *m = userdata;
161         int r;
162
163         r = manager_process_link(rtnl, mm, m);
164         if (r < 0)
165                 return r;
166
167         if (manager_all_configured(m))
168                 sd_event_exit(m->event, 0);
169
170         return 1;
171 }
172
173 static int manager_rtnl_listen(Manager *m) {
174         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
175         sd_rtnl_message *i;
176         int r;
177
178         assert(m);
179
180         /* First, subscribe to interfaces coming and going */
181         r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
182         if (r < 0)
183                 return r;
184
185         r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
186         if (r < 0)
187                 return r;
188
189         r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, on_rtnl_event, m);
190         if (r < 0)
191                 return r;
192
193         r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, on_rtnl_event, m);
194         if (r < 0)
195                 return r;
196
197         /* Then, enumerate all links */
198         r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
199         if (r < 0)
200                 return r;
201
202         r = sd_rtnl_message_request_dump(req, true);
203         if (r < 0)
204                 return r;
205
206         r = sd_rtnl_call(m->rtnl, req, 0, &reply);
207         if (r < 0)
208                 return r;
209
210         for (i = reply; i; i = sd_rtnl_message_next(i)) {
211                 r = manager_process_link(m->rtnl, i, m);
212                 if (r < 0)
213                         return r;
214         }
215
216         return r;
217 }
218
219 static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
220         Manager *m = userdata;
221         Iterator i;
222         Link *l;
223         int r;
224
225         assert(m);
226
227         sd_network_monitor_flush(m->network_monitor);
228
229         HASHMAP_FOREACH(l, m->links, i) {
230                 r = link_update_monitor(l);
231                 if (r < 0)
232                         log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
233         }
234
235         if (manager_all_configured(m))
236                 sd_event_exit(m->event, 0);
237
238         return 0;
239 }
240
241 static int manager_network_monitor_listen(Manager *m) {
242         int r, fd, events;
243
244         assert(m);
245
246         r = sd_network_monitor_new(&m->network_monitor, NULL);
247         if (r < 0)
248                 return r;
249
250         fd = sd_network_monitor_get_fd(m->network_monitor);
251         if (fd < 0)
252                 return fd;
253
254         events = sd_network_monitor_get_events(m->network_monitor);
255         if (events < 0)
256                 return events;
257
258         r = sd_event_add_io(m->event, &m->network_monitor_event_source,
259                             fd, events, &on_network_event, m);
260         if (r < 0)
261                 return r;
262
263         return 0;
264 }
265
266 int manager_new(Manager **ret, char **interfaces, char **ignore, usec_t timeout) {
267         _cleanup_(manager_freep) Manager *m = NULL;
268         int r;
269
270         assert(ret);
271
272         m = new0(Manager, 1);
273         if (!m)
274                 return -ENOMEM;
275
276         m->interfaces = interfaces;
277         m->ignore = ignore;
278
279         r = sd_event_default(&m->event);
280         if (r < 0)
281                 return r;
282
283         sd_event_add_signal(m->event, NULL, SIGTERM, NULL,  NULL);
284         sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
285
286         if (timeout > 0) {
287                 usec_t usec;
288
289                 usec = now(clock_boottime_or_monotonic()) + timeout;
290
291                 r = sd_event_add_time(m->event, NULL, clock_boottime_or_monotonic(), usec, 0, NULL, INT_TO_PTR(-ETIMEDOUT));
292                 if (r < 0)
293                         return r;
294         }
295
296         sd_event_set_watchdog(m->event, true);
297
298         r = manager_network_monitor_listen(m);
299         if (r < 0)
300                 return r;
301
302         r = manager_rtnl_listen(m);
303         if (r < 0)
304                 return r;
305
306         *ret = m;
307         m = NULL;
308
309         return 0;
310 }
311
312 void manager_free(Manager *m) {
313         Link *l;
314
315         if (!m)
316                 return;
317
318         while ((l = hashmap_first(m->links)))
319                link_free(l);
320         hashmap_free(m->links);
321         hashmap_free(m->links_by_name);
322
323         sd_event_source_unref(m->network_monitor_event_source);
324         sd_network_monitor_unref(m->network_monitor);
325
326         sd_event_source_unref(m->rtnl_event_source);
327         sd_rtnl_unref(m->rtnl);
328
329         sd_event_unref(m->event);
330         free(m);
331
332         return;
333 }