Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
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 "network-internal.h"
12 : : #include "strv.h"
13 : : #include "time-util.h"
14 : : #include "util.h"
15 : :
16 : 0 : static bool manager_ignore_link(Manager *m, Link *link) {
17 [ # # ]: 0 : assert(m);
18 [ # # ]: 0 : assert(link);
19 : :
20 : : /* always ignore the loopback interface */
21 [ # # ]: 0 : if (link->flags & IFF_LOOPBACK)
22 : 0 : return true;
23 : :
24 : : /* if interfaces are given on the command line, ignore all others */
25 [ # # # # ]: 0 : if (m->interfaces && !hashmap_contains(m->interfaces, link->ifname))
26 : 0 : return true;
27 : :
28 [ # # ]: 0 : if (!link->required_for_online)
29 : 0 : return true;
30 : :
31 : : /* ignore interfaces we explicitly are asked to ignore */
32 : 0 : return strv_fnmatch(m->ignore, link->ifname, 0);
33 : : }
34 : :
35 : 0 : static int manager_link_is_online(Manager *m, Link *l, LinkOperationalState s) {
36 : : /* This returns the following:
37 : : * -EAGAIN: not processed by udev or networkd
38 : : * 0: operstate is not enough
39 : : * 1: online */
40 : :
41 [ # # ]: 0 : if (!l->state)
42 [ # # # # ]: 0 : return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
43 : : "link has not yet been processed by udev");
44 : :
45 [ # # ]: 0 : if (STR_IN_SET(l->state, "configuring", "pending"))
46 [ # # # # ]: 0 : return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
47 : : "link is being processed by networkd");
48 : :
49 [ # # ]: 0 : if (s < 0)
50 [ # # ]: 0 : s = m->required_operstate >= 0 ? m->required_operstate : l->required_operstate;
51 : :
52 [ # # ]: 0 : if (l->operational_state < s) {
53 [ # # # # ]: 0 : log_link_debug(l, "Operational state '%s' is below '%s'",
54 : : link_operstate_to_string(l->operational_state),
55 : : link_operstate_to_string(s));
56 : 0 : return 0;
57 : : }
58 : :
59 : 0 : return 1;
60 : : }
61 : :
62 : 0 : bool manager_configured(Manager *m) {
63 : 0 : bool one_ready = false;
64 : : Iterator i;
65 : : const char *ifname;
66 : : void *p;
67 : : Link *l;
68 : : int r;
69 : :
70 [ # # ]: 0 : if (!hashmap_isempty(m->interfaces)) {
71 : : /* wait for all the links given on the command line to appear */
72 [ # # ]: 0 : HASHMAP_FOREACH_KEY(p, ifname, m->interfaces, i) {
73 : 0 : LinkOperationalState s = PTR_TO_INT(p);
74 : :
75 : 0 : l = hashmap_get(m->links_by_name, ifname);
76 [ # # ]: 0 : if (!l) {
77 [ # # ]: 0 : log_debug("still waiting for %s", ifname);
78 [ # # ]: 0 : if (!m->any)
79 : 0 : return false;
80 : 0 : continue;
81 : : }
82 : :
83 [ # # ]: 0 : if (manager_link_is_online(m, l, s) <= 0) {
84 [ # # ]: 0 : if (!m->any)
85 : 0 : return false;
86 : 0 : continue;
87 : : }
88 : :
89 : 0 : one_ready = true;
90 : : }
91 : :
92 : : /* all interfaces given by the command line are online, or
93 : : * one of the specified interfaces is online. */
94 : 0 : return one_ready;
95 : : }
96 : :
97 : : /* wait for all links networkd manages to be in admin state 'configured'
98 : : * and at least one link to gain a carrier */
99 [ # # ]: 0 : HASHMAP_FOREACH(l, m->links, i) {
100 [ # # ]: 0 : if (manager_ignore_link(m, l)) {
101 [ # # # # ]: 0 : log_link_debug(l, "link is ignored");
102 : 0 : continue;
103 : : }
104 : :
105 : 0 : r = manager_link_is_online(m, l, _LINK_OPERSTATE_INVALID);
106 [ # # # # ]: 0 : if (r < 0 && !m->any)
107 : 0 : return false;
108 [ # # ]: 0 : if (r > 0)
109 : : /* we wait for at least one link to be ready,
110 : : * regardless of who manages it */
111 : 0 : one_ready = true;
112 : : }
113 : :
114 : 0 : return one_ready;
115 : : }
116 : :
117 : 0 : static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
118 : 0 : Manager *m = userdata;
119 : : uint16_t type;
120 : : Link *l;
121 : : const char *ifname;
122 : : int ifindex, r;
123 : :
124 [ # # ]: 0 : assert(rtnl);
125 [ # # ]: 0 : assert(m);
126 [ # # ]: 0 : assert(mm);
127 : :
128 : 0 : r = sd_netlink_message_get_type(mm, &type);
129 [ # # ]: 0 : if (r < 0) {
130 [ # # ]: 0 : log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
131 : 0 : return 0;
132 : : }
133 : :
134 : 0 : r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
135 [ # # ]: 0 : if (r < 0) {
136 [ # # ]: 0 : log_warning_errno(r, "rtnl: Could not get ifindex from link, ignoring: %m");
137 : 0 : return 0;
138 [ # # ]: 0 : } else if (ifindex <= 0) {
139 [ # # ]: 0 : log_warning("rtnl: received link message with invalid ifindex %d, ignoring", ifindex);
140 : 0 : return 0;
141 : : }
142 : :
143 : 0 : r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname);
144 [ # # ]: 0 : if (r < 0) {
145 [ # # ]: 0 : log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
146 : 0 : return 0;
147 : : }
148 : :
149 : 0 : l = hashmap_get(m->links, INT_TO_PTR(ifindex));
150 : :
151 [ # # # ]: 0 : switch (type) {
152 : :
153 : 0 : case RTM_NEWLINK:
154 [ # # ]: 0 : if (!l) {
155 [ # # ]: 0 : log_debug("Found link %i", ifindex);
156 : :
157 : 0 : r = link_new(m, &l, ifindex, ifname);
158 [ # # ]: 0 : if (r < 0)
159 [ # # ]: 0 : return log_error_errno(r, "Failed to create link object: %m");
160 : : }
161 : :
162 : 0 : r = link_update_rtnl(l, mm);
163 [ # # ]: 0 : if (r < 0)
164 [ # # # # ]: 0 : log_link_warning_errno(l, r, "Failed to process RTNL link message, ignoring: %m");
165 : :
166 : 0 : r = link_update_monitor(l);
167 [ # # # # ]: 0 : if (r < 0 && r != -ENODATA)
168 [ # # # # ]: 0 : log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m");
169 : :
170 : 0 : break;
171 : :
172 : 0 : case RTM_DELLINK:
173 [ # # ]: 0 : if (l) {
174 [ # # # # ]: 0 : log_link_debug(l, "Removing link");
175 : 0 : link_free(l);
176 : : }
177 : :
178 : 0 : break;
179 : : }
180 : :
181 : 0 : return 0;
182 : : }
183 : :
184 : 0 : static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
185 : 0 : Manager *m = userdata;
186 : : int r;
187 : :
188 : 0 : r = manager_process_link(rtnl, mm, m);
189 [ # # ]: 0 : if (r < 0)
190 : 0 : return r;
191 : :
192 [ # # ]: 0 : if (manager_configured(m))
193 : 0 : sd_event_exit(m->event, 0);
194 : :
195 : 0 : return 1;
196 : : }
197 : :
198 : 0 : static int manager_rtnl_listen(Manager *m) {
199 : 0 : _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
200 : : sd_netlink_message *i;
201 : : int r;
202 : :
203 [ # # ]: 0 : assert(m);
204 : :
205 : : /* First, subscribe to interfaces coming and going */
206 : 0 : r = sd_netlink_open(&m->rtnl);
207 [ # # ]: 0 : if (r < 0)
208 : 0 : return r;
209 : :
210 : 0 : r = sd_netlink_attach_event(m->rtnl, m->event, 0);
211 [ # # ]: 0 : if (r < 0)
212 : 0 : return r;
213 : :
214 : 0 : r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, on_rtnl_event, NULL, m, "wait-online-on-NEWLINK");
215 [ # # ]: 0 : if (r < 0)
216 : 0 : return r;
217 : :
218 : 0 : r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELLINK, on_rtnl_event, NULL, m, "wait-online-on-DELLINK");
219 [ # # ]: 0 : if (r < 0)
220 : 0 : return r;
221 : :
222 : : /* Then, enumerate all links */
223 : 0 : r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
224 [ # # ]: 0 : if (r < 0)
225 : 0 : return r;
226 : :
227 : 0 : r = sd_netlink_message_request_dump(req, true);
228 [ # # ]: 0 : if (r < 0)
229 : 0 : return r;
230 : :
231 : 0 : r = sd_netlink_call(m->rtnl, req, 0, &reply);
232 [ # # ]: 0 : if (r < 0)
233 : 0 : return r;
234 : :
235 [ # # ]: 0 : for (i = reply; i; i = sd_netlink_message_next(i)) {
236 : 0 : r = manager_process_link(m->rtnl, i, m);
237 [ # # ]: 0 : if (r < 0)
238 : 0 : return r;
239 : : }
240 : :
241 : 0 : return r;
242 : : }
243 : :
244 : 0 : static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
245 : 0 : Manager *m = userdata;
246 : : Iterator i;
247 : : Link *l;
248 : : int r;
249 : :
250 [ # # ]: 0 : assert(m);
251 : :
252 : 0 : sd_network_monitor_flush(m->network_monitor);
253 : :
254 [ # # ]: 0 : HASHMAP_FOREACH(l, m->links, i) {
255 : 0 : r = link_update_monitor(l);
256 [ # # # # ]: 0 : if (r < 0 && r != -ENODATA)
257 [ # # # # ]: 0 : log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m");
258 : : }
259 : :
260 [ # # ]: 0 : if (manager_configured(m))
261 : 0 : sd_event_exit(m->event, 0);
262 : :
263 : 0 : return 0;
264 : : }
265 : :
266 : 0 : static int manager_network_monitor_listen(Manager *m) {
267 : : int r, fd, events;
268 : :
269 [ # # ]: 0 : assert(m);
270 : :
271 : 0 : r = sd_network_monitor_new(&m->network_monitor, NULL);
272 [ # # ]: 0 : if (r < 0)
273 : 0 : return r;
274 : :
275 : 0 : fd = sd_network_monitor_get_fd(m->network_monitor);
276 [ # # ]: 0 : if (fd < 0)
277 : 0 : return fd;
278 : :
279 : 0 : events = sd_network_monitor_get_events(m->network_monitor);
280 [ # # ]: 0 : if (events < 0)
281 : 0 : return events;
282 : :
283 : 0 : r = sd_event_add_io(m->event, &m->network_monitor_event_source,
284 : : fd, events, &on_network_event, m);
285 [ # # ]: 0 : if (r < 0)
286 : 0 : return r;
287 : :
288 : 0 : return 0;
289 : : }
290 : :
291 : 0 : int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
292 : : LinkOperationalState required_operstate,
293 : : bool any, usec_t timeout) {
294 : 0 : _cleanup_(manager_freep) Manager *m = NULL;
295 : : int r;
296 : :
297 [ # # ]: 0 : assert(ret);
298 : :
299 : 0 : m = new(Manager, 1);
300 [ # # ]: 0 : if (!m)
301 : 0 : return -ENOMEM;
302 : :
303 : 0 : *m = (Manager) {
304 : : .interfaces = interfaces,
305 : : .ignore = ignore,
306 : : .required_operstate = required_operstate,
307 : : .any = any,
308 : : };
309 : :
310 : 0 : r = sd_event_default(&m->event);
311 [ # # ]: 0 : if (r < 0)
312 : 0 : return r;
313 : :
314 : 0 : (void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
315 : 0 : (void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
316 : :
317 [ # # ]: 0 : if (timeout > 0) {
318 : : usec_t usec;
319 : :
320 : 0 : usec = now(clock_boottime_or_monotonic()) + timeout;
321 : :
322 : 0 : r = sd_event_add_time(m->event, NULL, clock_boottime_or_monotonic(), usec, 0, NULL, INT_TO_PTR(-ETIMEDOUT));
323 [ # # ]: 0 : if (r < 0)
324 : 0 : return r;
325 : : }
326 : :
327 : 0 : sd_event_set_watchdog(m->event, true);
328 : :
329 : 0 : r = manager_network_monitor_listen(m);
330 [ # # ]: 0 : if (r < 0)
331 : 0 : return r;
332 : :
333 : 0 : r = manager_rtnl_listen(m);
334 [ # # ]: 0 : if (r < 0)
335 : 0 : return r;
336 : :
337 : 0 : *ret = TAKE_PTR(m);
338 : :
339 : 0 : return 0;
340 : : }
341 : :
342 : 0 : void manager_free(Manager *m) {
343 [ # # ]: 0 : if (!m)
344 : 0 : return;
345 : :
346 [ # # ]: 0 : hashmap_free_with_destructor(m->links, link_free);
347 : 0 : hashmap_free(m->links_by_name);
348 : :
349 : 0 : sd_event_source_unref(m->network_monitor_event_source);
350 : 0 : sd_network_monitor_unref(m->network_monitor);
351 : :
352 : 0 : sd_event_source_unref(m->rtnl_event_source);
353 : 0 : sd_netlink_unref(m->rtnl);
354 : :
355 : 0 : sd_event_unref(m->event);
356 : 0 : free(m);
357 : :
358 : 0 : return;
359 : : }
|