1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/ether.h>
4 #include <linux/if.h>
5 #include <fnmatch.h>
6
7 #include "alloc-util.h"
8 #include "link.h"
9 #include "manager.h"
10 #include "netlink-util.h"
11 #include "strv.h"
12 #include "time-util.h"
13 #include "util.h"
14
manager_ignore_link(Manager * m,Link * link)15 static bool manager_ignore_link(Manager *m, Link *link) {
16 assert(m);
17 assert(link);
18
19 /* always ignore the loopback interface */
20 if (link->flags & IFF_LOOPBACK)
21 return true;
22
23 /* if interfaces are given on the command line, ignore all others */
24 if (m->command_line_interfaces_by_name &&
25 !hashmap_contains(m->command_line_interfaces_by_name, link->ifname))
26 return true;
27
28 if (!link->required_for_online)
29 return true;
30
31 /* ignore interfaces we explicitly are asked to ignore */
32 return strv_fnmatch(m->ignored_interfaces, link->ifname);
33 }
34
manager_link_is_online(Manager * m,Link * l,LinkOperationalStateRange s)35 static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange s) {
36 AddressFamily required_family;
37 bool needs_ipv4;
38 bool needs_ipv6;
39
40 assert(m);
41 assert(l);
42
43 /* This returns the following:
44 * -EAGAIN: not processed by udev or networkd
45 * 0: operstate is not enough
46 * 1: online */
47
48 if (!l->state || streq(l->state, "pending"))
49 /* If no state string exists, networkd (and possibly also udevd) has not detected the
50 * interface yet, that mean we cannot determine whether the interface is managed or
51 * not. Hence, return negative value.
52 * If the link is in pending state, then udevd has not processed the link, and networkd
53 * has not tried to find .network file for the link. Hence, return negative value. */
54 return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
55 "link has not yet been processed by udev: setup state is %s.",
56 strna(l->state));
57
58 if (streq(l->state, "unmanaged")) {
59 /* If the link is in unmanaged state, then ignore the interface unless the interface is
60 * specified in '--interface/-i' option. */
61 if (!hashmap_contains(m->command_line_interfaces_by_name, l->ifname)) {
62 log_link_debug(l, "link is not managed by networkd (yet?).");
63 return 0;
64 }
65
66 } else if (!streq(l->state, "configured"))
67 /* If the link is in non-configured state, return negative value here. */
68 return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
69 "link is being processed by networkd: setup state is %s.",
70 l->state);
71
72 if (s.min < 0)
73 s.min = m->required_operstate.min >= 0 ? m->required_operstate.min
74 : l->required_operstate.min;
75
76 if (s.max < 0)
77 s.max = m->required_operstate.max >= 0 ? m->required_operstate.max
78 : l->required_operstate.max;
79
80 if (l->operational_state < s.min || l->operational_state > s.max) {
81 log_link_debug(l, "Operational state '%s' is not in range ['%s':'%s']",
82 link_operstate_to_string(l->operational_state),
83 link_operstate_to_string(s.min), link_operstate_to_string(s.max));
84 return 0;
85 }
86
87 required_family = m->required_family > 0 ? m->required_family : l->required_family;
88 needs_ipv4 = required_family & ADDRESS_FAMILY_IPV4;
89 needs_ipv6 = required_family & ADDRESS_FAMILY_IPV6;
90
91 if (s.min < LINK_OPERSTATE_ROUTABLE) {
92 if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_DEGRADED) {
93 log_link_debug(l, "No routable or link-local IPv4 address is configured.");
94 return 0;
95 }
96
97 if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_DEGRADED) {
98 log_link_debug(l, "No routable or link-local IPv6 address is configured.");
99 return 0;
100 }
101 } else {
102 if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_ROUTABLE) {
103 log_link_debug(l, "No routable IPv4 address is configured.");
104 return 0;
105 }
106
107 if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_ROUTABLE) {
108 log_link_debug(l, "No routable IPv6 address is configured.");
109 return 0;
110 }
111 }
112
113 log_link_debug(l, "link is configured by networkd and online.");
114 return 1;
115 }
116
manager_configured(Manager * m)117 bool manager_configured(Manager *m) {
118 bool one_ready = false;
119 const char *ifname;
120 Link *l;
121 int r;
122
123 if (!hashmap_isempty(m->command_line_interfaces_by_name)) {
124 LinkOperationalStateRange *range;
125
126 /* wait for all the links given on the command line to appear */
127 HASHMAP_FOREACH_KEY(range, ifname, m->command_line_interfaces_by_name) {
128
129 l = hashmap_get(m->links_by_name, ifname);
130 if (!l && range->min == LINK_OPERSTATE_MISSING) {
131 one_ready = true;
132 continue;
133 }
134
135 if (!l) {
136 log_debug("still waiting for %s", ifname);
137 if (!m->any)
138 return false;
139 continue;
140 }
141
142 if (manager_link_is_online(m, l, *range) <= 0) {
143 if (!m->any)
144 return false;
145 continue;
146 }
147
148 one_ready = true;
149 }
150
151 /* all interfaces given by the command line are online, or
152 * one of the specified interfaces is online. */
153 return one_ready;
154 }
155
156 /* wait for all links networkd manages to be in admin state 'configured'
157 * and at least one link to gain a carrier */
158 HASHMAP_FOREACH(l, m->links_by_index) {
159 if (manager_ignore_link(m, l)) {
160 log_link_debug(l, "link is ignored");
161 continue;
162 }
163
164 r = manager_link_is_online(m, l,
165 (LinkOperationalStateRange) { _LINK_OPERSTATE_INVALID,
166 _LINK_OPERSTATE_INVALID });
167 if (r < 0 && !m->any)
168 return false;
169 if (r > 0)
170 /* we wait for at least one link to be ready,
171 * regardless of who manages it */
172 one_ready = true;
173 }
174
175 return one_ready;
176 }
177
manager_process_link(sd_netlink * rtnl,sd_netlink_message * mm,void * userdata)178 static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
179 Manager *m = userdata;
180 uint16_t type;
181 Link *l;
182 const char *ifname;
183 int ifindex, r;
184
185 assert(rtnl);
186 assert(m);
187 assert(mm);
188
189 r = sd_netlink_message_get_type(mm, &type);
190 if (r < 0) {
191 log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
192 return 0;
193 }
194
195 r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
196 if (r < 0) {
197 log_warning_errno(r, "rtnl: Could not get ifindex from link, ignoring: %m");
198 return 0;
199 } else if (ifindex <= 0) {
200 log_warning("rtnl: received link message with invalid ifindex %d, ignoring", ifindex);
201 return 0;
202 }
203
204 r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname);
205 if (r < 0) {
206 log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
207 return 0;
208 }
209
210 l = hashmap_get(m->links_by_index, INT_TO_PTR(ifindex));
211
212 switch (type) {
213
214 case RTM_NEWLINK:
215 if (!l) {
216 log_debug("Found link %i", ifindex);
217
218 r = link_new(m, &l, ifindex, ifname);
219 if (r < 0)
220 return log_error_errno(r, "Failed to create link object: %m");
221 }
222
223 r = link_update_rtnl(l, mm);
224 if (r < 0)
225 log_link_warning_errno(l, r, "Failed to process RTNL link message, ignoring: %m");
226
227 r = link_update_monitor(l);
228 if (r < 0 && r != -ENODATA)
229 log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m");
230
231 break;
232
233 case RTM_DELLINK:
234 if (l) {
235 log_link_debug(l, "Removing link");
236 link_free(l);
237 }
238
239 break;
240 }
241
242 return 0;
243 }
244
on_rtnl_event(sd_netlink * rtnl,sd_netlink_message * mm,void * userdata)245 static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
246 Manager *m = userdata;
247 int r;
248
249 r = manager_process_link(rtnl, mm, m);
250 if (r < 0)
251 return r;
252
253 if (manager_configured(m))
254 sd_event_exit(m->event, 0);
255
256 return 1;
257 }
258
manager_rtnl_listen(Manager * m)259 static int manager_rtnl_listen(Manager *m) {
260 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
261 int r;
262
263 assert(m);
264
265 /* First, subscribe to interfaces coming and going */
266 r = sd_netlink_open(&m->rtnl);
267 if (r < 0)
268 return r;
269
270 r = sd_netlink_attach_event(m->rtnl, m->event, 0);
271 if (r < 0)
272 return r;
273
274 r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, on_rtnl_event, NULL, m, "wait-online-on-NEWLINK");
275 if (r < 0)
276 return r;
277
278 r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELLINK, on_rtnl_event, NULL, m, "wait-online-on-DELLINK");
279 if (r < 0)
280 return r;
281
282 /* Then, enumerate all links */
283 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
284 if (r < 0)
285 return r;
286
287 r = sd_netlink_message_request_dump(req, true);
288 if (r < 0)
289 return r;
290
291 r = sd_netlink_call(m->rtnl, req, 0, &reply);
292 if (r < 0)
293 return r;
294
295 for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) {
296 r = manager_process_link(m->rtnl, i, m);
297 if (r < 0)
298 return r;
299 }
300
301 return r;
302 }
303
on_network_event(sd_event_source * s,int fd,uint32_t revents,void * userdata)304 static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
305 Manager *m = userdata;
306 Link *l;
307 int r;
308
309 assert(m);
310
311 sd_network_monitor_flush(m->network_monitor);
312
313 HASHMAP_FOREACH(l, m->links_by_index) {
314 r = link_update_monitor(l);
315 if (r < 0 && r != -ENODATA)
316 log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m");
317 }
318
319 if (manager_configured(m))
320 sd_event_exit(m->event, 0);
321
322 return 0;
323 }
324
manager_network_monitor_listen(Manager * m)325 static int manager_network_monitor_listen(Manager *m) {
326 int r, fd, events;
327
328 assert(m);
329
330 r = sd_network_monitor_new(&m->network_monitor, NULL);
331 if (r < 0)
332 return r;
333
334 fd = sd_network_monitor_get_fd(m->network_monitor);
335 if (fd < 0)
336 return fd;
337
338 events = sd_network_monitor_get_events(m->network_monitor);
339 if (events < 0)
340 return events;
341
342 r = sd_event_add_io(m->event, &m->network_monitor_event_source,
343 fd, events, &on_network_event, m);
344 if (r < 0)
345 return r;
346
347 return 0;
348 }
349
manager_new(Manager ** ret,Hashmap * command_line_interfaces_by_name,char ** ignored_interfaces,LinkOperationalStateRange required_operstate,AddressFamily required_family,bool any,usec_t timeout)350 int manager_new(Manager **ret,
351 Hashmap *command_line_interfaces_by_name,
352 char **ignored_interfaces,
353 LinkOperationalStateRange required_operstate,
354 AddressFamily required_family,
355 bool any,
356 usec_t timeout) {
357
358 _cleanup_(manager_freep) Manager *m = NULL;
359 int r;
360
361 assert(ret);
362
363 m = new(Manager, 1);
364 if (!m)
365 return -ENOMEM;
366
367 *m = (Manager) {
368 .command_line_interfaces_by_name = command_line_interfaces_by_name,
369 .ignored_interfaces = ignored_interfaces,
370 .required_operstate = required_operstate,
371 .required_family = required_family,
372 .any = any,
373 };
374
375 r = sd_event_default(&m->event);
376 if (r < 0)
377 return r;
378
379 (void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
380 (void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
381
382 if (timeout > 0) {
383 r = sd_event_add_time_relative(m->event, NULL, CLOCK_BOOTTIME, timeout, 0, NULL, INT_TO_PTR(-ETIMEDOUT));
384 if (r < 0 && r != -EOVERFLOW)
385 return r;
386 }
387
388 sd_event_set_watchdog(m->event, true);
389
390 r = manager_network_monitor_listen(m);
391 if (r < 0)
392 return r;
393
394 r = manager_rtnl_listen(m);
395 if (r < 0)
396 return r;
397
398 *ret = TAKE_PTR(m);
399
400 return 0;
401 }
402
manager_free(Manager * m)403 Manager* manager_free(Manager *m) {
404 if (!m)
405 return NULL;
406
407 hashmap_free_with_destructor(m->links_by_index, link_free);
408 hashmap_free(m->links_by_name);
409
410 sd_event_source_unref(m->network_monitor_event_source);
411 sd_network_monitor_unref(m->network_monitor);
412 sd_event_source_unref(m->rtnl_event_source);
413 sd_netlink_unref(m->rtnl);
414 sd_event_unref(m->event);
415
416 return mfree(m);
417 }
418