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