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