]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/wait-online/manager.c
tree-wide: beautify remaining copyright statements
[thirdparty/systemd.git] / src / network / wait-online / manager.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright © 2013 Tom Gundersen <teg@jklm.no>
4 ***/
5
6 #include <netinet/ether.h>
7 #include <linux/if.h>
8 #include <fnmatch.h>
9
10 #include "alloc-util.h"
11 #include "link.h"
12 #include "manager.h"
13 #include "netlink-util.h"
14 #include "network-internal.h"
15 #include "time-util.h"
16 #include "util.h"
17
18 bool manager_ignore_link(Manager *m, Link *link) {
19 assert(m);
20 assert(link);
21
22 /* always ignore the loopback interface */
23 if (link->flags & IFF_LOOPBACK)
24 return true;
25
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
30 if (!link->required_for_online)
31 return true;
32
33 /* ignore interfaces we explicitly are asked to ignore */
34 return strv_fnmatch(m->ignore, link->ifname, 0);
35 }
36
37 bool manager_all_configured(Manager *m) {
38 Iterator i;
39 Link *l;
40 char **ifname;
41 bool one_ready = false;
42
43 /* wait for all the links given on the command line to appear */
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) {
55 if (manager_ignore_link(m, l)) {
56 log_info("ignoring: %s", l->ifname);
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
66 if (STR_IN_SET(l->state, "configuring", "pending")) {
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
82 static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
83 Manager *m = userdata;
84 uint16_t type;
85 Link *l;
86 const char *ifname;
87 int ifindex, r;
88
89 assert(rtnl);
90 assert(m);
91 assert(mm);
92
93 r = sd_netlink_message_get_type(mm, &type);
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
101 r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname);
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
139 fail:
140 log_warning_errno(r, "Failed to process RTNL link message: %m");
141 return 0;
142 }
143
144 static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
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
158 static int manager_rtnl_listen(Manager *m) {
159 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
160 sd_netlink_message *i;
161 int r;
162
163 assert(m);
164
165 /* First, subscribe to interfaces coming and going */
166 r = sd_netlink_open(&m->rtnl);
167 if (r < 0)
168 return r;
169
170 r = sd_netlink_attach_event(m->rtnl, m->event, 0);
171 if (r < 0)
172 return r;
173
174 r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, on_rtnl_event, m);
175 if (r < 0)
176 return r;
177
178 r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, on_rtnl_event, m);
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
187 r = sd_netlink_message_request_dump(req, true);
188 if (r < 0)
189 return r;
190
191 r = sd_netlink_call(m->rtnl, req, 0, &reply);
192 if (r < 0)
193 return r;
194
195 for (i = reply; i; i = sd_netlink_message_next(i)) {
196 r = manager_process_link(m->rtnl, i, m);
197 if (r < 0)
198 return r;
199 }
200
201 return r;
202 }
203
204 static 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)
217 log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
218 }
219
220 if (manager_all_configured(m))
221 sd_event_exit(m->event, 0);
222
223 return 0;
224 }
225
226 static 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
251 int manager_new(Manager **ret, char **interfaces, char **ignore, usec_t timeout) {
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;
262 m->ignore = ignore;
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
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
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
291 *ret = TAKE_PTR(m);
292
293 return 0;
294 }
295
296 void 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);
311 sd_netlink_unref(m->rtnl);
312
313 sd_event_unref(m->event);
314 free(m);
315
316 return;
317 }