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