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