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