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