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