]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
f579559b | 2 | |
9aa5d8ba | 3 | #include <netinet/in.h> |
091a364c | 4 | #include <sys/socket.h> |
9aa5d8ba | 5 | #include <unistd.h> |
7b9da386 | 6 | #include <linux/if.h> |
bce67bbe | 7 | #include <linux/fib_rules.h> |
c16c7808 | 8 | #include <linux/nexthop.h> |
96f5f9ef | 9 | #include <linux/nl80211.h> |
3bef724f | 10 | |
07630cea | 11 | #include "sd-netlink.h" |
fc2f9534 | 12 | |
b5efdb8a | 13 | #include "alloc-util.h" |
f63e09ef | 14 | #include "bus-error.h" |
b607fd3f | 15 | #include "bus-locator.h" |
ac9f55ed | 16 | #include "bus-log-control-api.h" |
269e4d2d | 17 | #include "bus-polkit.h" |
a97dcc12 | 18 | #include "bus-util.h" |
6daaeafe | 19 | #include "common-signal.h" |
07630cea | 20 | #include "conf-parser.h" |
28db6fbf | 21 | #include "constants.h" |
af7a86b8 | 22 | #include "daemon-util.h" |
1fd3ac1e YW |
23 | #include "device-private.h" |
24 | #include "device-util.h" | |
482d1aeb | 25 | #include "dns-domain.h" |
013359ac | 26 | #include "env-util.h" |
3ffd4af2 | 27 | #include "fd-util.h" |
0d39fa9c | 28 | #include "fileio.h" |
761cf19d | 29 | #include "firewall-util.h" |
af664001 | 30 | #include "fs-util.h" |
baa6a42d | 31 | #include "initrd-util.h" |
4f5f911e | 32 | #include "local-addresses.h" |
07630cea | 33 | #include "netlink-util.h" |
dc0d4078 | 34 | #include "network-internal.h" |
bfbf150e | 35 | #include "networkd-address-pool.h" |
3b6a3bde | 36 | #include "networkd-address.h" |
cf72a786 | 37 | #include "networkd-dhcp-server-bus.h" |
ca5ad760 | 38 | #include "networkd-dhcp6.h" |
6a1af3d4 | 39 | #include "networkd-link-bus.h" |
23f53b99 | 40 | #include "networkd-manager.h" |
c5c74d85 LP |
41 | #include "networkd-manager-bus.h" |
42 | #include "networkd-manager-varlink.h" | |
1939ebeb | 43 | #include "networkd-neighbor.h" |
ceac2c2b | 44 | #include "networkd-network-bus.h" |
75156ccb | 45 | #include "networkd-nexthop.h" |
19d9a5ad | 46 | #include "networkd-queue.h" |
3b6a3bde | 47 | #include "networkd-route.h" |
ca183bf8 | 48 | #include "networkd-routing-policy-rule.h" |
a879e1a4 | 49 | #include "networkd-speed-meter.h" |
3b5a4fc6 | 50 | #include "networkd-state-file.h" |
96f5f9ef | 51 | #include "networkd-wifi.h" |
edb69db2 | 52 | #include "networkd-wiphy.h" |
00616955 | 53 | #include "ordered-set.h" |
b0c82192 | 54 | #include "path-lookup.h" |
07630cea | 55 | #include "path-util.h" |
828a81a9 | 56 | #include "qdisc.h" |
92b555aa | 57 | #include "selinux-util.h" |
07630cea | 58 | #include "set.h" |
ab76be55 | 59 | #include "signal-util.h" |
d31f33e3 | 60 | #include "stat-util.h" |
21486d9e | 61 | #include "strv.h" |
4b600505 | 62 | #include "sysctl-util.h" |
828a81a9 | 63 | #include "tclass.h" |
e4de7287 | 64 | #include "tmpfile-util.h" |
af7a86b8 | 65 | #include "tuntap.h" |
82f52245 | 66 | #include "udev-util.h" |
505f8da7 | 67 | |
48d0248e YW |
68 | /* use 128 MB for receive socket kernel queue. */ |
69 | #define RCVBUF_SIZE (128*1024*1024) | |
be660c37 | 70 | |
19070062 | 71 | static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { |
99534007 | 72 | Manager *m = ASSERT_PTR(userdata); |
a39a9ac8 | 73 | Link *link; |
9c0a72f9 TG |
74 | int b, r; |
75 | ||
19070062 | 76 | assert(message); |
9c0a72f9 TG |
77 | |
78 | r = sd_bus_message_read(message, "b", &b); | |
79 | if (r < 0) { | |
d67b1d18 | 80 | bus_log_parse_error(r); |
9c0a72f9 TG |
81 | return 0; |
82 | } | |
83 | ||
84 | if (b) | |
85 | return 0; | |
86 | ||
a39a9ac8 | 87 | log_debug("Coming back from suspend, reconfiguring all connections..."); |
9c0a72f9 | 88 | |
a39a9ac8 YW |
89 | HASHMAP_FOREACH(link, m->links_by_index) { |
90 | r = link_reconfigure(link, /* force = */ true); | |
91 | if (r < 0) { | |
92 | log_link_warning_errno(link, r, "Failed to reconfigure interface: %m"); | |
93 | link_enter_failed(link); | |
94 | } | |
95 | } | |
9c0a72f9 TG |
96 | |
97 | return 0; | |
98 | } | |
99 | ||
d7afd945 | 100 | static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { |
99534007 | 101 | Manager *m = ASSERT_PTR(userdata); |
9c0a72f9 | 102 | |
d7afd945 | 103 | assert(message); |
9c0a72f9 | 104 | |
d7afd945 LP |
105 | /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */ |
106 | if (m->dynamic_hostname) | |
107 | (void) manager_set_hostname(m, m->dynamic_hostname); | |
108 | if (m->dynamic_timezone) | |
109 | (void) manager_set_timezone(m, m->dynamic_timezone); | |
ccffa166 | 110 | if (m->product_uuid_requested) |
4e26a5ba | 111 | (void) manager_request_product_uuid(m); |
9c0a72f9 | 112 | |
d7afd945 LP |
113 | return 0; |
114 | } | |
9c0a72f9 | 115 | |
96243149 | 116 | static int manager_connect_bus(Manager *m) { |
d7afd945 LP |
117 | int r; |
118 | ||
119 | assert(m); | |
96243149 | 120 | assert(!m->bus); |
7d6884b6 | 121 | |
621e4509 | 122 | r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network"); |
9c0a72f9 | 123 | if (r < 0) |
d7afd945 | 124 | return log_error_errno(r, "Failed to connect to bus: %m"); |
9c0a72f9 | 125 | |
6e194652 | 126 | r = bus_add_implementation(m->bus, &manager_object, m); |
e331e246 | 127 | if (r < 0) |
6e194652 | 128 | return r; |
e331e246 | 129 | |
ac9f55ed LP |
130 | r = bus_log_control_api_register(m->bus); |
131 | if (r < 0) | |
132 | return r; | |
133 | ||
696fc836 | 134 | r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL); |
e331e246 | 135 | if (r < 0) |
0c0b9306 | 136 | return log_error_errno(r, "Failed to request name: %m"); |
e331e246 TG |
137 | |
138 | r = sd_bus_attach_event(m->bus, m->event, 0); | |
139 | if (r < 0) | |
140 | return log_error_errno(r, "Failed to attach bus to event loop: %m"); | |
141 | ||
d7afd945 LP |
142 | r = sd_bus_match_signal_async( |
143 | m->bus, | |
cad43595 | 144 | NULL, |
d7afd945 LP |
145 | "org.freedesktop.DBus.Local", |
146 | NULL, | |
147 | "org.freedesktop.DBus.Local", | |
148 | "Connected", | |
149 | on_connected, NULL, m); | |
150 | if (r < 0) | |
151 | return log_error_errno(r, "Failed to request match on Connected signal: %m"); | |
152 | ||
d962e737 | 153 | r = bus_match_signal_async( |
d7afd945 | 154 | m->bus, |
cad43595 | 155 | NULL, |
d962e737 | 156 | bus_login_mgr, |
d7afd945 LP |
157 | "PrepareForSleep", |
158 | match_prepare_for_sleep, NULL, m); | |
159 | if (r < 0) | |
160 | log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m"); | |
7901cea1 | 161 | |
9c0a72f9 TG |
162 | return 0; |
163 | } | |
164 | ||
1fd3ac1e YW |
165 | static int manager_process_uevent(sd_device_monitor *monitor, sd_device *device, void *userdata) { |
166 | Manager *m = ASSERT_PTR(userdata); | |
167 | sd_device_action_t action; | |
1fd3ac1e YW |
168 | int r; |
169 | ||
170 | assert(device); | |
171 | ||
172 | r = sd_device_get_action(device, &action); | |
173 | if (r < 0) | |
174 | return log_device_warning_errno(device, r, "Failed to get udev action, ignoring: %m"); | |
175 | ||
fb53ee0a | 176 | if (device_in_subsystem(device, "net")) |
1fd3ac1e | 177 | r = manager_udev_process_link(m, device, action); |
fb53ee0a | 178 | else if (device_in_subsystem(device, "ieee80211")) |
c49d5362 | 179 | r = manager_udev_process_wiphy(m, device, action); |
fb53ee0a | 180 | else if (device_in_subsystem(device, "rfkill")) |
8642e04b | 181 | r = manager_udev_process_rfkill(m, device, action); |
1fd3ac1e YW |
182 | if (r < 0) |
183 | log_device_warning_errno(device, r, "Failed to process \"%s\" uevent, ignoring: %m", | |
184 | device_action_to_string(action)); | |
185 | ||
186 | return 0; | |
187 | } | |
188 | ||
5fae368b TG |
189 | static int manager_connect_udev(Manager *m) { |
190 | int r; | |
f579559b | 191 | |
d31f33e3 YW |
192 | /* udev does not initialize devices inside containers, so we rely on them being already |
193 | * initialized before entering the container. */ | |
82f52245 | 194 | if (!udev_available()) |
5fae368b | 195 | return 0; |
f579559b | 196 | |
d2ebf952 | 197 | r = sd_device_monitor_new(&m->device_monitor); |
02b59d57 | 198 | if (r < 0) |
d2ebf952 | 199 | return log_error_errno(r, "Failed to initialize device monitor: %m"); |
02b59d57 | 200 | |
d2ebf952 YW |
201 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL); |
202 | if (r < 0) | |
1fd3ac1e | 203 | return log_error_errno(r, "Could not add device monitor filter for net subsystem: %m"); |
505f8da7 | 204 | |
c49d5362 YW |
205 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "ieee80211", NULL); |
206 | if (r < 0) | |
207 | return log_error_errno(r, "Could not add device monitor filter for ieee80211 subsystem: %m"); | |
208 | ||
8642e04b YW |
209 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "rfkill", NULL); |
210 | if (r < 0) | |
211 | return log_error_errno(r, "Could not add device monitor filter for rfkill subsystem: %m"); | |
212 | ||
deb2b734 | 213 | r = sd_device_monitor_attach_event(m->device_monitor, m->event); |
5fae368b | 214 | if (r < 0) |
d2ebf952 | 215 | return log_error_errno(r, "Failed to attach event to device monitor: %m"); |
505f8da7 | 216 | |
1fd3ac1e | 217 | r = sd_device_monitor_start(m->device_monitor, manager_process_uevent, m); |
505f8da7 | 218 | if (r < 0) |
d2ebf952 | 219 | return log_error_errno(r, "Failed to start device monitor: %m"); |
11a7f229 | 220 | |
505f8da7 TG |
221 | return 0; |
222 | } | |
f579559b | 223 | |
af7a86b8 YW |
224 | static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) { |
225 | _cleanup_strv_free_ char **names = NULL; | |
254d1313 | 226 | int n, rtnl_fd = -EBADF; |
5fae368b | 227 | |
af7a86b8 YW |
228 | assert(m); |
229 | assert(ret_rtnl_fd); | |
230 | ||
231 | n = sd_listen_fds_with_names(/* unset_environment = */ true, &names); | |
232 | if (n < 0) | |
233 | return n; | |
234 | ||
235 | if (strv_length(names) != (size_t) n) | |
5fae368b TG |
236 | return -EINVAL; |
237 | ||
af7a86b8 YW |
238 | for (int i = 0; i < n; i++) { |
239 | int fd = i + SD_LISTEN_FDS_START; | |
240 | ||
5fae368b | 241 | if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { |
af7a86b8 YW |
242 | if (rtnl_fd >= 0) { |
243 | log_debug("Received multiple netlink socket, ignoring."); | |
244 | safe_close(fd); | |
245 | continue; | |
246 | } | |
5fae368b TG |
247 | |
248 | rtnl_fd = fd; | |
af7a86b8 | 249 | continue; |
5fae368b | 250 | } |
5fae368b | 251 | |
af7a86b8 YW |
252 | if (manager_add_tuntap_fd(m, fd, names[i]) >= 0) |
253 | continue; | |
254 | ||
255 | if (m->test_mode) | |
256 | safe_close(fd); | |
257 | else | |
258 | close_and_notify_warn(fd, names[i]); | |
259 | } | |
260 | ||
261 | *ret_rtnl_fd = rtnl_fd; | |
262 | return 0; | |
5fae368b TG |
263 | } |
264 | ||
05d0c2e3 JT |
265 | static int manager_connect_genl(Manager *m) { |
266 | int r; | |
267 | ||
268 | assert(m); | |
269 | ||
270 | r = sd_genl_socket_open(&m->genl); | |
271 | if (r < 0) | |
272 | return r; | |
273 | ||
78cca583 | 274 | r = sd_netlink_increase_rxbuf(m->genl, RCVBUF_SIZE); |
05d0c2e3 | 275 | if (r < 0) |
8c63924c | 276 | log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m"); |
05d0c2e3 JT |
277 | |
278 | r = sd_netlink_attach_event(m->genl, m->event, 0); | |
279 | if (r < 0) | |
280 | return r; | |
281 | ||
96f5f9ef YW |
282 | r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_CONFIG, 0, |
283 | &manager_genl_process_nl80211_config, NULL, m, "network-genl_process_nl80211_config"); | |
284 | if (r < 0 && r != -EOPNOTSUPP) | |
285 | return r; | |
286 | ||
287 | r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_MLME, 0, | |
288 | &manager_genl_process_nl80211_mlme, NULL, m, "network-genl_process_nl80211_mlme"); | |
289 | if (r < 0 && r != -EOPNOTSUPP) | |
290 | return r; | |
291 | ||
05d0c2e3 JT |
292 | return 0; |
293 | } | |
294 | ||
26a8be48 YW |
295 | static int manager_setup_rtnl_filter(Manager *manager) { |
296 | struct sock_filter filter[] = { | |
297 | /* Check the packet length. */ | |
298 | BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ | |
299 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr), 1, 0), /* A (packet length) >= sizeof(struct nlmsghdr) ? */ | |
300 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
301 | /* Always accept multipart message. */ | |
302 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_flags)), /* A <- message flags */ | |
303 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NLM_F_MULTI), 0, 1), /* message flags has NLM_F_MULTI ? */ | |
304 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
305 | /* Accept all message types except for RTM_NEWNEIGH or RTM_DELNEIGH. */ | |
306 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_type)), /* A <- message type */ | |
307 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_NEWNEIGH), 2, 0), /* message type == RTM_NEWNEIGH ? */ | |
308 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_DELNEIGH), 1, 0), /* message type == RTM_DELNEIGH ? */ | |
309 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
310 | /* Check the packet length. */ | |
311 | BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ | |
312 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr) + sizeof(struct ndmsg), 1, 0), | |
313 | /* packet length >= sizeof(struct nlmsghdr) + sizeof(struct ndmsg) ? */ | |
314 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
315 | /* Reject the message when the neighbor state does not have NUD_PERMANENT flag. */ | |
316 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, sizeof(struct nlmsghdr) + offsetof(struct ndmsg, ndm_state)), | |
317 | /* A <- neighbor state */ | |
318 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NUD_PERMANENT), 1, 0), /* neighbor state has NUD_PERMANENT ? */ | |
319 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
320 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
321 | }; | |
322 | ||
323 | assert(manager); | |
324 | assert(manager->rtnl); | |
325 | ||
326 | return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter); | |
327 | } | |
328 | ||
af7a86b8 YW |
329 | static int manager_connect_rtnl(Manager *m, int fd) { |
330 | _unused_ _cleanup_close_ int fd_close = fd; | |
331 | int r; | |
505f8da7 TG |
332 | |
333 | assert(m); | |
505f8da7 | 334 | |
af7a86b8 YW |
335 | /* This takes input fd. */ |
336 | ||
5fae368b | 337 | if (fd < 0) |
1c4baffc | 338 | r = sd_netlink_open(&m->rtnl); |
5fae368b | 339 | else |
1c4baffc | 340 | r = sd_netlink_open_fd(&m->rtnl, fd); |
505f8da7 TG |
341 | if (r < 0) |
342 | return r; | |
af7a86b8 | 343 | TAKE_FD(fd_close); |
505f8da7 | 344 | |
e13af7bd YW |
345 | /* Bump receiver buffer, but only if we are not called via socket activation, as in that |
346 | * case systemd sets the receive buffer size for us, and the value in the .socket unit | |
347 | * should take full effect. */ | |
348 | if (fd < 0) { | |
78cca583 | 349 | r = sd_netlink_increase_rxbuf(m->rtnl, RCVBUF_SIZE); |
e13af7bd YW |
350 | if (r < 0) |
351 | log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m"); | |
352 | } | |
f579559b | 353 | |
1c4baffc | 354 | r = sd_netlink_attach_event(m->rtnl, m->event, 0); |
505f8da7 TG |
355 | if (r < 0) |
356 | return r; | |
f579559b | 357 | |
8dfed23d | 358 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
359 | if (r < 0) |
360 | return r; | |
505f8da7 | 361 | |
8dfed23d | 362 | r = netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
363 | if (r < 0) |
364 | return r; | |
45af44d4 | 365 | |
828a81a9 YW |
366 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); |
367 | if (r < 0) | |
368 | return r; | |
369 | ||
370 | r = netlink_add_match(m->rtnl, NULL, RTM_DELQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); | |
371 | if (r < 0) | |
372 | return r; | |
373 | ||
374 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); | |
375 | if (r < 0) | |
376 | return r; | |
377 | ||
378 | r = netlink_add_match(m->rtnl, NULL, RTM_DELTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); | |
379 | if (r < 0) | |
380 | return r; | |
381 | ||
8dfed23d | 382 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
383 | if (r < 0) |
384 | return r; | |
385 | ||
8dfed23d | 386 | r = netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
387 | if (r < 0) |
388 | return r; | |
389 | ||
8dfed23d | 390 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
391 | if (r < 0) |
392 | return r; | |
393 | ||
8dfed23d | 394 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
395 | if (r < 0) |
396 | return r; | |
397 | ||
8dfed23d | 398 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
399 | if (r < 0) |
400 | return r; | |
401 | ||
8dfed23d | 402 | r = netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
403 | if (r < 0) |
404 | return r; | |
405 | ||
8dfed23d | 406 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
407 | if (r < 0) |
408 | return r; | |
409 | ||
8dfed23d | 410 | r = netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
411 | if (r < 0) |
412 | return r; | |
413 | ||
8dfed23d | 414 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
415 | if (r < 0) |
416 | return r; | |
417 | ||
8dfed23d | 418 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
419 | if (r < 0) |
420 | return r; | |
421 | ||
26a8be48 | 422 | return manager_setup_rtnl_filter(m); |
45af44d4 | 423 | } |
505f8da7 | 424 | |
2e1113b7 YW |
425 | static int manager_post_handler(sd_event_source *s, void *userdata) { |
426 | Manager *manager = ASSERT_PTR(userdata); | |
84de38c5 | 427 | |
85a6f300 | 428 | (void) manager_process_remove_requests(manager); |
e36d8e48 | 429 | (void) manager_process_requests(manager); |
2e1113b7 YW |
430 | (void) manager_clean_all(manager); |
431 | return 0; | |
84de38c5 TG |
432 | } |
433 | ||
ab76be55 | 434 | static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
99534007 | 435 | Manager *m = ASSERT_PTR(userdata); |
ab76be55 | 436 | |
ab76be55 ZJS |
437 | m->restarting = false; |
438 | ||
439 | log_debug("Terminate operation initiated."); | |
440 | ||
441 | return sd_event_exit(sd_event_source_get_event(s), 0); | |
442 | } | |
443 | ||
444 | static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { | |
99534007 | 445 | Manager *m = ASSERT_PTR(userdata); |
ab76be55 | 446 | |
ab76be55 ZJS |
447 | m->restarting = true; |
448 | ||
449 | log_debug("Restart operation initiated."); | |
450 | ||
451 | return sd_event_exit(sd_event_source_get_event(s), 0); | |
452 | } | |
453 | ||
0e07cdb0 LP |
454 | static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
455 | Manager *m = ASSERT_PTR(userdata); | |
456 | ||
1e869a5d | 457 | (void) manager_reload(m, /* message = */ NULL); |
0e07cdb0 LP |
458 | |
459 | return 0; | |
460 | } | |
461 | ||
ea853de5 YW |
462 | static int manager_set_keep_configuration(Manager *m) { |
463 | int r; | |
464 | ||
465 | assert(m); | |
466 | ||
467 | if (in_initrd()) { | |
468 | log_debug("Running in initrd, keep DHCPv4 addresses on stopping networkd by default."); | |
469 | m->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP; | |
470 | return 0; | |
471 | } | |
472 | ||
473 | r = path_is_network_fs("/"); | |
474 | if (r < 0) | |
475 | return log_error_errno(r, "Failed to detect if root is network filesystem: %m"); | |
476 | if (r == 0) { | |
477 | m->keep_configuration = _KEEP_CONFIGURATION_INVALID; | |
478 | return 0; | |
479 | } | |
480 | ||
481 | log_debug("Running on network filesystem, enabling KeepConfiguration= by default."); | |
482 | m->keep_configuration = KEEP_CONFIGURATION_YES; | |
483 | return 0; | |
484 | } | |
485 | ||
4c78dc17 | 486 | int manager_setup(Manager *m) { |
254d1313 | 487 | _cleanup_close_ int rtnl_fd = -EBADF; |
45af44d4 | 488 | int r; |
f579559b | 489 | |
96243149 | 490 | assert(m); |
5fae368b | 491 | |
3534a043 YW |
492 | r = sd_event_default(&m->event); |
493 | if (r < 0) | |
494 | return r; | |
495 | ||
05e21627 | 496 | (void) sd_event_set_watchdog(m->event, true); |
0e07cdb0 LP |
497 | (void) sd_event_add_signal(m->event, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m); |
498 | (void) sd_event_add_signal(m->event, NULL, SIGINT | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m); | |
499 | (void) sd_event_add_signal(m->event, NULL, SIGUSR2 | SD_EVENT_SIGNAL_PROCMASK, signal_restart_callback, m); | |
500 | (void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, signal_reload_callback, m); | |
6daaeafe LP |
501 | (void) sd_event_add_signal(m->event, NULL, (SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL); |
502 | ||
503 | r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL); | |
504 | if (r < 0) | |
505 | log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m"); | |
5fae368b | 506 | |
2e1113b7 | 507 | r = sd_event_add_post(m->event, NULL, manager_post_handler, m); |
84de38c5 TG |
508 | if (r < 0) |
509 | return r; | |
510 | ||
af7a86b8 YW |
511 | r = manager_listen_fds(m, &rtnl_fd); |
512 | if (r < 0) | |
513 | return r; | |
514 | ||
515 | r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd)); | |
45af44d4 TG |
516 | if (r < 0) |
517 | return r; | |
518 | ||
05d0c2e3 JT |
519 | r = manager_connect_genl(m); |
520 | if (r < 0) | |
521 | return r; | |
522 | ||
4c78dc17 | 523 | if (m->test_mode) |
96243149 YW |
524 | return 0; |
525 | ||
c5c74d85 LP |
526 | r = manager_connect_varlink(m); |
527 | if (r < 0) | |
528 | return r; | |
529 | ||
96243149 YW |
530 | r = manager_connect_bus(m); |
531 | if (r < 0) | |
532 | return r; | |
533 | ||
5fae368b TG |
534 | r = manager_connect_udev(m); |
535 | if (r < 0) | |
536 | return r; | |
45af44d4 | 537 | |
05d0c2e3 JT |
538 | r = sd_resolve_default(&m->resolve); |
539 | if (r < 0) | |
540 | return r; | |
541 | ||
542 | r = sd_resolve_attach_event(m->resolve, m->event, 0); | |
543 | if (r < 0) | |
544 | return r; | |
545 | ||
ed76f585 | 546 | r = address_pool_setup_default(m); |
5fae368b TG |
547 | if (r < 0) |
548 | return r; | |
f579559b | 549 | |
ea853de5 YW |
550 | r = manager_set_keep_configuration(m); |
551 | if (r < 0) | |
552 | return r; | |
553 | ||
96243149 YW |
554 | m->state_file = strdup("/run/systemd/netif/state"); |
555 | if (!m->state_file) | |
556 | return -ENOMEM; | |
557 | ||
558 | return 0; | |
559 | } | |
560 | ||
013359ac YW |
561 | static int persistent_storage_open(void) { |
562 | _cleanup_close_ int fd = -EBADF; | |
f90eb086 YW |
563 | int r; |
564 | ||
013359ac YW |
565 | r = getenv_bool("SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY"); |
566 | if (r < 0 && r != -ENXIO) | |
567 | return log_debug_errno(r, "Failed to parse $SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY environment variable, ignoring: %m"); | |
568 | if (r <= 0) | |
569 | return -EBADF; | |
f90eb086 | 570 | |
fb6f98ae | 571 | fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY); |
013359ac YW |
572 | if (fd < 0) |
573 | return log_debug_errno(errno, "Failed to open /var/lib/systemd/network/, ignoring: %m"); | |
f90eb086 | 574 | |
013359ac YW |
575 | r = fd_is_read_only_fs(fd); |
576 | if (r < 0) | |
577 | return log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m"); | |
578 | if (r > 0) | |
579 | return log_debug_errno(SYNTHETIC_ERRNO(EROFS), "The directory /var/lib/systemd/network/ is on read-only filesystem."); | |
f90eb086 | 580 | |
013359ac | 581 | return TAKE_FD(fd); |
f90eb086 YW |
582 | } |
583 | ||
4c78dc17 | 584 | int manager_new(Manager **ret, bool test_mode) { |
96243149 | 585 | _cleanup_(manager_freep) Manager *m = NULL; |
f579559b | 586 | |
96243149 YW |
587 | m = new(Manager, 1); |
588 | if (!m) | |
589 | return -ENOMEM; | |
590 | ||
591 | *m = (Manager) { | |
ea853de5 | 592 | .keep_configuration = _KEEP_CONFIGURATION_INVALID, |
932ef6ec | 593 | .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO, |
4c78dc17 | 594 | .test_mode = test_mode, |
96243149 YW |
595 | .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL, |
596 | .online_state = _LINK_ONLINE_STATE_INVALID, | |
597 | .manage_foreign_routes = true, | |
598 | .manage_foreign_rules = true, | |
bbc05bec | 599 | .manage_foreign_nexthops = true, |
254d1313 | 600 | .ethtool_fd = -EBADF, |
013359ac | 601 | .persistent_storage_fd = persistent_storage_open(), |
7a169cb4 YW |
602 | .dhcp_use_domains = _USE_DOMAINS_INVALID, |
603 | .dhcp6_use_domains = _USE_DOMAINS_INVALID, | |
418f2dc7 | 604 | .ndisc_use_domains = _USE_DOMAINS_INVALID, |
96243149 YW |
605 | .dhcp_duid.type = DUID_TYPE_EN, |
606 | .dhcp6_duid.type = DUID_TYPE_EN, | |
607 | .duid_product_uuid.type = DUID_TYPE_UUID, | |
a3ed665a | 608 | .dhcp_server_persist_leases = true, |
3976c430 | 609 | .ip_forwarding = { -1, -1, }, |
96243149 YW |
610 | }; |
611 | ||
612 | *ret = TAKE_PTR(m); | |
f579559b TG |
613 | return 0; |
614 | } | |
615 | ||
75db809a | 616 | Manager* manager_free(Manager *m) { |
5fae368b | 617 | Link *link; |
f579559b | 618 | |
5fae368b | 619 | if (!m) |
75db809a | 620 | return NULL; |
505f8da7 | 621 | |
5fae368b | 622 | free(m->state_file); |
505f8da7 | 623 | |
6eab614d | 624 | HASHMAP_FOREACH(link, m->links_by_index) |
2a99eed0 | 625 | (void) link_stop_engines(link, true); |
946f8e14 | 626 | |
40b12fa2 | 627 | m->request_queue = ordered_set_free(m->request_queue); |
85a6f300 | 628 | m->remove_request_queue = ordered_set_free(m->remove_request_queue); |
19d9a5ad | 629 | |
c4397d94 | 630 | m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref); |
9c5b8d46 | 631 | m->new_wlan_ifindices = set_free(m->new_wlan_ifindices); |
0b54c870 | 632 | m->links_by_name = hashmap_free(m->links_by_name); |
fe321d45 | 633 | m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr); |
a27588d4 | 634 | m->links_by_dhcp_pd_subnet_prefix = hashmap_free(m->links_by_dhcp_pd_subnet_prefix); |
6eab614d | 635 | m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref); |
27dfc982 | 636 | |
a27588d4 | 637 | m->dhcp_pd_subnet_ids = set_free(m->dhcp_pd_subnet_ids); |
715d398e | 638 | m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref); |
dbffab87 | 639 | |
c4397d94 | 640 | m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref); |
5fae368b | 641 | |
af7a86b8 YW |
642 | m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name); |
643 | ||
edb69db2 YW |
644 | m->wiphy_by_name = hashmap_free(m->wiphy_by_name); |
645 | m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free); | |
646 | ||
bfbf150e | 647 | ordered_set_free_free(m->address_pools); |
5fae368b | 648 | |
552b90a2 YW |
649 | hashmap_free(m->route_table_names_by_number); |
650 | hashmap_free(m->route_table_numbers_by_name); | |
c038ce46 | 651 | |
eb72fa3a | 652 | set_free(m->rules); |
bce67bbe | 653 | |
d4df6326 SS |
654 | sd_netlink_unref(m->rtnl); |
655 | sd_netlink_unref(m->genl); | |
656 | sd_resolve_unref(m->resolve); | |
657 | ||
450fa34b YW |
658 | /* reject (e.g. unreachable) type routes are managed by Manager, but may be referenced by a |
659 | * link. E.g., DHCP6 with prefix delegation creates unreachable routes, and they are referenced | |
660 | * by the upstream link. And the links may be referenced by netlink slots. Hence, two | |
661 | * set_free() must be called after the above sd_netlink_unref(). */ | |
662 | m->routes = set_free(m->routes); | |
450fa34b | 663 | |
69e244e3 | 664 | m->nexthops_by_id = hashmap_free(m->nexthops_by_id); |
fb126bb1 | 665 | m->nexthop_ids = set_free(m->nexthop_ids); |
69e244e3 | 666 | |
a879e1a4 | 667 | sd_event_source_unref(m->speed_meter_event_source); |
2f5b4a77 | 668 | sd_event_unref(m->event); |
5fae368b | 669 | |
d2ebf952 | 670 | sd_device_monitor_unref(m->device_monitor); |
7d20d375 | 671 | |
c5c74d85 | 672 | manager_varlink_done(m); |
2a1ffd3e | 673 | hashmap_free(m->polkit_registry); |
92e31da1 | 674 | sd_bus_flush_close_unref(m->bus); |
7d20d375 | 675 | |
7901cea1 MP |
676 | free(m->dynamic_timezone); |
677 | free(m->dynamic_hostname); | |
678 | ||
c643bda5 | 679 | safe_close(m->ethtool_fd); |
013359ac | 680 | safe_close(m->persistent_storage_fd); |
c643bda5 | 681 | |
761cf19d FW |
682 | m->fw_ctx = fw_ctx_free(m->fw_ctx); |
683 | ||
75db809a | 684 | return mfree(m); |
5fae368b TG |
685 | } |
686 | ||
b76d99d9 | 687 | int manager_start(Manager *m) { |
84de38c5 | 688 | Link *link; |
a879e1a4 | 689 | int r; |
84de38c5 | 690 | |
a97dcc12 TG |
691 | assert(m); |
692 | ||
3976c430 YW |
693 | manager_set_sysctl(m); |
694 | ||
a879e1a4 YW |
695 | r = manager_start_speed_meter(m); |
696 | if (r < 0) | |
697 | return log_error_errno(r, "Failed to initialize speed meter: %m"); | |
698 | ||
84de38c5 TG |
699 | /* The dirty handler will deal with future serialization, but the first one |
700 | must be done explicitly. */ | |
701 | ||
d23a66f2 YW |
702 | r = manager_save(m); |
703 | if (r < 0) | |
704 | log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file); | |
84de38c5 | 705 | |
6eab614d | 706 | HASHMAP_FOREACH(link, m->links_by_index) { |
ac4a6950 | 707 | r = link_save_and_clean(link); |
d23a66f2 YW |
708 | if (r < 0) |
709 | log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file); | |
710 | } | |
84de38c5 | 711 | |
b76d99d9 | 712 | return 0; |
a97dcc12 TG |
713 | } |
714 | ||
5fae368b TG |
715 | int manager_load_config(Manager *m) { |
716 | int r; | |
717 | ||
e272b621 | 718 | r = netdev_load(m, false); |
f579559b TG |
719 | if (r < 0) |
720 | return r; | |
721 | ||
af7a86b8 YW |
722 | manager_clear_unmanaged_tuntap_fds(m); |
723 | ||
7f06b3e1 | 724 | r = network_load(m, &m->networks); |
9021bb9f TG |
725 | if (r < 0) |
726 | return r; | |
727 | ||
fb126bb1 YW |
728 | r = manager_build_dhcp_pd_subnet_ids(m); |
729 | if (r < 0) | |
730 | return r; | |
731 | ||
732 | r = manager_build_nexthop_ids(m); | |
733 | if (r < 0) | |
734 | return r; | |
735 | ||
736 | return 0; | |
f579559b | 737 | } |
f882c247 | 738 | |
41476186 | 739 | int manager_enumerate_internal( |
446aaaf3 | 740 | Manager *m, |
bdcd4ab2 | 741 | sd_netlink *nl, |
446aaaf3 | 742 | sd_netlink_message *req, |
f12629ae | 743 | int (*process)(sd_netlink *, sd_netlink_message *, Manager *)) { |
446aaaf3 YW |
744 | |
745 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL; | |
1339b950 | 746 | int r; |
f882c247 | 747 | |
5da8149f | 748 | assert(m); |
bdcd4ab2 | 749 | assert(nl); |
446aaaf3 YW |
750 | assert(req); |
751 | assert(process); | |
f882c247 | 752 | |
24c0f385 | 753 | r = sd_netlink_message_set_request_dump(req, true); |
dd3efc09 TG |
754 | if (r < 0) |
755 | return r; | |
756 | ||
bdcd4ab2 | 757 | r = sd_netlink_call(nl, req, 0, &reply); |
f12629ae | 758 | if (r < 0) |
f2236469 TG |
759 | return r; |
760 | ||
a6b08423 | 761 | m->enumerating = true; |
1339b950 ZJS |
762 | for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) |
763 | RET_GATHER(r, process(nl, reply_one, m)); | |
a6b08423 | 764 | m->enumerating = false; |
2e9f08ea | 765 | |
5fae368b | 766 | return r; |
f882c247 | 767 | } |
3bef724f | 768 | |
446aaaf3 YW |
769 | static int manager_enumerate_links(Manager *m) { |
770 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1346b1f0 TG |
771 | int r; |
772 | ||
5fae368b TG |
773 | assert(m); |
774 | assert(m->rtnl); | |
bcbca829 | 775 | |
446aaaf3 | 776 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); |
5fae368b TG |
777 | if (r < 0) |
778 | return r; | |
779 | ||
11cee6ef YW |
780 | r = manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); |
781 | if (r < 0) | |
782 | return r; | |
783 | ||
784 | req = sd_netlink_message_unref(req); | |
785 | ||
786 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); | |
787 | if (r < 0) | |
788 | return r; | |
789 | ||
790 | r = sd_rtnl_message_link_set_family(req, AF_BRIDGE); | |
791 | if (r < 0) | |
792 | return r; | |
793 | ||
f12629ae | 794 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); |
446aaaf3 | 795 | } |
5fae368b | 796 | |
828a81a9 YW |
797 | static int manager_enumerate_qdisc(Manager *m) { |
798 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
799 | int r; | |
800 | ||
801 | assert(m); | |
802 | assert(m->rtnl); | |
803 | ||
804 | r = sd_rtnl_message_new_traffic_control(m->rtnl, &req, RTM_GETQDISC, 0, 0, 0); | |
805 | if (r < 0) | |
806 | return r; | |
807 | ||
808 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_qdisc); | |
809 | } | |
810 | ||
811 | static int manager_enumerate_tclass(Manager *m) { | |
41476186 YW |
812 | Link *link; |
813 | int r = 0; | |
828a81a9 YW |
814 | |
815 | assert(m); | |
816 | assert(m->rtnl); | |
817 | ||
41476186 YW |
818 | /* TC class can be enumerated only per link. See tc_dump_tclass() in net/sched/sched_api.c. */ |
819 | ||
820 | HASHMAP_FOREACH(link, m->links_by_index) | |
821 | RET_GATHER(r, link_enumerate_tclass(link, 0)); | |
828a81a9 | 822 | |
41476186 | 823 | return r; |
828a81a9 YW |
824 | } |
825 | ||
446aaaf3 YW |
826 | static int manager_enumerate_addresses(Manager *m) { |
827 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
828 | int r; | |
6a24f148 | 829 | |
446aaaf3 YW |
830 | assert(m); |
831 | assert(m->rtnl); | |
6a24f148 | 832 | |
446aaaf3 YW |
833 | r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0); |
834 | if (r < 0) | |
835 | return r; | |
5fae368b | 836 | |
f12629ae | 837 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_address); |
1346b1f0 | 838 | } |
d1bdafd2 | 839 | |
446aaaf3 YW |
840 | static int manager_enumerate_neighbors(Manager *m) { |
841 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
d1bdafd2 WKI |
842 | int r; |
843 | ||
844 | assert(m); | |
845 | assert(m->rtnl); | |
846 | ||
847 | r = sd_rtnl_message_new_neigh(m->rtnl, &req, RTM_GETNEIGH, 0, AF_UNSPEC); | |
848 | if (r < 0) | |
849 | return r; | |
850 | ||
f12629ae | 851 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_neighbor); |
d1bdafd2 | 852 | } |
1346b1f0 | 853 | |
446aaaf3 YW |
854 | static int manager_enumerate_routes(Manager *m) { |
855 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1c8e710c TG |
856 | int r; |
857 | ||
858 | assert(m); | |
859 | assert(m->rtnl); | |
860 | ||
5ff1ef31 YW |
861 | if (!m->manage_foreign_routes) |
862 | return 0; | |
863 | ||
1c8e710c TG |
864 | r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0); |
865 | if (r < 0) | |
866 | return r; | |
867 | ||
f12629ae | 868 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_route); |
1c8e710c TG |
869 | } |
870 | ||
446aaaf3 YW |
871 | static int manager_enumerate_rules(Manager *m) { |
872 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
bce67bbe SS |
873 | int r; |
874 | ||
875 | assert(m); | |
876 | assert(m->rtnl); | |
877 | ||
d94dfe70 YW |
878 | if (!m->manage_foreign_rules) |
879 | return 0; | |
880 | ||
bce67bbe SS |
881 | r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0); |
882 | if (r < 0) | |
883 | return r; | |
884 | ||
f12629ae | 885 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_rule); |
bce67bbe SS |
886 | } |
887 | ||
446aaaf3 YW |
888 | static int manager_enumerate_nexthop(Manager *m) { |
889 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
c16c7808 SS |
890 | int r; |
891 | ||
892 | assert(m); | |
893 | assert(m->rtnl); | |
894 | ||
bbc05bec YW |
895 | if (!m->manage_foreign_nexthops) |
896 | return 0; | |
897 | ||
c16c7808 SS |
898 | r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0); |
899 | if (r < 0) | |
900 | return r; | |
901 | ||
f12629ae | 902 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop); |
446aaaf3 | 903 | } |
c16c7808 | 904 | |
edb69db2 YW |
905 | static int manager_enumerate_nl80211_wiphy(Manager *m) { |
906 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
907 | int r; | |
908 | ||
909 | assert(m); | |
910 | assert(m->genl); | |
911 | ||
912 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_WIPHY, &req); | |
913 | if (r < 0) | |
914 | return r; | |
915 | ||
916 | return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_wiphy); | |
917 | } | |
918 | ||
96f5f9ef YW |
919 | static int manager_enumerate_nl80211_config(Manager *m) { |
920 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
921 | int r; | |
922 | ||
923 | assert(m); | |
924 | assert(m->genl); | |
925 | ||
926 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &req); | |
927 | if (r < 0) | |
928 | return r; | |
929 | ||
930 | return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_config); | |
931 | } | |
932 | ||
933 | static int manager_enumerate_nl80211_mlme(Manager *m) { | |
934 | Link *link; | |
935 | int r; | |
936 | ||
937 | assert(m); | |
938 | assert(m->genl); | |
939 | ||
940 | HASHMAP_FOREACH(link, m->links_by_index) { | |
941 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
942 | ||
943 | if (link->wlan_iftype != NL80211_IFTYPE_STATION) | |
944 | continue; | |
945 | ||
946 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &req); | |
947 | if (r < 0) | |
948 | return r; | |
949 | ||
950 | r = sd_netlink_message_append_u32(req, NL80211_ATTR_IFINDEX, link->ifindex); | |
951 | if (r < 0) | |
952 | return r; | |
953 | ||
954 | r = manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_mlme); | |
955 | if (r < 0) | |
956 | return r; | |
957 | } | |
958 | ||
959 | return 0; | |
960 | } | |
961 | ||
446aaaf3 YW |
962 | int manager_enumerate(Manager *m) { |
963 | int r; | |
c16c7808 | 964 | |
446aaaf3 YW |
965 | r = manager_enumerate_links(m); |
966 | if (r < 0) | |
967 | return log_error_errno(r, "Could not enumerate links: %m"); | |
c16c7808 | 968 | |
828a81a9 | 969 | r = manager_enumerate_qdisc(m); |
15ac2a62 YW |
970 | if (r == -EOPNOTSUPP) |
971 | log_debug_errno(r, "Could not enumerate QDiscs, ignoring: %m"); | |
972 | else if (r < 0) | |
828a81a9 YW |
973 | return log_error_errno(r, "Could not enumerate QDisc: %m"); |
974 | ||
975 | r = manager_enumerate_tclass(m); | |
15ac2a62 YW |
976 | if (r == -EOPNOTSUPP) |
977 | log_debug_errno(r, "Could not enumerate TClasses, ignoring: %m"); | |
978 | else if (r < 0) | |
828a81a9 YW |
979 | return log_error_errno(r, "Could not enumerate TClass: %m"); |
980 | ||
446aaaf3 YW |
981 | r = manager_enumerate_addresses(m); |
982 | if (r < 0) | |
983 | return log_error_errno(r, "Could not enumerate addresses: %m"); | |
c16c7808 | 984 | |
446aaaf3 YW |
985 | r = manager_enumerate_neighbors(m); |
986 | if (r < 0) | |
987 | return log_error_errno(r, "Could not enumerate neighbors: %m"); | |
c16c7808 | 988 | |
f12629ae YW |
989 | /* NextHop support is added in kernel v5.3 (65ee00a9409f751188a8cdc0988167858eb4a536), |
990 | * and older kernels return -EOPNOTSUPP, or -EINVAL if SELinux is enabled. */ | |
0c0585ca | 991 | r = manager_enumerate_nexthop(m); |
f12629ae YW |
992 | if (r == -EOPNOTSUPP || (r == -EINVAL && mac_selinux_enforcing())) |
993 | log_debug_errno(r, "Could not enumerate nexthops, ignoring: %m"); | |
994 | else if (r < 0) | |
995 | return log_error_errno(r, "Could not enumerate nexthops: %m"); | |
0c0585ca | 996 | |
446aaaf3 YW |
997 | r = manager_enumerate_routes(m); |
998 | if (r < 0) | |
999 | return log_error_errno(r, "Could not enumerate routes: %m"); | |
c16c7808 | 1000 | |
f12629ae | 1001 | /* If kernel is built with CONFIG_FIB_RULES=n, it returns -EOPNOTSUPP. */ |
446aaaf3 | 1002 | r = manager_enumerate_rules(m); |
f12629ae YW |
1003 | if (r == -EOPNOTSUPP) |
1004 | log_debug_errno(r, "Could not enumerate routing policy rules, ignoring: %m"); | |
1005 | else if (r < 0) | |
446aaaf3 | 1006 | return log_error_errno(r, "Could not enumerate routing policy rules: %m"); |
c16c7808 | 1007 | |
edb69db2 YW |
1008 | r = manager_enumerate_nl80211_wiphy(m); |
1009 | if (r == -EOPNOTSUPP) | |
1010 | log_debug_errno(r, "Could not enumerate wireless LAN phy, ignoring: %m"); | |
1011 | else if (r < 0) | |
1012 | return log_error_errno(r, "Could not enumerate wireless LAN phy: %m"); | |
1013 | ||
96f5f9ef YW |
1014 | r = manager_enumerate_nl80211_config(m); |
1015 | if (r == -EOPNOTSUPP) | |
1016 | log_debug_errno(r, "Could not enumerate wireless LAN interfaces, ignoring: %m"); | |
1017 | else if (r < 0) | |
1018 | return log_error_errno(r, "Could not enumerate wireless LAN interfaces: %m"); | |
1019 | ||
1020 | r = manager_enumerate_nl80211_mlme(m); | |
1021 | if (r == -EOPNOTSUPP) | |
1022 | log_debug_errno(r, "Could not enumerate wireless LAN stations, ignoring: %m"); | |
1023 | else if (r < 0) | |
1024 | return log_error_errno(r, "Could not enumerate wireless LAN stations: %m"); | |
1025 | ||
446aaaf3 | 1026 | return 0; |
c16c7808 SS |
1027 | } |
1028 | ||
59eb33e0 | 1029 | static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { |
59eb33e0 | 1030 | const sd_bus_error *e; |
f63e09ef | 1031 | int r; |
59eb33e0 MP |
1032 | |
1033 | assert(m); | |
59eb33e0 MP |
1034 | |
1035 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
1036 | if (e) { |
1037 | r = sd_bus_error_get_errno(e); | |
1038 | log_warning_errno(r, "Could not set hostname: %s", bus_error_message(e, r)); | |
1039 | } | |
59eb33e0 MP |
1040 | |
1041 | return 1; | |
1042 | } | |
1043 | ||
1044 | int manager_set_hostname(Manager *m, const char *hostname) { | |
1045 | int r; | |
1046 | ||
1047 | log_debug("Setting transient hostname: '%s'", strna(hostname)); | |
d7afd945 | 1048 | |
b3f9c17a YW |
1049 | r = free_and_strdup_warn(&m->dynamic_hostname, hostname); |
1050 | if (r < 0) | |
1051 | return r; | |
59eb33e0 | 1052 | |
5dbec9bd ZJS |
1053 | if (sd_bus_is_ready(m->bus) <= 0) { |
1054 | log_debug("Not connected to system bus, setting system hostname later."); | |
59eb33e0 MP |
1055 | return 0; |
1056 | } | |
1057 | ||
d2775306 | 1058 | r = bus_call_method_async( |
59eb33e0 MP |
1059 | m->bus, |
1060 | NULL, | |
d2775306 | 1061 | bus_hostname, |
59eb33e0 MP |
1062 | "SetHostname", |
1063 | set_hostname_handler, | |
1064 | m, | |
1065 | "sb", | |
1066 | hostname, | |
1067 | false); | |
59eb33e0 MP |
1068 | if (r < 0) |
1069 | return log_error_errno(r, "Could not set transient hostname: %m"); | |
1070 | ||
1071 | return 0; | |
1072 | } | |
1073 | ||
1074 | static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { | |
59eb33e0 | 1075 | const sd_bus_error *e; |
f63e09ef | 1076 | int r; |
59eb33e0 MP |
1077 | |
1078 | assert(m); | |
59eb33e0 MP |
1079 | |
1080 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
1081 | if (e) { |
1082 | r = sd_bus_error_get_errno(e); | |
1083 | log_warning_errno(r, "Could not set timezone: %s", bus_error_message(e, r)); | |
1084 | } | |
59eb33e0 MP |
1085 | |
1086 | return 1; | |
1087 | } | |
1088 | ||
1089 | int manager_set_timezone(Manager *m, const char *tz) { | |
1090 | int r; | |
1091 | ||
1092 | assert(m); | |
1093 | assert(tz); | |
1094 | ||
1095 | log_debug("Setting system timezone: '%s'", tz); | |
b3f9c17a YW |
1096 | r = free_and_strdup_warn(&m->dynamic_timezone, tz); |
1097 | if (r < 0) | |
1098 | return r; | |
59eb33e0 | 1099 | |
5dbec9bd ZJS |
1100 | if (sd_bus_is_ready(m->bus) <= 0) { |
1101 | log_debug("Not connected to system bus, setting system timezone later."); | |
59eb33e0 MP |
1102 | return 0; |
1103 | } | |
1104 | ||
b607fd3f | 1105 | r = bus_call_method_async( |
59eb33e0 MP |
1106 | m->bus, |
1107 | NULL, | |
b607fd3f | 1108 | bus_timedate, |
59eb33e0 MP |
1109 | "SetTimezone", |
1110 | set_timezone_handler, | |
1111 | m, | |
1112 | "sb", | |
1113 | tz, | |
1114 | false); | |
1115 | if (r < 0) | |
1116 | return log_error_errno(r, "Could not set timezone: %m"); | |
1117 | ||
1118 | return 0; | |
1119 | } | |
0e07cdb0 | 1120 | |
1e869a5d | 1121 | int manager_reload(Manager *m, sd_bus_message *message) { |
0e07cdb0 LP |
1122 | Link *link; |
1123 | int r; | |
1124 | ||
1125 | assert(m); | |
1126 | ||
b377a7cc | 1127 | (void) notify_reloading(); |
0e07cdb0 LP |
1128 | |
1129 | r = netdev_load(m, /* reload= */ true); | |
1130 | if (r < 0) | |
1131 | goto finish; | |
1132 | ||
1133 | r = network_reload(m); | |
1134 | if (r < 0) | |
1135 | goto finish; | |
1136 | ||
1137 | HASHMAP_FOREACH(link, m->links_by_index) { | |
1e869a5d YW |
1138 | if (message) |
1139 | r = link_reconfigure_on_bus_method_reload(link, message); | |
1140 | else | |
1141 | r = link_reconfigure(link, /* force = */ false); | |
1142 | if (r < 0) { | |
1143 | log_link_warning_errno(link, r, "Failed to reconfigure the interface: %m"); | |
1144 | link_enter_failed(link); | |
1145 | } | |
0e07cdb0 LP |
1146 | } |
1147 | ||
1148 | r = 0; | |
1149 | finish: | |
1150 | (void) sd_notify(/* unset= */ false, NOTIFY_READY); | |
1151 | return r; | |
1152 | } |