]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | ||
3 | #include <linux/filter.h> | |
4 | #include <linux/nl80211.h> | |
5 | #include <sys/socket.h> | |
6 | ||
7 | #include "sd-bus.h" | |
8 | #include "sd-event.h" | |
9 | #include "sd-netlink.h" | |
10 | #include "sd-resolve.h" | |
11 | ||
12 | #include "alloc-util.h" | |
13 | #include "bus-error.h" | |
14 | #include "bus-locator.h" | |
15 | #include "bus-log-control-api.h" | |
16 | #include "bus-object.h" | |
17 | #include "bus-util.h" | |
18 | #include "capability-util.h" | |
19 | #include "common-signal.h" | |
20 | #include "daemon-util.h" | |
21 | #include "device-private.h" | |
22 | #include "device-util.h" | |
23 | #include "env-util.h" | |
24 | #include "errno-util.h" | |
25 | #include "fd-util.h" | |
26 | #include "firewall-util.h" | |
27 | #include "initrd-util.h" | |
28 | #include "mount-util.h" | |
29 | #include "netlink-util.h" | |
30 | #include "networkd-address.h" | |
31 | #include "networkd-address-label.h" | |
32 | #include "networkd-address-pool.h" | |
33 | #include "networkd-link.h" | |
34 | #include "networkd-manager.h" | |
35 | #include "networkd-manager-bus.h" | |
36 | #include "networkd-manager-varlink.h" | |
37 | #include "networkd-neighbor.h" | |
38 | #include "networkd-nexthop.h" | |
39 | #include "networkd-queue.h" | |
40 | #include "networkd-route.h" | |
41 | #include "networkd-routing-policy-rule.h" | |
42 | #include "networkd-serialize.h" | |
43 | #include "networkd-speed-meter.h" | |
44 | #include "networkd-state-file.h" | |
45 | #include "networkd-wifi.h" | |
46 | #include "networkd-wiphy.h" | |
47 | #include "ordered-set.h" | |
48 | #include "qdisc.h" | |
49 | #include "set.h" | |
50 | #include "stat-util.h" | |
51 | #include "string-util.h" | |
52 | #include "strv.h" | |
53 | #include "tclass.h" | |
54 | #include "tuntap.h" | |
55 | #include "udev-util.h" | |
56 | ||
57 | /* use 128 MB for receive socket kernel queue. */ | |
58 | #define RCVBUF_SIZE (128*1024*1024) | |
59 | ||
60 | static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { | |
61 | Manager *m = ASSERT_PTR(userdata); | |
62 | Link *link; | |
63 | int b, r; | |
64 | ||
65 | assert(message); | |
66 | ||
67 | r = sd_bus_message_read(message, "b", &b); | |
68 | if (r < 0) { | |
69 | bus_log_parse_error(r); | |
70 | return 0; | |
71 | } | |
72 | ||
73 | if (b) | |
74 | return 0; | |
75 | ||
76 | log_debug("Coming back from suspend, reconfiguring all connections..."); | |
77 | ||
78 | HASHMAP_FOREACH(link, m->links_by_index) | |
79 | (void) link_reconfigure(link, LINK_RECONFIGURE_UNCONDITIONALLY); | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { | |
85 | Manager *m = ASSERT_PTR(userdata); | |
86 | ||
87 | assert(message); | |
88 | ||
89 | /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */ | |
90 | if (m->dynamic_hostname) | |
91 | (void) manager_set_hostname(m, m->dynamic_hostname); | |
92 | if (m->dynamic_timezone) | |
93 | (void) manager_set_timezone(m, m->dynamic_timezone); | |
94 | if (m->product_uuid_requested) | |
95 | (void) manager_request_product_uuid(m); | |
96 | ||
97 | return 0; | |
98 | } | |
99 | ||
100 | static int manager_connect_bus(Manager *m) { | |
101 | int r; | |
102 | ||
103 | assert(m); | |
104 | assert(!m->bus); | |
105 | ||
106 | r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network"); | |
107 | if (r < 0) | |
108 | return log_error_errno(r, "Failed to connect to bus: %m"); | |
109 | ||
110 | r = bus_add_implementation(m->bus, &manager_object, m); | |
111 | if (r < 0) | |
112 | return r; | |
113 | ||
114 | r = bus_log_control_api_register(m->bus); | |
115 | if (r < 0) | |
116 | return r; | |
117 | ||
118 | r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL); | |
119 | if (r < 0) | |
120 | return log_error_errno(r, "Failed to request name: %m"); | |
121 | ||
122 | r = sd_bus_attach_event(m->bus, m->event, 0); | |
123 | if (r < 0) | |
124 | return log_error_errno(r, "Failed to attach bus to event loop: %m"); | |
125 | ||
126 | r = sd_bus_match_signal_async( | |
127 | m->bus, | |
128 | NULL, | |
129 | "org.freedesktop.DBus.Local", | |
130 | NULL, | |
131 | "org.freedesktop.DBus.Local", | |
132 | "Connected", | |
133 | on_connected, NULL, m); | |
134 | if (r < 0) | |
135 | return log_error_errno(r, "Failed to request match on Connected signal: %m"); | |
136 | ||
137 | r = bus_match_signal_async( | |
138 | m->bus, | |
139 | NULL, | |
140 | bus_login_mgr, | |
141 | "PrepareForSleep", | |
142 | match_prepare_for_sleep, NULL, m); | |
143 | if (r < 0) | |
144 | log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m"); | |
145 | ||
146 | return 0; | |
147 | } | |
148 | ||
149 | static int manager_process_uevent(sd_device_monitor *monitor, sd_device *device, void *userdata) { | |
150 | Manager *m = ASSERT_PTR(userdata); | |
151 | sd_device_action_t action; | |
152 | int r; | |
153 | ||
154 | assert(device); | |
155 | ||
156 | r = sd_device_get_action(device, &action); | |
157 | if (r < 0) | |
158 | return log_device_warning_errno(device, r, "Failed to get udev action, ignoring: %m"); | |
159 | ||
160 | if (device_in_subsystem(device, "net") > 0) | |
161 | r = manager_udev_process_link(m, device, action); | |
162 | else if (device_in_subsystem(device, "ieee80211") > 0) | |
163 | r = manager_udev_process_wiphy(m, device, action); | |
164 | else if (device_in_subsystem(device, "rfkill") > 0) | |
165 | r = manager_udev_process_rfkill(m, device, action); | |
166 | if (r < 0) | |
167 | log_device_warning_errno(device, r, "Failed to process \"%s\" uevent, ignoring: %m", | |
168 | device_action_to_string(action)); | |
169 | ||
170 | return 0; | |
171 | } | |
172 | ||
173 | static int manager_connect_udev(Manager *m) { | |
174 | int r; | |
175 | ||
176 | /* udev does not initialize devices inside containers, so we rely on them being already | |
177 | * initialized before entering the container. */ | |
178 | if (!udev_available()) | |
179 | return 0; | |
180 | ||
181 | r = sd_device_monitor_new(&m->device_monitor); | |
182 | if (r < 0) | |
183 | return log_error_errno(r, "Failed to initialize device monitor: %m"); | |
184 | ||
185 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL); | |
186 | if (r < 0) | |
187 | return log_error_errno(r, "Could not add device monitor filter for net subsystem: %m"); | |
188 | ||
189 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "ieee80211", NULL); | |
190 | if (r < 0) | |
191 | return log_error_errno(r, "Could not add device monitor filter for ieee80211 subsystem: %m"); | |
192 | ||
193 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "rfkill", NULL); | |
194 | if (r < 0) | |
195 | return log_error_errno(r, "Could not add device monitor filter for rfkill subsystem: %m"); | |
196 | ||
197 | r = sd_device_monitor_attach_event(m->device_monitor, m->event); | |
198 | if (r < 0) | |
199 | return log_error_errno(r, "Failed to attach event to device monitor: %m"); | |
200 | ||
201 | r = sd_device_monitor_start(m->device_monitor, manager_process_uevent, m); | |
202 | if (r < 0) | |
203 | return log_error_errno(r, "Failed to start device monitor: %m"); | |
204 | ||
205 | return 0; | |
206 | } | |
207 | ||
208 | static int manager_listen_fds(Manager *m, int *ret_rtnl_fd, int *ret_varlink_fd) { | |
209 | _cleanup_strv_free_ char **names = NULL; | |
210 | int n, rtnl_fd = -EBADF, varlink_fd = -EBADF; | |
211 | ||
212 | assert(m); | |
213 | assert(ret_rtnl_fd); | |
214 | assert(ret_varlink_fd); | |
215 | ||
216 | n = sd_listen_fds_with_names(/* unset_environment = */ true, &names); | |
217 | if (n < 0) | |
218 | return n; | |
219 | ||
220 | for (int i = 0; i < n; i++) { | |
221 | int fd = i + SD_LISTEN_FDS_START; | |
222 | ||
223 | if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { | |
224 | if (rtnl_fd >= 0) { | |
225 | log_debug("Received multiple netlink sockets, ignoring."); | |
226 | goto unused; | |
227 | } | |
228 | ||
229 | rtnl_fd = fd; | |
230 | continue; | |
231 | } | |
232 | ||
233 | if (streq(names[i], "varlink")) { | |
234 | varlink_fd = fd; | |
235 | continue; | |
236 | } | |
237 | ||
238 | if (manager_set_serialization_fd(m, fd, names[i]) >= 0) | |
239 | continue; | |
240 | ||
241 | if (manager_add_tuntap_fd(m, fd, names[i]) >= 0) | |
242 | continue; | |
243 | ||
244 | unused: | |
245 | if (m->test_mode) | |
246 | safe_close(fd); | |
247 | else | |
248 | close_and_notify_warn(fd, names[i]); | |
249 | } | |
250 | ||
251 | *ret_rtnl_fd = rtnl_fd; | |
252 | *ret_varlink_fd = varlink_fd; | |
253 | ||
254 | return 0; | |
255 | } | |
256 | ||
257 | static int manager_connect_genl(Manager *m) { | |
258 | int r; | |
259 | ||
260 | assert(m); | |
261 | ||
262 | r = sd_genl_socket_open(&m->genl); | |
263 | if (r < 0) | |
264 | return r; | |
265 | ||
266 | r = sd_netlink_increase_rxbuf(m->genl, RCVBUF_SIZE); | |
267 | if (r < 0) | |
268 | log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m"); | |
269 | ||
270 | r = sd_netlink_attach_event(m->genl, m->event, 0); | |
271 | if (r < 0) | |
272 | return r; | |
273 | ||
274 | /* If the kernel is built without CONFIG_WIRELESS, the below will fail with -EOPNOTSUPP. */ | |
275 | r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_CONFIG, 0, | |
276 | &manager_genl_process_nl80211_config, NULL, m, "network-genl_process_nl80211_config"); | |
277 | if (r < 0 && r != -EOPNOTSUPP) | |
278 | return r; | |
279 | ||
280 | r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_MLME, 0, | |
281 | &manager_genl_process_nl80211_mlme, NULL, m, "network-genl_process_nl80211_mlme"); | |
282 | if (r < 0 && r != -EOPNOTSUPP) | |
283 | return r; | |
284 | ||
285 | return 0; | |
286 | } | |
287 | ||
288 | static int manager_setup_rtnl_filter(Manager *manager) { | |
289 | struct sock_filter filter[] = { | |
290 | /* Check the packet length. */ | |
291 | BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ | |
292 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr), 1, 0), /* A (packet length) >= sizeof(struct nlmsghdr) ? */ | |
293 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
294 | /* Always accept multipart message. */ | |
295 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_flags)), /* A <- message flags */ | |
296 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NLM_F_MULTI), 0, 1), /* message flags has NLM_F_MULTI ? */ | |
297 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
298 | /* Accept all message types except for RTM_NEWNEIGH or RTM_DELNEIGH. */ | |
299 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_type)), /* A <- message type */ | |
300 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_NEWNEIGH), 2, 0), /* message type == RTM_NEWNEIGH ? */ | |
301 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_DELNEIGH), 1, 0), /* message type == RTM_DELNEIGH ? */ | |
302 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
303 | /* Check the packet length. */ | |
304 | BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ | |
305 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr) + sizeof(struct ndmsg), 1, 0), | |
306 | /* packet length >= sizeof(struct nlmsghdr) + sizeof(struct ndmsg) ? */ | |
307 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
308 | /* Reject the message when the neighbor state does not have NUD_PERMANENT flag. */ | |
309 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, sizeof(struct nlmsghdr) + offsetof(struct ndmsg, ndm_state)), | |
310 | /* A <- neighbor state */ | |
311 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NUD_PERMANENT), 1, 0), /* neighbor state has NUD_PERMANENT ? */ | |
312 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
313 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
314 | }; | |
315 | ||
316 | assert(manager); | |
317 | assert(manager->rtnl); | |
318 | ||
319 | return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter); | |
320 | } | |
321 | ||
322 | static int manager_connect_rtnl(Manager *m, int fd) { | |
323 | _unused_ _cleanup_close_ int fd_close = fd; | |
324 | int r; | |
325 | ||
326 | assert(m); | |
327 | ||
328 | /* This takes input fd. */ | |
329 | ||
330 | if (fd < 0) | |
331 | r = sd_netlink_open(&m->rtnl); | |
332 | else | |
333 | r = sd_netlink_open_fd(&m->rtnl, fd); | |
334 | if (r < 0) | |
335 | return r; | |
336 | TAKE_FD(fd_close); | |
337 | ||
338 | /* Bump receiver buffer, but only if we are not called via socket activation, as in that | |
339 | * case systemd sets the receive buffer size for us, and the value in the .socket unit | |
340 | * should take full effect. */ | |
341 | if (fd < 0) { | |
342 | r = sd_netlink_increase_rxbuf(m->rtnl, RCVBUF_SIZE); | |
343 | if (r < 0) | |
344 | log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m"); | |
345 | } | |
346 | ||
347 | r = sd_netlink_attach_event(m->rtnl, m->event, 0); | |
348 | if (r < 0) | |
349 | return r; | |
350 | ||
351 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); | |
352 | if (r < 0) | |
353 | return r; | |
354 | ||
355 | r = netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); | |
356 | if (r < 0) | |
357 | return r; | |
358 | ||
359 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); | |
360 | if (r < 0) | |
361 | return r; | |
362 | ||
363 | r = netlink_add_match(m->rtnl, NULL, RTM_DELQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); | |
364 | if (r < 0) | |
365 | return r; | |
366 | ||
367 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); | |
368 | if (r < 0) | |
369 | return r; | |
370 | ||
371 | r = netlink_add_match(m->rtnl, NULL, RTM_DELTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); | |
372 | if (r < 0) | |
373 | return r; | |
374 | ||
375 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); | |
376 | if (r < 0) | |
377 | return r; | |
378 | ||
379 | r = netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); | |
380 | if (r < 0) | |
381 | return r; | |
382 | ||
383 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); | |
384 | if (r < 0) | |
385 | return r; | |
386 | ||
387 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); | |
388 | if (r < 0) | |
389 | return r; | |
390 | ||
391 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); | |
392 | if (r < 0) | |
393 | return r; | |
394 | ||
395 | r = netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); | |
396 | if (r < 0) | |
397 | return r; | |
398 | ||
399 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); | |
400 | if (r < 0) | |
401 | return r; | |
402 | ||
403 | r = netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); | |
404 | if (r < 0) | |
405 | return r; | |
406 | ||
407 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); | |
408 | if (r < 0) | |
409 | return r; | |
410 | ||
411 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); | |
412 | if (r < 0) | |
413 | return r; | |
414 | ||
415 | return manager_setup_rtnl_filter(m); | |
416 | } | |
417 | ||
418 | static int manager_post_handler(sd_event_source *s, void *userdata) { | |
419 | Manager *manager = ASSERT_PTR(userdata); | |
420 | ||
421 | /* To release dynamic leases, we need to process queued remove requests before stopping networkd. | |
422 | * This is especially important when KeepConfiguration=no. See issue #34837. */ | |
423 | (void) manager_process_remove_requests(manager); | |
424 | ||
425 | switch (manager->state) { | |
426 | case MANAGER_RUNNING: | |
427 | (void) manager_process_requests(manager); | |
428 | (void) manager_clean_all(manager); | |
429 | return 0; | |
430 | ||
431 | case MANAGER_TERMINATING: | |
432 | case MANAGER_RESTARTING: | |
433 | if (!ordered_set_isempty(manager->remove_request_queue)) | |
434 | return 0; /* There are some unissued remove requests. */ | |
435 | ||
436 | if (netlink_get_reply_callback_count(manager->rtnl) > 0 || | |
437 | netlink_get_reply_callback_count(manager->genl) > 0 || | |
438 | fw_ctx_get_reply_callback_count(manager->fw_ctx) > 0) | |
439 | return 0; /* There are some message calls waiting for their replies. */ | |
440 | ||
441 | (void) manager_serialize(manager); | |
442 | manager->state = MANAGER_STOPPED; | |
443 | return sd_event_exit(sd_event_source_get_event(s), 0); | |
444 | ||
445 | default: | |
446 | assert_not_reached(); | |
447 | } | |
448 | ||
449 | return 0; | |
450 | } | |
451 | ||
452 | static int manager_stop(Manager *manager, ManagerState state) { | |
453 | assert(manager); | |
454 | assert(IN_SET(state, MANAGER_TERMINATING, MANAGER_RESTARTING)); | |
455 | ||
456 | if (manager->state != MANAGER_RUNNING) { | |
457 | log_debug("Already terminating or restarting systemd-networkd, refusing further operation request."); | |
458 | return 0; | |
459 | } | |
460 | ||
461 | switch (state) { | |
462 | case MANAGER_TERMINATING: | |
463 | log_debug("Terminate operation initiated."); | |
464 | break; | |
465 | case MANAGER_RESTARTING: | |
466 | log_debug("Restart operation initiated."); | |
467 | break; | |
468 | default: | |
469 | assert_not_reached(); | |
470 | } | |
471 | ||
472 | manager->state = state; | |
473 | ||
474 | Link *link; | |
475 | HASHMAP_FOREACH(link, manager->links_by_index) | |
476 | (void) link_stop_engines(link, /* may_keep_dynamic = */ true); | |
477 | ||
478 | return 0; | |
479 | } | |
480 | ||
481 | static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { | |
482 | return manager_stop(userdata, MANAGER_TERMINATING); | |
483 | } | |
484 | ||
485 | static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { | |
486 | return manager_stop(userdata, MANAGER_RESTARTING); | |
487 | } | |
488 | ||
489 | static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { | |
490 | Manager *m = ASSERT_PTR(userdata); | |
491 | ||
492 | (void) manager_reload(m, /* message = */ NULL); | |
493 | ||
494 | return 0; | |
495 | } | |
496 | ||
497 | static int manager_set_keep_configuration(Manager *m) { | |
498 | int r; | |
499 | ||
500 | assert(m); | |
501 | ||
502 | if (in_initrd()) { | |
503 | log_debug("Running in initrd, keep dynamically assigned configurations on stopping networkd by default."); | |
504 | m->keep_configuration = KEEP_CONFIGURATION_DYNAMIC_ON_STOP; | |
505 | return 0; | |
506 | } | |
507 | ||
508 | r = path_is_network_fs_harder("/"); | |
509 | if (r < 0) { | |
510 | log_warning_errno(r, "Failed to detect if root is network filesystem, assuming not: %m"); | |
511 | return 0; | |
512 | } | |
513 | if (r == 0) { | |
514 | m->keep_configuration = _KEEP_CONFIGURATION_INVALID; | |
515 | return 0; | |
516 | } | |
517 | ||
518 | log_debug("Running on network filesystem, enabling KeepConfiguration= by default."); | |
519 | m->keep_configuration = KEEP_CONFIGURATION_YES; | |
520 | return 0; | |
521 | } | |
522 | ||
523 | int manager_setup(Manager *m) { | |
524 | _cleanup_close_ int rtnl_fd = -EBADF, varlink_fd = -EBADF; | |
525 | int r; | |
526 | ||
527 | assert(m); | |
528 | ||
529 | r = sd_event_default(&m->event); | |
530 | if (r < 0) | |
531 | return r; | |
532 | ||
533 | (void) sd_event_set_watchdog(m->event, true); | |
534 | (void) sd_event_add_signal(m->event, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m); | |
535 | (void) sd_event_add_signal(m->event, NULL, SIGINT | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m); | |
536 | (void) sd_event_add_signal(m->event, NULL, SIGUSR2 | SD_EVENT_SIGNAL_PROCMASK, signal_restart_callback, m); | |
537 | (void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, signal_reload_callback, m); | |
538 | (void) sd_event_add_signal(m->event, NULL, (SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL); | |
539 | ||
540 | r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL); | |
541 | if (r < 0) | |
542 | log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m"); | |
543 | ||
544 | r = sd_event_add_post(m->event, NULL, manager_post_handler, m); | |
545 | if (r < 0) | |
546 | return r; | |
547 | ||
548 | r = manager_listen_fds(m, &rtnl_fd, &varlink_fd); | |
549 | if (r < 0) | |
550 | return r; | |
551 | ||
552 | r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd)); | |
553 | if (r < 0) | |
554 | return r; | |
555 | ||
556 | r = manager_connect_genl(m); | |
557 | if (r < 0) | |
558 | return r; | |
559 | ||
560 | if (m->test_mode) | |
561 | return 0; | |
562 | ||
563 | r = manager_connect_varlink(m, TAKE_FD(varlink_fd)); | |
564 | if (r < 0) | |
565 | return r; | |
566 | ||
567 | r = manager_connect_bus(m); | |
568 | if (r < 0) | |
569 | return r; | |
570 | ||
571 | r = manager_connect_udev(m); | |
572 | if (r < 0) | |
573 | return r; | |
574 | ||
575 | r = sd_resolve_default(&m->resolve); | |
576 | if (r < 0) | |
577 | return r; | |
578 | ||
579 | r = sd_resolve_attach_event(m->resolve, m->event, 0); | |
580 | if (r < 0) | |
581 | return r; | |
582 | ||
583 | r = address_pool_setup_default(m); | |
584 | if (r < 0) | |
585 | return r; | |
586 | ||
587 | r = manager_set_keep_configuration(m); | |
588 | if (r < 0) | |
589 | return r; | |
590 | ||
591 | m->state_file = strdup("/run/systemd/netif/state"); | |
592 | if (!m->state_file) | |
593 | return -ENOMEM; | |
594 | ||
595 | return 0; | |
596 | } | |
597 | ||
598 | static int persistent_storage_open(void) { | |
599 | _cleanup_close_ int fd = -EBADF; | |
600 | int r; | |
601 | ||
602 | r = getenv_bool("SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY"); | |
603 | if (r < 0 && r != -ENXIO) | |
604 | return log_debug_errno(r, "Failed to parse $SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY environment variable, ignoring: %m"); | |
605 | if (r <= 0) | |
606 | return -EBADF; | |
607 | ||
608 | fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY); | |
609 | if (fd < 0) | |
610 | return log_debug_errno(errno, "Failed to open %s, ignoring: %m", "/var/lib/systemd/network/"); | |
611 | ||
612 | r = fd_is_read_only_fs(fd); | |
613 | if (r < 0) | |
614 | return log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m"); | |
615 | if (r > 0) | |
616 | return log_debug_errno(SYNTHETIC_ERRNO(EROFS), "The directory /var/lib/systemd/network/ is on read-only filesystem."); | |
617 | ||
618 | return TAKE_FD(fd); | |
619 | } | |
620 | ||
621 | int manager_new(Manager **ret, bool test_mode) { | |
622 | _cleanup_(manager_freep) Manager *m = NULL; | |
623 | ||
624 | m = new(Manager, 1); | |
625 | if (!m) | |
626 | return -ENOMEM; | |
627 | ||
628 | *m = (Manager) { | |
629 | .keep_configuration = _KEEP_CONFIGURATION_INVALID, | |
630 | .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO, | |
631 | .test_mode = test_mode, | |
632 | .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL, | |
633 | .online_state = _LINK_ONLINE_STATE_INVALID, | |
634 | .manage_foreign_routes = true, | |
635 | .manage_foreign_rules = true, | |
636 | .manage_foreign_nexthops = true, | |
637 | .ethtool_fd = -EBADF, | |
638 | .persistent_storage_fd = persistent_storage_open(), | |
639 | .dhcp_use_domains = _USE_DOMAINS_INVALID, | |
640 | .dhcp6_use_domains = _USE_DOMAINS_INVALID, | |
641 | .ndisc_use_domains = _USE_DOMAINS_INVALID, | |
642 | .dhcp_client_identifier = DHCP_CLIENT_ID_DUID, | |
643 | .dhcp_duid.type = DUID_TYPE_EN, | |
644 | .dhcp6_duid.type = DUID_TYPE_EN, | |
645 | .duid_product_uuid.type = DUID_TYPE_UUID, | |
646 | .dhcp_server_persist_leases = DHCP_SERVER_PERSIST_LEASES_YES, | |
647 | .serialization_fd = -EBADF, | |
648 | .ip_forwarding = { -1, -1, }, | |
649 | #if HAVE_VMLINUX_H | |
650 | .cgroup_fd = -EBADF, | |
651 | #endif | |
652 | }; | |
653 | ||
654 | *ret = TAKE_PTR(m); | |
655 | return 0; | |
656 | } | |
657 | ||
658 | Manager* manager_free(Manager *m) { | |
659 | if (!m) | |
660 | return NULL; | |
661 | ||
662 | manager_remove_sysctl_monitor(m); | |
663 | ||
664 | free(m->state_file); | |
665 | ||
666 | m->request_queue = ordered_set_free(m->request_queue); | |
667 | m->remove_request_queue = ordered_set_free(m->remove_request_queue); | |
668 | ||
669 | m->new_wlan_ifindices = set_free(m->new_wlan_ifindices); | |
670 | ||
671 | m->dirty_links = set_free(m->dirty_links); | |
672 | m->links_by_name = hashmap_free(m->links_by_name); | |
673 | m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr); | |
674 | m->links_by_dhcp_pd_subnet_prefix = hashmap_free(m->links_by_dhcp_pd_subnet_prefix); | |
675 | m->links_by_index = hashmap_free(m->links_by_index); | |
676 | ||
677 | m->dhcp_pd_subnet_ids = set_free(m->dhcp_pd_subnet_ids); | |
678 | m->networks = ordered_hashmap_free(m->networks); | |
679 | ||
680 | /* The same object may be registered with multiple names, and netdev_detach() may drop multiple entries. */ | |
681 | for (NetDev *n; (n = hashmap_first(m->netdevs)); ) | |
682 | netdev_detach(n); | |
683 | m->netdevs = hashmap_free(m->netdevs); | |
684 | ||
685 | m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name); | |
686 | ||
687 | m->wiphy_by_name = hashmap_free(m->wiphy_by_name); | |
688 | m->wiphy_by_index = hashmap_free(m->wiphy_by_index); | |
689 | ||
690 | ordered_set_free(m->address_pools); | |
691 | ||
692 | hashmap_free(m->route_table_names_by_number); | |
693 | hashmap_free(m->route_table_numbers_by_name); | |
694 | ||
695 | set_free(m->rules); | |
696 | ||
697 | sd_netlink_unref(m->rtnl); | |
698 | sd_netlink_unref(m->genl); | |
699 | sd_resolve_unref(m->resolve); | |
700 | ||
701 | m->routes = set_free(m->routes); | |
702 | ||
703 | m->nexthops_by_id = hashmap_free(m->nexthops_by_id); | |
704 | m->nexthop_ids = set_free(m->nexthop_ids); | |
705 | ||
706 | m->address_labels_by_section = hashmap_free(m->address_labels_by_section); | |
707 | ||
708 | sd_event_source_unref(m->speed_meter_event_source); | |
709 | sd_event_unref(m->event); | |
710 | ||
711 | sd_device_monitor_unref(m->device_monitor); | |
712 | ||
713 | manager_varlink_done(m); | |
714 | hashmap_free(m->polkit_registry); | |
715 | sd_bus_flush_close_unref(m->bus); | |
716 | ||
717 | free(m->dynamic_timezone); | |
718 | free(m->dynamic_hostname); | |
719 | ||
720 | safe_close(m->ethtool_fd); | |
721 | safe_close(m->persistent_storage_fd); | |
722 | ||
723 | m->fw_ctx = fw_ctx_free(m->fw_ctx); | |
724 | ||
725 | m->serialization_fd = safe_close(m->serialization_fd); | |
726 | ||
727 | return mfree(m); | |
728 | } | |
729 | ||
730 | int manager_start(Manager *m) { | |
731 | Link *link; | |
732 | int r; | |
733 | ||
734 | assert(m); | |
735 | ||
736 | log_debug("Starting..."); | |
737 | ||
738 | (void) manager_install_sysctl_monitor(m); | |
739 | ||
740 | /* Loading BPF programs requires CAP_SYS_ADMIN and CAP_BPF. | |
741 | * Drop the capabilities here, regardless if the load succeeds or not. */ | |
742 | r = drop_capability(CAP_SYS_ADMIN); | |
743 | if (r < 0) | |
744 | log_warning_errno(r, "Failed to drop CAP_SYS_ADMIN, ignoring: %m."); | |
745 | ||
746 | r = drop_capability(CAP_BPF); | |
747 | if (r < 0) | |
748 | log_warning_errno(r, "Failed to drop CAP_BPF, ignoring: %m."); | |
749 | ||
750 | manager_set_sysctl(m); | |
751 | ||
752 | r = manager_request_static_address_labels(m); | |
753 | if (r < 0) | |
754 | return r; | |
755 | ||
756 | r = manager_start_speed_meter(m); | |
757 | if (r < 0) | |
758 | return log_error_errno(r, "Failed to initialize speed meter: %m"); | |
759 | ||
760 | HASHMAP_FOREACH(link, m->links_by_index) { | |
761 | if (link->state != LINK_STATE_PENDING) | |
762 | continue; | |
763 | ||
764 | r = link_check_initialized(link); | |
765 | if (r < 0) { | |
766 | log_link_warning_errno(link, r, "Failed to check if link is initialized: %m"); | |
767 | link_enter_failed(link); | |
768 | } | |
769 | } | |
770 | ||
771 | /* The dirty handler will deal with future serialization, but the first one | |
772 | must be done explicitly. */ | |
773 | ||
774 | r = manager_save(m); | |
775 | if (r < 0) | |
776 | log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file); | |
777 | ||
778 | HASHMAP_FOREACH(link, m->links_by_index) { | |
779 | r = link_save_and_clean(link); | |
780 | if (r < 0) | |
781 | log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file); | |
782 | } | |
783 | ||
784 | log_debug("Started."); | |
785 | return 0; | |
786 | } | |
787 | ||
788 | int manager_load_config(Manager *m) { | |
789 | int r; | |
790 | ||
791 | log_debug("Loading..."); | |
792 | ||
793 | r = netdev_load(m); | |
794 | if (r < 0) | |
795 | return log_debug_errno(r, "Failed to load .netdev files: %m"); | |
796 | ||
797 | manager_clear_unmanaged_tuntap_fds(m); | |
798 | ||
799 | r = network_load(m, &m->networks); | |
800 | if (r < 0) | |
801 | return log_debug_errno(r, "Failed to load .network files: %m"); | |
802 | ||
803 | r = manager_build_dhcp_pd_subnet_ids(m); | |
804 | if (r < 0) | |
805 | return log_debug_errno(r, "Failed to build DHCP-PD subnet ID map: %m"); | |
806 | ||
807 | r = manager_build_nexthop_ids(m); | |
808 | if (r < 0) | |
809 | return log_debug_errno(r, "Failed to build nexthop ID map: %m"); | |
810 | ||
811 | log_debug("Loaded."); | |
812 | return 0; | |
813 | } | |
814 | ||
815 | int manager_enumerate_internal( | |
816 | Manager *m, | |
817 | sd_netlink *nl, | |
818 | sd_netlink_message *req, | |
819 | int (*process)(sd_netlink *, sd_netlink_message *, Manager *)) { | |
820 | ||
821 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL; | |
822 | int r; | |
823 | ||
824 | assert(m); | |
825 | assert(nl); | |
826 | assert(req); | |
827 | assert(process); | |
828 | ||
829 | r = sd_netlink_message_set_request_dump(req, true); | |
830 | if (r < 0) | |
831 | return r; | |
832 | ||
833 | r = sd_netlink_call(nl, req, 0, &reply); | |
834 | if (r < 0) | |
835 | return r; | |
836 | ||
837 | m->enumerating = true; | |
838 | for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) | |
839 | RET_GATHER(r, process(nl, reply_one, m)); | |
840 | m->enumerating = false; | |
841 | ||
842 | return r; | |
843 | } | |
844 | ||
845 | static int manager_enumerate_links(Manager *m) { | |
846 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
847 | int r; | |
848 | ||
849 | assert(m); | |
850 | assert(m->rtnl); | |
851 | ||
852 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); | |
853 | if (r < 0) | |
854 | return r; | |
855 | ||
856 | r = manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); | |
857 | if (r < 0) | |
858 | return r; | |
859 | ||
860 | req = sd_netlink_message_unref(req); | |
861 | ||
862 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); | |
863 | if (r < 0) | |
864 | return r; | |
865 | ||
866 | r = sd_rtnl_message_link_set_family(req, AF_BRIDGE); | |
867 | if (r < 0) | |
868 | return r; | |
869 | ||
870 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); | |
871 | } | |
872 | ||
873 | static int manager_enumerate_qdisc(Manager *m) { | |
874 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
875 | int r; | |
876 | ||
877 | assert(m); | |
878 | assert(m->rtnl); | |
879 | ||
880 | r = sd_rtnl_message_new_traffic_control(m->rtnl, &req, RTM_GETQDISC, 0, 0, 0); | |
881 | if (r < 0) | |
882 | return r; | |
883 | ||
884 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_qdisc); | |
885 | } | |
886 | ||
887 | static int manager_enumerate_tclass(Manager *m) { | |
888 | Link *link; | |
889 | int r = 0; | |
890 | ||
891 | assert(m); | |
892 | assert(m->rtnl); | |
893 | ||
894 | /* TC class can be enumerated only per link. See tc_dump_tclass() in net/sched/sched_api.c. */ | |
895 | ||
896 | HASHMAP_FOREACH(link, m->links_by_index) | |
897 | RET_GATHER(r, link_enumerate_tclass(link, 0)); | |
898 | ||
899 | return r; | |
900 | } | |
901 | ||
902 | static int manager_enumerate_addresses(Manager *m) { | |
903 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
904 | int r; | |
905 | ||
906 | assert(m); | |
907 | assert(m->rtnl); | |
908 | ||
909 | r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0); | |
910 | if (r < 0) | |
911 | return r; | |
912 | ||
913 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_address); | |
914 | } | |
915 | ||
916 | static int manager_enumerate_neighbors(Manager *m) { | |
917 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
918 | int r; | |
919 | ||
920 | assert(m); | |
921 | assert(m->rtnl); | |
922 | ||
923 | r = sd_rtnl_message_new_neigh(m->rtnl, &req, RTM_GETNEIGH, 0, AF_UNSPEC); | |
924 | if (r < 0) | |
925 | return r; | |
926 | ||
927 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_neighbor); | |
928 | } | |
929 | ||
930 | static int manager_enumerate_routes(Manager *m) { | |
931 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
932 | int r; | |
933 | ||
934 | assert(m); | |
935 | assert(m->rtnl); | |
936 | ||
937 | if (!m->manage_foreign_routes) | |
938 | return 0; | |
939 | ||
940 | r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0); | |
941 | if (r < 0) | |
942 | return r; | |
943 | ||
944 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_route); | |
945 | } | |
946 | ||
947 | static int manager_enumerate_rules(Manager *m) { | |
948 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
949 | int r; | |
950 | ||
951 | assert(m); | |
952 | assert(m->rtnl); | |
953 | ||
954 | if (!m->manage_foreign_rules) | |
955 | return 0; | |
956 | ||
957 | r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0); | |
958 | if (r < 0) | |
959 | return r; | |
960 | ||
961 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_rule); | |
962 | } | |
963 | ||
964 | static int manager_enumerate_nexthop(Manager *m) { | |
965 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
966 | int r; | |
967 | ||
968 | assert(m); | |
969 | assert(m->rtnl); | |
970 | ||
971 | if (!m->manage_foreign_nexthops) | |
972 | return 0; | |
973 | ||
974 | r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0); | |
975 | if (r < 0) | |
976 | return r; | |
977 | ||
978 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop); | |
979 | } | |
980 | ||
981 | static int manager_enumerate_nl80211_wiphy(Manager *m) { | |
982 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
983 | int r; | |
984 | ||
985 | assert(m); | |
986 | assert(m->genl); | |
987 | ||
988 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_WIPHY, &req); | |
989 | if (r < 0) | |
990 | return r; | |
991 | ||
992 | return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_wiphy); | |
993 | } | |
994 | ||
995 | static int manager_enumerate_nl80211_config(Manager *m) { | |
996 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
997 | int r; | |
998 | ||
999 | assert(m); | |
1000 | assert(m->genl); | |
1001 | ||
1002 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &req); | |
1003 | if (r < 0) | |
1004 | return r; | |
1005 | ||
1006 | return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_config); | |
1007 | } | |
1008 | ||
1009 | static int manager_enumerate_nl80211_mlme(Manager *m) { | |
1010 | Link *link; | |
1011 | int r; | |
1012 | ||
1013 | assert(m); | |
1014 | assert(m->genl); | |
1015 | ||
1016 | HASHMAP_FOREACH(link, m->links_by_index) { | |
1017 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1018 | ||
1019 | if (link->wlan_iftype != NL80211_IFTYPE_STATION) | |
1020 | continue; | |
1021 | ||
1022 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &req); | |
1023 | if (r < 0) | |
1024 | return r; | |
1025 | ||
1026 | r = sd_netlink_message_append_u32(req, NL80211_ATTR_IFINDEX, link->ifindex); | |
1027 | if (r < 0) | |
1028 | return r; | |
1029 | ||
1030 | r = manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_mlme); | |
1031 | if (r < 0) | |
1032 | return r; | |
1033 | } | |
1034 | ||
1035 | return 0; | |
1036 | } | |
1037 | ||
1038 | int manager_enumerate(Manager *m) { | |
1039 | int r; | |
1040 | ||
1041 | log_debug("Enumerating..."); | |
1042 | ||
1043 | r = manager_enumerate_links(m); | |
1044 | if (r < 0) | |
1045 | return log_error_errno(r, "Could not enumerate links: %m"); | |
1046 | ||
1047 | /* If the kernel is built without CONFIG_NET_SCHED, the below will fail with -EOPNOTSUPP. */ | |
1048 | r = manager_enumerate_qdisc(m); | |
1049 | if (r == -EOPNOTSUPP) | |
1050 | log_debug_errno(r, "Could not enumerate QDiscs, ignoring: %m"); | |
1051 | else if (r < 0) | |
1052 | return log_error_errno(r, "Could not enumerate QDisc: %m"); | |
1053 | ||
1054 | /* If the kernel is built without CONFIG_NET_CLS, the below will fail with -EOPNOTSUPP. */ | |
1055 | r = manager_enumerate_tclass(m); | |
1056 | if (r == -EOPNOTSUPP) | |
1057 | log_debug_errno(r, "Could not enumerate TClasses, ignoring: %m"); | |
1058 | else if (r < 0) | |
1059 | return log_error_errno(r, "Could not enumerate TClass: %m"); | |
1060 | ||
1061 | r = manager_enumerate_addresses(m); | |
1062 | if (r < 0) | |
1063 | return log_error_errno(r, "Could not enumerate addresses: %m"); | |
1064 | ||
1065 | r = manager_enumerate_neighbors(m); | |
1066 | if (r < 0) | |
1067 | return log_error_errno(r, "Could not enumerate neighbors: %m"); | |
1068 | ||
1069 | r = manager_enumerate_nexthop(m); | |
1070 | if (r < 0) | |
1071 | return log_error_errno(r, "Could not enumerate nexthops: %m"); | |
1072 | ||
1073 | r = manager_enumerate_routes(m); | |
1074 | if (r < 0) | |
1075 | return log_error_errno(r, "Could not enumerate routes: %m"); | |
1076 | ||
1077 | /* If the kernel is built without CONFIG_FIB_RULES, the below will fail with -EOPNOTSUPP. */ | |
1078 | r = manager_enumerate_rules(m); | |
1079 | if (r == -EOPNOTSUPP) | |
1080 | log_debug_errno(r, "Could not enumerate routing policy rules, ignoring: %m"); | |
1081 | else if (r < 0) | |
1082 | return log_error_errno(r, "Could not enumerate routing policy rules: %m"); | |
1083 | ||
1084 | /* If the kernel is built without CONFIG_WIRELESS, the below will fail with -EOPNOTSUPP. */ | |
1085 | r = manager_enumerate_nl80211_wiphy(m); | |
1086 | if (r == -EOPNOTSUPP) | |
1087 | log_debug_errno(r, "Could not enumerate wireless LAN phy, ignoring: %m"); | |
1088 | else if (r < 0) | |
1089 | return log_error_errno(r, "Could not enumerate wireless LAN phy: %m"); | |
1090 | ||
1091 | r = manager_enumerate_nl80211_config(m); | |
1092 | if (r == -EOPNOTSUPP) | |
1093 | log_debug_errno(r, "Could not enumerate wireless LAN interfaces, ignoring: %m"); | |
1094 | else if (r < 0) | |
1095 | return log_error_errno(r, "Could not enumerate wireless LAN interfaces: %m"); | |
1096 | ||
1097 | r = manager_enumerate_nl80211_mlme(m); | |
1098 | if (r == -EOPNOTSUPP) | |
1099 | log_debug_errno(r, "Could not enumerate wireless LAN stations, ignoring: %m"); | |
1100 | else if (r < 0) | |
1101 | return log_error_errno(r, "Could not enumerate wireless LAN stations: %m"); | |
1102 | ||
1103 | log_debug("Enumeration completed."); | |
1104 | return 0; | |
1105 | } | |
1106 | ||
1107 | static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { | |
1108 | const sd_bus_error *e; | |
1109 | int r; | |
1110 | ||
1111 | assert(m); | |
1112 | ||
1113 | e = sd_bus_message_get_error(m); | |
1114 | if (e) { | |
1115 | r = sd_bus_error_get_errno(e); | |
1116 | log_warning_errno(r, "Could not set hostname: %s", bus_error_message(e, r)); | |
1117 | } | |
1118 | ||
1119 | return 1; | |
1120 | } | |
1121 | ||
1122 | int manager_set_hostname(Manager *m, const char *hostname) { | |
1123 | int r; | |
1124 | ||
1125 | log_debug("Setting transient hostname: '%s'", strna(hostname)); | |
1126 | ||
1127 | r = free_and_strdup_warn(&m->dynamic_hostname, hostname); | |
1128 | if (r < 0) | |
1129 | return r; | |
1130 | ||
1131 | if (sd_bus_is_ready(m->bus) <= 0) { | |
1132 | log_debug("Not connected to system bus, setting system hostname later."); | |
1133 | return 0; | |
1134 | } | |
1135 | ||
1136 | r = bus_call_method_async( | |
1137 | m->bus, | |
1138 | NULL, | |
1139 | bus_hostname, | |
1140 | "SetHostname", | |
1141 | set_hostname_handler, | |
1142 | m, | |
1143 | "sb", | |
1144 | hostname, | |
1145 | false); | |
1146 | if (r < 0) | |
1147 | return log_error_errno(r, "Could not set transient hostname: %m"); | |
1148 | ||
1149 | return 0; | |
1150 | } | |
1151 | ||
1152 | static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { | |
1153 | const sd_bus_error *e; | |
1154 | int r; | |
1155 | ||
1156 | assert(m); | |
1157 | ||
1158 | e = sd_bus_message_get_error(m); | |
1159 | if (e) { | |
1160 | r = sd_bus_error_get_errno(e); | |
1161 | log_warning_errno(r, "Could not set timezone: %s", bus_error_message(e, r)); | |
1162 | } | |
1163 | ||
1164 | return 1; | |
1165 | } | |
1166 | ||
1167 | int manager_set_timezone(Manager *m, const char *tz) { | |
1168 | int r; | |
1169 | ||
1170 | assert(m); | |
1171 | assert(tz); | |
1172 | ||
1173 | log_debug("Setting system timezone: '%s'", tz); | |
1174 | r = free_and_strdup_warn(&m->dynamic_timezone, tz); | |
1175 | if (r < 0) | |
1176 | return r; | |
1177 | ||
1178 | if (sd_bus_is_ready(m->bus) <= 0) { | |
1179 | log_debug("Not connected to system bus, setting system timezone later."); | |
1180 | return 0; | |
1181 | } | |
1182 | ||
1183 | r = bus_call_method_async( | |
1184 | m->bus, | |
1185 | NULL, | |
1186 | bus_timedate, | |
1187 | "SetTimezone", | |
1188 | set_timezone_handler, | |
1189 | m, | |
1190 | "sb", | |
1191 | tz, | |
1192 | false); | |
1193 | if (r < 0) | |
1194 | return log_error_errno(r, "Could not set timezone: %m"); | |
1195 | ||
1196 | return 0; | |
1197 | } | |
1198 | ||
1199 | int manager_reload(Manager *m, sd_bus_message *message) { | |
1200 | Link *link; | |
1201 | int r; | |
1202 | ||
1203 | assert(m); | |
1204 | ||
1205 | log_debug("Reloading..."); | |
1206 | (void) notify_reloading(); | |
1207 | ||
1208 | r = netdev_reload(m); | |
1209 | if (r < 0) { | |
1210 | log_debug_errno(r, "Failed to reload .netdev files: %m"); | |
1211 | goto finish; | |
1212 | } | |
1213 | ||
1214 | r = network_reload(m); | |
1215 | if (r < 0) { | |
1216 | log_debug_errno(r, "Failed to reload .network files: %m"); | |
1217 | goto finish; | |
1218 | } | |
1219 | ||
1220 | HASHMAP_FOREACH(link, m->links_by_index) | |
1221 | (void) link_reconfigure_full(link, /* flags = */ 0, message, | |
1222 | /* counter = */ message ? &m->reloading : NULL); | |
1223 | ||
1224 | log_debug("Reloaded."); | |
1225 | r = 0; | |
1226 | finish: | |
1227 | (void) sd_notify(/* unset_environment= */ false, NOTIFY_READY_MESSAGE); | |
1228 | return r; | |
1229 | } |