]> git.ipfire.org Git - thirdparty/systemd.git/blame - 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
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
7de12ae7
TG
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>
5d8689d7 23#include <fnmatch.h>
7de12ae7 24
b5efdb8a 25#include "alloc-util.h"
c5fcf6e4
TG
26#include "link.h"
27#include "manager.h"
1c4baffc 28#include "netlink-util.h"
7de12ae7 29#include "network-internal.h"
e56cdb7a 30#include "time-util.h"
b5efdb8a 31#include "util.h"
7de12ae7 32
79b1f37d
TG
33bool manager_ignore_link(Manager *m, Link *link) {
34 assert(m);
35 assert(link);
36
be0c1370 37 /* always ignore the loopback interface */
79b1f37d
TG
38 if (link->flags & IFF_LOOPBACK)
39 return true;
40
be0c1370
TG
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 */
03fb3334 46 return strv_fnmatch(m->ignore, link->ifname, 0);
79b1f37d
TG
47}
48
7de12ae7
TG
49bool manager_all_configured(Manager *m) {
50 Iterator i;
51 Link *l;
52 char **ifname;
53 bool one_ready = false;
54
3f85ef0f 55 /* wait for all the links given on the command line to appear */
7de12ae7
TG
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) {
79b1f37d
TG
67 if (manager_ignore_link(m, l)) {
68 log_info("ignoring: %s", l->ifname);
7de12ae7
TG
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
79ac8ba9 78 if (STR_IN_SET(l->state, "configuring", "pending")) {
7de12ae7
TG
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
1c4baffc 94static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
7de12ae7
TG
95 Manager *m = userdata;
96 uint16_t type;
97 Link *l;
d2437732 98 const char *ifname;
7de12ae7
TG
99 int ifindex, r;
100
101 assert(rtnl);
102 assert(m);
103 assert(mm);
104
1c4baffc 105 r = sd_netlink_message_get_type(mm, &type);
7de12ae7
TG
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
1c4baffc 113 r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname);
7de12ae7
TG
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
151fail:
da927ba9 152 log_warning_errno(r, "Failed to process RTNL link message: %m");
7de12ae7
TG
153 return 0;
154}
155
1c4baffc 156static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
7de12ae7
TG
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
170static int manager_rtnl_listen(Manager *m) {
4afd3348 171 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1c4baffc 172 sd_netlink_message *i;
7de12ae7
TG
173 int r;
174
175 assert(m);
176
6fb2f9ab 177 /* First, subscribe to interfaces coming and going */
1c4baffc 178 r = sd_netlink_open(&m->rtnl);
7de12ae7
TG
179 if (r < 0)
180 return r;
181
1c4baffc 182 r = sd_netlink_attach_event(m->rtnl, m->event, 0);
7de12ae7
TG
183 if (r < 0)
184 return r;
185
1c4baffc 186 r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, on_rtnl_event, m);
7de12ae7
TG
187 if (r < 0)
188 return r;
189
1c4baffc 190 r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, on_rtnl_event, m);
7de12ae7
TG
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
1c4baffc 199 r = sd_netlink_message_request_dump(req, true);
7de12ae7
TG
200 if (r < 0)
201 return r;
202
1c4baffc 203 r = sd_netlink_call(m->rtnl, req, 0, &reply);
7de12ae7
TG
204 if (r < 0)
205 return r;
206
1c4baffc 207 for (i = reply; i; i = sd_netlink_message_next(i)) {
7de12ae7
TG
208 r = manager_process_link(m->rtnl, i, m);
209 if (r < 0)
210 return r;
211 }
212
213 return r;
214}
215
216static 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)
da927ba9 229 log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
7de12ae7
TG
230 }
231
232 if (manager_all_configured(m))
233 sd_event_exit(m->event, 0);
234
235 return 0;
236}
237
238static 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
e56cdb7a 263int manager_new(Manager **ret, char **interfaces, char **ignore, usec_t timeout) {
7de12ae7
TG
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;
79b1f37d 274 m->ignore = ignore;
7de12ae7
TG
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
e56cdb7a
TG
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
7de12ae7
TG
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
309void 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);
1c4baffc 324 sd_netlink_unref(m->rtnl);
7de12ae7
TG
325
326 sd_event_unref(m->event);
327 free(m);
328
329 return;
330}