]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
f579559b | 2 | |
baa3fadf | 3 | #include <linux/filter.h> |
96f5f9ef | 4 | #include <linux/nl80211.h> |
1cf40697 | 5 | #include <sys/socket.h> |
3bef724f | 6 | |
baa3fadf DDM |
7 | #include "sd-bus.h" |
8 | #include "sd-event.h" | |
07630cea | 9 | #include "sd-netlink.h" |
baa3fadf | 10 | #include "sd-resolve.h" |
fc2f9534 | 11 | |
b5efdb8a | 12 | #include "alloc-util.h" |
f63e09ef | 13 | #include "bus-error.h" |
b607fd3f | 14 | #include "bus-locator.h" |
ac9f55ed | 15 | #include "bus-log-control-api.h" |
baa3fadf | 16 | #include "bus-object.h" |
a97dcc12 | 17 | #include "bus-util.h" |
6d9ef22a | 18 | #include "capability-util.h" |
6daaeafe | 19 | #include "common-signal.h" |
af7a86b8 | 20 | #include "daemon-util.h" |
1fd3ac1e YW |
21 | #include "device-private.h" |
22 | #include "device-util.h" | |
013359ac | 23 | #include "env-util.h" |
baa3fadf | 24 | #include "errno-util.h" |
3ffd4af2 | 25 | #include "fd-util.h" |
761cf19d | 26 | #include "firewall-util.h" |
baa6a42d | 27 | #include "initrd-util.h" |
c0323de6 | 28 | #include "mount-util.h" |
07630cea | 29 | #include "netlink-util.h" |
1cf40697 | 30 | #include "networkd-address.h" |
489671d2 | 31 | #include "networkd-address-label.h" |
bfbf150e | 32 | #include "networkd-address-pool.h" |
0ee78fc9 | 33 | #include "networkd-link.h" |
23f53b99 | 34 | #include "networkd-manager.h" |
c5c74d85 LP |
35 | #include "networkd-manager-bus.h" |
36 | #include "networkd-manager-varlink.h" | |
1939ebeb | 37 | #include "networkd-neighbor.h" |
75156ccb | 38 | #include "networkd-nexthop.h" |
19d9a5ad | 39 | #include "networkd-queue.h" |
3b6a3bde | 40 | #include "networkd-route.h" |
ca183bf8 | 41 | #include "networkd-routing-policy-rule.h" |
c321d332 | 42 | #include "networkd-serialize.h" |
a879e1a4 | 43 | #include "networkd-speed-meter.h" |
3b5a4fc6 | 44 | #include "networkd-state-file.h" |
96f5f9ef | 45 | #include "networkd-wifi.h" |
edb69db2 | 46 | #include "networkd-wiphy.h" |
00616955 | 47 | #include "ordered-set.h" |
828a81a9 | 48 | #include "qdisc.h" |
07630cea | 49 | #include "set.h" |
baa3fadf DDM |
50 | #include "stat-util.h" |
51 | #include "string-util.h" | |
21486d9e | 52 | #include "strv.h" |
828a81a9 | 53 | #include "tclass.h" |
af7a86b8 | 54 | #include "tuntap.h" |
82f52245 | 55 | #include "udev-util.h" |
505f8da7 | 56 | |
48d0248e YW |
57 | /* use 128 MB for receive socket kernel queue. */ |
58 | #define RCVBUF_SIZE (128*1024*1024) | |
be660c37 | 59 | |
19070062 | 60 | static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { |
99534007 | 61 | Manager *m = ASSERT_PTR(userdata); |
a39a9ac8 | 62 | Link *link; |
9c0a72f9 TG |
63 | int b, r; |
64 | ||
19070062 | 65 | assert(message); |
9c0a72f9 TG |
66 | |
67 | r = sd_bus_message_read(message, "b", &b); | |
68 | if (r < 0) { | |
d67b1d18 | 69 | bus_log_parse_error(r); |
9c0a72f9 TG |
70 | return 0; |
71 | } | |
72 | ||
73 | if (b) | |
74 | return 0; | |
75 | ||
a39a9ac8 | 76 | log_debug("Coming back from suspend, reconfiguring all connections..."); |
9c0a72f9 | 77 | |
021d39d3 | 78 | HASHMAP_FOREACH(link, m->links_by_index) |
2b07a321 | 79 | (void) link_reconfigure(link, LINK_RECONFIGURE_UNCONDITIONALLY); |
9c0a72f9 TG |
80 | |
81 | return 0; | |
82 | } | |
83 | ||
d7afd945 | 84 | static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { |
99534007 | 85 | Manager *m = ASSERT_PTR(userdata); |
9c0a72f9 | 86 | |
d7afd945 | 87 | assert(message); |
9c0a72f9 | 88 | |
d7afd945 LP |
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); | |
ccffa166 | 94 | if (m->product_uuid_requested) |
4e26a5ba | 95 | (void) manager_request_product_uuid(m); |
9c0a72f9 | 96 | |
d7afd945 LP |
97 | return 0; |
98 | } | |
9c0a72f9 | 99 | |
96243149 | 100 | static int manager_connect_bus(Manager *m) { |
d7afd945 LP |
101 | int r; |
102 | ||
103 | assert(m); | |
96243149 | 104 | assert(!m->bus); |
7d6884b6 | 105 | |
621e4509 | 106 | r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network"); |
9c0a72f9 | 107 | if (r < 0) |
d7afd945 | 108 | return log_error_errno(r, "Failed to connect to bus: %m"); |
9c0a72f9 | 109 | |
6e194652 | 110 | r = bus_add_implementation(m->bus, &manager_object, m); |
e331e246 | 111 | if (r < 0) |
6e194652 | 112 | return r; |
e331e246 | 113 | |
ac9f55ed LP |
114 | r = bus_log_control_api_register(m->bus); |
115 | if (r < 0) | |
116 | return r; | |
117 | ||
696fc836 | 118 | r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL); |
e331e246 | 119 | if (r < 0) |
0c0b9306 | 120 | return log_error_errno(r, "Failed to request name: %m"); |
e331e246 TG |
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 | ||
d7afd945 LP |
126 | r = sd_bus_match_signal_async( |
127 | m->bus, | |
cad43595 | 128 | NULL, |
d7afd945 LP |
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 | ||
d962e737 | 137 | r = bus_match_signal_async( |
d7afd945 | 138 | m->bus, |
cad43595 | 139 | NULL, |
d962e737 | 140 | bus_login_mgr, |
d7afd945 LP |
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"); | |
7901cea1 | 145 | |
9c0a72f9 TG |
146 | return 0; |
147 | } | |
148 | ||
1fd3ac1e YW |
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; | |
1fd3ac1e YW |
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 | ||
ab1bd9da | 160 | if (device_in_subsystem(device, "net") > 0) |
1fd3ac1e | 161 | r = manager_udev_process_link(m, device, action); |
ab1bd9da | 162 | else if (device_in_subsystem(device, "ieee80211") > 0) |
c49d5362 | 163 | r = manager_udev_process_wiphy(m, device, action); |
ab1bd9da | 164 | else if (device_in_subsystem(device, "rfkill") > 0) |
8642e04b | 165 | r = manager_udev_process_rfkill(m, device, action); |
1fd3ac1e YW |
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 | ||
5fae368b TG |
173 | static int manager_connect_udev(Manager *m) { |
174 | int r; | |
f579559b | 175 | |
d31f33e3 YW |
176 | /* udev does not initialize devices inside containers, so we rely on them being already |
177 | * initialized before entering the container. */ | |
82f52245 | 178 | if (!udev_available()) |
5fae368b | 179 | return 0; |
f579559b | 180 | |
d2ebf952 | 181 | r = sd_device_monitor_new(&m->device_monitor); |
02b59d57 | 182 | if (r < 0) |
d2ebf952 | 183 | return log_error_errno(r, "Failed to initialize device monitor: %m"); |
02b59d57 | 184 | |
d2ebf952 YW |
185 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL); |
186 | if (r < 0) | |
1fd3ac1e | 187 | return log_error_errno(r, "Could not add device monitor filter for net subsystem: %m"); |
505f8da7 | 188 | |
c49d5362 YW |
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 | ||
8642e04b YW |
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 | ||
deb2b734 | 197 | r = sd_device_monitor_attach_event(m->device_monitor, m->event); |
5fae368b | 198 | if (r < 0) |
d2ebf952 | 199 | return log_error_errno(r, "Failed to attach event to device monitor: %m"); |
505f8da7 | 200 | |
1fd3ac1e | 201 | r = sd_device_monitor_start(m->device_monitor, manager_process_uevent, m); |
505f8da7 | 202 | if (r < 0) |
d2ebf952 | 203 | return log_error_errno(r, "Failed to start device monitor: %m"); |
11a7f229 | 204 | |
505f8da7 TG |
205 | return 0; |
206 | } | |
f579559b | 207 | |
b0ea79c5 | 208 | static int manager_listen_fds(Manager *m, int *ret_rtnl_fd, int *ret_varlink_fd) { |
af7a86b8 | 209 | _cleanup_strv_free_ char **names = NULL; |
b0ea79c5 | 210 | int n, rtnl_fd = -EBADF, varlink_fd = -EBADF; |
5fae368b | 211 | |
af7a86b8 YW |
212 | assert(m); |
213 | assert(ret_rtnl_fd); | |
b0ea79c5 | 214 | assert(ret_varlink_fd); |
af7a86b8 YW |
215 | |
216 | n = sd_listen_fds_with_names(/* unset_environment = */ true, &names); | |
217 | if (n < 0) | |
218 | return n; | |
219 | ||
af7a86b8 YW |
220 | for (int i = 0; i < n; i++) { |
221 | int fd = i + SD_LISTEN_FDS_START; | |
222 | ||
5fae368b | 223 | if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { |
af7a86b8 | 224 | if (rtnl_fd >= 0) { |
b0ea79c5 | 225 | log_debug("Received multiple netlink sockets, ignoring."); |
ae659748 | 226 | goto unused; |
af7a86b8 | 227 | } |
5fae368b TG |
228 | |
229 | rtnl_fd = fd; | |
af7a86b8 | 230 | continue; |
5fae368b | 231 | } |
5fae368b | 232 | |
b0ea79c5 DDM |
233 | if (streq(names[i], "varlink")) { |
234 | varlink_fd = fd; | |
235 | continue; | |
236 | } | |
237 | ||
c321d332 YW |
238 | if (manager_set_serialization_fd(m, fd, names[i]) >= 0) |
239 | continue; | |
240 | ||
af7a86b8 YW |
241 | if (manager_add_tuntap_fd(m, fd, names[i]) >= 0) |
242 | continue; | |
243 | ||
ae659748 | 244 | unused: |
af7a86b8 YW |
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; | |
b0ea79c5 DDM |
252 | *ret_varlink_fd = varlink_fd; |
253 | ||
af7a86b8 | 254 | return 0; |
5fae368b TG |
255 | } |
256 | ||
05d0c2e3 JT |
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 | ||
78cca583 | 266 | r = sd_netlink_increase_rxbuf(m->genl, RCVBUF_SIZE); |
05d0c2e3 | 267 | if (r < 0) |
8c63924c | 268 | log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m"); |
05d0c2e3 JT |
269 | |
270 | r = sd_netlink_attach_event(m->genl, m->event, 0); | |
271 | if (r < 0) | |
272 | return r; | |
273 | ||
4bfbf0fc | 274 | /* If the kernel is built without CONFIG_WIRELESS, the below will fail with -EOPNOTSUPP. */ |
96f5f9ef YW |
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 | ||
05d0c2e3 JT |
285 | return 0; |
286 | } | |
287 | ||
26a8be48 YW |
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 | ||
af7a86b8 YW |
322 | static int manager_connect_rtnl(Manager *m, int fd) { |
323 | _unused_ _cleanup_close_ int fd_close = fd; | |
324 | int r; | |
505f8da7 TG |
325 | |
326 | assert(m); | |
505f8da7 | 327 | |
af7a86b8 YW |
328 | /* This takes input fd. */ |
329 | ||
5fae368b | 330 | if (fd < 0) |
1c4baffc | 331 | r = sd_netlink_open(&m->rtnl); |
5fae368b | 332 | else |
1c4baffc | 333 | r = sd_netlink_open_fd(&m->rtnl, fd); |
505f8da7 TG |
334 | if (r < 0) |
335 | return r; | |
af7a86b8 | 336 | TAKE_FD(fd_close); |
505f8da7 | 337 | |
e13af7bd YW |
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) { | |
78cca583 | 342 | r = sd_netlink_increase_rxbuf(m->rtnl, RCVBUF_SIZE); |
e13af7bd YW |
343 | if (r < 0) |
344 | log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m"); | |
345 | } | |
f579559b | 346 | |
1c4baffc | 347 | r = sd_netlink_attach_event(m->rtnl, m->event, 0); |
505f8da7 TG |
348 | if (r < 0) |
349 | return r; | |
f579559b | 350 | |
8dfed23d | 351 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
352 | if (r < 0) |
353 | return r; | |
505f8da7 | 354 | |
8dfed23d | 355 | r = netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
356 | if (r < 0) |
357 | return r; | |
45af44d4 | 358 | |
828a81a9 YW |
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 | ||
8dfed23d | 375 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
376 | if (r < 0) |
377 | return r; | |
378 | ||
8dfed23d | 379 | r = netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
380 | if (r < 0) |
381 | return r; | |
382 | ||
8dfed23d | 383 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
384 | if (r < 0) |
385 | return r; | |
386 | ||
8dfed23d | 387 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
388 | if (r < 0) |
389 | return r; | |
390 | ||
8dfed23d | 391 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
392 | if (r < 0) |
393 | return r; | |
394 | ||
8dfed23d | 395 | r = netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
396 | if (r < 0) |
397 | return r; | |
398 | ||
8dfed23d | 399 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
400 | if (r < 0) |
401 | return r; | |
402 | ||
8dfed23d | 403 | r = netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
404 | if (r < 0) |
405 | return r; | |
406 | ||
8dfed23d | 407 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
408 | if (r < 0) |
409 | return r; | |
410 | ||
8dfed23d | 411 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
412 | if (r < 0) |
413 | return r; | |
414 | ||
26a8be48 | 415 | return manager_setup_rtnl_filter(m); |
45af44d4 | 416 | } |
505f8da7 | 417 | |
2e1113b7 YW |
418 | static int manager_post_handler(sd_event_source *s, void *userdata) { |
419 | Manager *manager = ASSERT_PTR(userdata); | |
84de38c5 | 420 | |
db68e990 YW |
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. */ | |
85a6f300 | 423 | (void) manager_process_remove_requests(manager); |
db68e990 YW |
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 | ||
c321d332 | 441 | (void) manager_serialize(manager); |
db68e990 YW |
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 | ||
2e1113b7 | 449 | return 0; |
84de38c5 TG |
450 | } |
451 | ||
db68e990 YW |
452 | static int manager_stop(Manager *manager, ManagerState state) { |
453 | assert(manager); | |
454 | assert(IN_SET(state, MANAGER_TERMINATING, MANAGER_RESTARTING)); | |
ab76be55 | 455 | |
db68e990 YW |
456 | if (manager->state != MANAGER_RUNNING) { |
457 | log_debug("Already terminating or restarting systemd-networkd, refusing further operation request."); | |
458 | return 0; | |
459 | } | |
ab76be55 | 460 | |
db68e990 YW |
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 | } | |
ab76be55 | 471 | |
db68e990 | 472 | manager->state = state; |
ab76be55 | 473 | |
db68e990 | 474 | Link *link; |
49e50134 | 475 | HASHMAP_FOREACH(link, manager->links_by_index) |
80a89d1a | 476 | (void) link_stop_engines(link, /* may_keep_dynamic = */ true); |
ab76be55 | 477 | |
db68e990 YW |
478 | return 0; |
479 | } | |
ab76be55 | 480 | |
db68e990 YW |
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 | } | |
ab76be55 | 484 | |
db68e990 YW |
485 | static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
486 | return manager_stop(userdata, MANAGER_RESTARTING); | |
ab76be55 ZJS |
487 | } |
488 | ||
0e07cdb0 LP |
489 | static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
490 | Manager *m = ASSERT_PTR(userdata); | |
491 | ||
1e869a5d | 492 | (void) manager_reload(m, /* message = */ NULL); |
0e07cdb0 LP |
493 | |
494 | return 0; | |
495 | } | |
496 | ||
ea853de5 YW |
497 | static int manager_set_keep_configuration(Manager *m) { |
498 | int r; | |
499 | ||
500 | assert(m); | |
501 | ||
502 | if (in_initrd()) { | |
80a89d1a YW |
503 | log_debug("Running in initrd, keep dynamically assigned configurations on stopping networkd by default."); |
504 | m->keep_configuration = KEEP_CONFIGURATION_DYNAMIC_ON_STOP; | |
ea853de5 YW |
505 | return 0; |
506 | } | |
507 | ||
c0323de6 YW |
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 | } | |
ea853de5 YW |
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 | ||
4c78dc17 | 523 | int manager_setup(Manager *m) { |
b0ea79c5 | 524 | _cleanup_close_ int rtnl_fd = -EBADF, varlink_fd = -EBADF; |
45af44d4 | 525 | int r; |
f579559b | 526 | |
96243149 | 527 | assert(m); |
5fae368b | 528 | |
3534a043 YW |
529 | r = sd_event_default(&m->event); |
530 | if (r < 0) | |
531 | return r; | |
532 | ||
05e21627 | 533 | (void) sd_event_set_watchdog(m->event, true); |
0e07cdb0 LP |
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); | |
6daaeafe LP |
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"); | |
5fae368b | 543 | |
2e1113b7 | 544 | r = sd_event_add_post(m->event, NULL, manager_post_handler, m); |
84de38c5 TG |
545 | if (r < 0) |
546 | return r; | |
547 | ||
b0ea79c5 | 548 | r = manager_listen_fds(m, &rtnl_fd, &varlink_fd); |
af7a86b8 YW |
549 | if (r < 0) |
550 | return r; | |
551 | ||
552 | r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd)); | |
45af44d4 TG |
553 | if (r < 0) |
554 | return r; | |
555 | ||
05d0c2e3 JT |
556 | r = manager_connect_genl(m); |
557 | if (r < 0) | |
558 | return r; | |
559 | ||
4c78dc17 | 560 | if (m->test_mode) |
96243149 YW |
561 | return 0; |
562 | ||
b0ea79c5 | 563 | r = manager_connect_varlink(m, TAKE_FD(varlink_fd)); |
c5c74d85 LP |
564 | if (r < 0) |
565 | return r; | |
566 | ||
96243149 YW |
567 | r = manager_connect_bus(m); |
568 | if (r < 0) | |
569 | return r; | |
570 | ||
5fae368b TG |
571 | r = manager_connect_udev(m); |
572 | if (r < 0) | |
573 | return r; | |
45af44d4 | 574 | |
05d0c2e3 JT |
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 | ||
ed76f585 | 583 | r = address_pool_setup_default(m); |
5fae368b TG |
584 | if (r < 0) |
585 | return r; | |
f579559b | 586 | |
ea853de5 YW |
587 | r = manager_set_keep_configuration(m); |
588 | if (r < 0) | |
589 | return r; | |
590 | ||
96243149 YW |
591 | m->state_file = strdup("/run/systemd/netif/state"); |
592 | if (!m->state_file) | |
593 | return -ENOMEM; | |
594 | ||
595 | return 0; | |
596 | } | |
597 | ||
013359ac YW |
598 | static int persistent_storage_open(void) { |
599 | _cleanup_close_ int fd = -EBADF; | |
f90eb086 YW |
600 | int r; |
601 | ||
013359ac YW |
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; | |
f90eb086 | 607 | |
fb6f98ae | 608 | fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY); |
013359ac | 609 | if (fd < 0) |
42ba9974 | 610 | return log_debug_errno(errno, "Failed to open %s, ignoring: %m", "/var/lib/systemd/network/"); |
f90eb086 | 611 | |
013359ac YW |
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."); | |
f90eb086 | 617 | |
013359ac | 618 | return TAKE_FD(fd); |
f90eb086 YW |
619 | } |
620 | ||
4c78dc17 | 621 | int manager_new(Manager **ret, bool test_mode) { |
96243149 | 622 | _cleanup_(manager_freep) Manager *m = NULL; |
f579559b | 623 | |
96243149 YW |
624 | m = new(Manager, 1); |
625 | if (!m) | |
626 | return -ENOMEM; | |
627 | ||
628 | *m = (Manager) { | |
ea853de5 | 629 | .keep_configuration = _KEEP_CONFIGURATION_INVALID, |
932ef6ec | 630 | .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO, |
4c78dc17 | 631 | .test_mode = test_mode, |
96243149 YW |
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, | |
bbc05bec | 636 | .manage_foreign_nexthops = true, |
254d1313 | 637 | .ethtool_fd = -EBADF, |
013359ac | 638 | .persistent_storage_fd = persistent_storage_open(), |
7a169cb4 YW |
639 | .dhcp_use_domains = _USE_DOMAINS_INVALID, |
640 | .dhcp6_use_domains = _USE_DOMAINS_INVALID, | |
418f2dc7 | 641 | .ndisc_use_domains = _USE_DOMAINS_INVALID, |
7bbe9ad7 | 642 | .dhcp_client_identifier = DHCP_CLIENT_ID_DUID, |
96243149 YW |
643 | .dhcp_duid.type = DUID_TYPE_EN, |
644 | .dhcp6_duid.type = DUID_TYPE_EN, | |
645 | .duid_product_uuid.type = DUID_TYPE_UUID, | |
a145343b | 646 | .dhcp_server_persist_leases = DHCP_SERVER_PERSIST_LEASES_YES, |
c321d332 | 647 | .serialization_fd = -EBADF, |
3976c430 | 648 | .ip_forwarding = { -1, -1, }, |
4d6ad22f | 649 | #if HAVE_VMLINUX_H |
6d9ef22a | 650 | .cgroup_fd = -EBADF, |
4d6ad22f | 651 | #endif |
96243149 YW |
652 | }; |
653 | ||
654 | *ret = TAKE_PTR(m); | |
f579559b TG |
655 | return 0; |
656 | } | |
657 | ||
75db809a | 658 | Manager* manager_free(Manager *m) { |
5fae368b | 659 | if (!m) |
75db809a | 660 | return NULL; |
505f8da7 | 661 | |
22583a00 | 662 | manager_remove_sysctl_monitor(m); |
6d9ef22a | 663 | |
5fae368b | 664 | free(m->state_file); |
505f8da7 | 665 | |
40b12fa2 | 666 | m->request_queue = ordered_set_free(m->request_queue); |
85a6f300 | 667 | m->remove_request_queue = ordered_set_free(m->remove_request_queue); |
19d9a5ad | 668 | |
9c5b8d46 | 669 | m->new_wlan_ifindices = set_free(m->new_wlan_ifindices); |
4cf443e6 YW |
670 | |
671 | m->dirty_links = set_free(m->dirty_links); | |
0b54c870 | 672 | m->links_by_name = hashmap_free(m->links_by_name); |
fe321d45 | 673 | m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr); |
a27588d4 | 674 | m->links_by_dhcp_pd_subnet_prefix = hashmap_free(m->links_by_dhcp_pd_subnet_prefix); |
4cf443e6 | 675 | m->links_by_index = hashmap_free(m->links_by_index); |
27dfc982 | 676 | |
a27588d4 | 677 | m->dhcp_pd_subnet_ids = set_free(m->dhcp_pd_subnet_ids); |
a85f73fa | 678 | m->networks = ordered_hashmap_free(m->networks); |
dbffab87 | 679 | |
bdf4f200 | 680 | /* The same object may be registered with multiple names, and netdev_detach() may drop multiple entries. */ |
36ca0164 YW |
681 | for (NetDev *n; (n = hashmap_first(m->netdevs)); ) |
682 | netdev_detach(n); | |
683 | m->netdevs = hashmap_free(m->netdevs); | |
5fae368b | 684 | |
af7a86b8 YW |
685 | m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name); |
686 | ||
edb69db2 | 687 | m->wiphy_by_name = hashmap_free(m->wiphy_by_name); |
52278e06 | 688 | m->wiphy_by_index = hashmap_free(m->wiphy_by_index); |
edb69db2 | 689 | |
04b7949e | 690 | ordered_set_free(m->address_pools); |
5fae368b | 691 | |
552b90a2 YW |
692 | hashmap_free(m->route_table_names_by_number); |
693 | hashmap_free(m->route_table_numbers_by_name); | |
c038ce46 | 694 | |
eb72fa3a | 695 | set_free(m->rules); |
bce67bbe | 696 | |
d4df6326 SS |
697 | sd_netlink_unref(m->rtnl); |
698 | sd_netlink_unref(m->genl); | |
699 | sd_resolve_unref(m->resolve); | |
700 | ||
450fa34b | 701 | m->routes = set_free(m->routes); |
450fa34b | 702 | |
69e244e3 | 703 | m->nexthops_by_id = hashmap_free(m->nexthops_by_id); |
fb126bb1 | 704 | m->nexthop_ids = set_free(m->nexthop_ids); |
69e244e3 | 705 | |
489671d2 YW |
706 | m->address_labels_by_section = hashmap_free(m->address_labels_by_section); |
707 | ||
a879e1a4 | 708 | sd_event_source_unref(m->speed_meter_event_source); |
2f5b4a77 | 709 | sd_event_unref(m->event); |
5fae368b | 710 | |
d2ebf952 | 711 | sd_device_monitor_unref(m->device_monitor); |
7d20d375 | 712 | |
c5c74d85 | 713 | manager_varlink_done(m); |
2a1ffd3e | 714 | hashmap_free(m->polkit_registry); |
92e31da1 | 715 | sd_bus_flush_close_unref(m->bus); |
7d20d375 | 716 | |
7901cea1 MP |
717 | free(m->dynamic_timezone); |
718 | free(m->dynamic_hostname); | |
719 | ||
c643bda5 | 720 | safe_close(m->ethtool_fd); |
013359ac | 721 | safe_close(m->persistent_storage_fd); |
c643bda5 | 722 | |
761cf19d FW |
723 | m->fw_ctx = fw_ctx_free(m->fw_ctx); |
724 | ||
c321d332 YW |
725 | m->serialization_fd = safe_close(m->serialization_fd); |
726 | ||
75db809a | 727 | return mfree(m); |
5fae368b TG |
728 | } |
729 | ||
b76d99d9 | 730 | int manager_start(Manager *m) { |
84de38c5 | 731 | Link *link; |
a879e1a4 | 732 | int r; |
84de38c5 | 733 | |
a97dcc12 TG |
734 | assert(m); |
735 | ||
6119221a YW |
736 | log_debug("Starting..."); |
737 | ||
22583a00 | 738 | (void) manager_install_sysctl_monitor(m); |
6d9ef22a MC |
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) | |
64e03ca8 | 744 | log_warning_errno(r, "Failed to drop CAP_SYS_ADMIN, ignoring: %m."); |
6d9ef22a MC |
745 | |
746 | r = drop_capability(CAP_BPF); | |
747 | if (r < 0) | |
64e03ca8 | 748 | log_warning_errno(r, "Failed to drop CAP_BPF, ignoring: %m."); |
6d9ef22a | 749 | |
3976c430 YW |
750 | manager_set_sysctl(m); |
751 | ||
489671d2 YW |
752 | r = manager_request_static_address_labels(m); |
753 | if (r < 0) | |
754 | return r; | |
755 | ||
a879e1a4 YW |
756 | r = manager_start_speed_meter(m); |
757 | if (r < 0) | |
758 | return log_error_errno(r, "Failed to initialize speed meter: %m"); | |
759 | ||
9c402e3a YW |
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 | ||
84de38c5 TG |
771 | /* The dirty handler will deal with future serialization, but the first one |
772 | must be done explicitly. */ | |
773 | ||
d23a66f2 YW |
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); | |
84de38c5 | 777 | |
6eab614d | 778 | HASHMAP_FOREACH(link, m->links_by_index) { |
ac4a6950 | 779 | r = link_save_and_clean(link); |
d23a66f2 YW |
780 | if (r < 0) |
781 | log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file); | |
782 | } | |
84de38c5 | 783 | |
6119221a | 784 | log_debug("Started."); |
b76d99d9 | 785 | return 0; |
a97dcc12 TG |
786 | } |
787 | ||
5fae368b TG |
788 | int manager_load_config(Manager *m) { |
789 | int r; | |
790 | ||
6119221a YW |
791 | log_debug("Loading..."); |
792 | ||
173c9f63 | 793 | r = netdev_load(m); |
f579559b | 794 | if (r < 0) |
6119221a | 795 | return log_debug_errno(r, "Failed to load .netdev files: %m"); |
f579559b | 796 | |
af7a86b8 YW |
797 | manager_clear_unmanaged_tuntap_fds(m); |
798 | ||
7f06b3e1 | 799 | r = network_load(m, &m->networks); |
9021bb9f | 800 | if (r < 0) |
6119221a | 801 | return log_debug_errno(r, "Failed to load .network files: %m"); |
9021bb9f | 802 | |
fb126bb1 YW |
803 | r = manager_build_dhcp_pd_subnet_ids(m); |
804 | if (r < 0) | |
6119221a | 805 | return log_debug_errno(r, "Failed to build DHCP-PD subnet ID map: %m"); |
fb126bb1 YW |
806 | |
807 | r = manager_build_nexthop_ids(m); | |
808 | if (r < 0) | |
6119221a | 809 | return log_debug_errno(r, "Failed to build nexthop ID map: %m"); |
fb126bb1 | 810 | |
6119221a | 811 | log_debug("Loaded."); |
fb126bb1 | 812 | return 0; |
f579559b | 813 | } |
f882c247 | 814 | |
41476186 | 815 | int manager_enumerate_internal( |
446aaaf3 | 816 | Manager *m, |
bdcd4ab2 | 817 | sd_netlink *nl, |
446aaaf3 | 818 | sd_netlink_message *req, |
f12629ae | 819 | int (*process)(sd_netlink *, sd_netlink_message *, Manager *)) { |
446aaaf3 YW |
820 | |
821 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL; | |
1339b950 | 822 | int r; |
f882c247 | 823 | |
5da8149f | 824 | assert(m); |
bdcd4ab2 | 825 | assert(nl); |
446aaaf3 YW |
826 | assert(req); |
827 | assert(process); | |
f882c247 | 828 | |
24c0f385 | 829 | r = sd_netlink_message_set_request_dump(req, true); |
dd3efc09 TG |
830 | if (r < 0) |
831 | return r; | |
832 | ||
bdcd4ab2 | 833 | r = sd_netlink_call(nl, req, 0, &reply); |
f12629ae | 834 | if (r < 0) |
f2236469 TG |
835 | return r; |
836 | ||
a6b08423 | 837 | m->enumerating = true; |
1339b950 ZJS |
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)); | |
a6b08423 | 840 | m->enumerating = false; |
2e9f08ea | 841 | |
5fae368b | 842 | return r; |
f882c247 | 843 | } |
3bef724f | 844 | |
446aaaf3 YW |
845 | static int manager_enumerate_links(Manager *m) { |
846 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1346b1f0 TG |
847 | int r; |
848 | ||
5fae368b TG |
849 | assert(m); |
850 | assert(m->rtnl); | |
bcbca829 | 851 | |
446aaaf3 | 852 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); |
5fae368b TG |
853 | if (r < 0) |
854 | return r; | |
855 | ||
11cee6ef YW |
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 | ||
f12629ae | 870 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); |
446aaaf3 | 871 | } |
5fae368b | 872 | |
828a81a9 YW |
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) { | |
41476186 YW |
888 | Link *link; |
889 | int r = 0; | |
828a81a9 YW |
890 | |
891 | assert(m); | |
892 | assert(m->rtnl); | |
893 | ||
41476186 YW |
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)); | |
828a81a9 | 898 | |
41476186 | 899 | return r; |
828a81a9 YW |
900 | } |
901 | ||
446aaaf3 YW |
902 | static int manager_enumerate_addresses(Manager *m) { |
903 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
904 | int r; | |
6a24f148 | 905 | |
446aaaf3 YW |
906 | assert(m); |
907 | assert(m->rtnl); | |
6a24f148 | 908 | |
446aaaf3 YW |
909 | r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0); |
910 | if (r < 0) | |
911 | return r; | |
5fae368b | 912 | |
f12629ae | 913 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_address); |
1346b1f0 | 914 | } |
d1bdafd2 | 915 | |
446aaaf3 YW |
916 | static int manager_enumerate_neighbors(Manager *m) { |
917 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
d1bdafd2 WKI |
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 | ||
f12629ae | 927 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_neighbor); |
d1bdafd2 | 928 | } |
1346b1f0 | 929 | |
446aaaf3 YW |
930 | static int manager_enumerate_routes(Manager *m) { |
931 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1c8e710c TG |
932 | int r; |
933 | ||
934 | assert(m); | |
935 | assert(m->rtnl); | |
936 | ||
5ff1ef31 YW |
937 | if (!m->manage_foreign_routes) |
938 | return 0; | |
939 | ||
1c8e710c TG |
940 | r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0); |
941 | if (r < 0) | |
942 | return r; | |
943 | ||
f12629ae | 944 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_route); |
1c8e710c TG |
945 | } |
946 | ||
446aaaf3 YW |
947 | static int manager_enumerate_rules(Manager *m) { |
948 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
bce67bbe SS |
949 | int r; |
950 | ||
951 | assert(m); | |
952 | assert(m->rtnl); | |
953 | ||
d94dfe70 YW |
954 | if (!m->manage_foreign_rules) |
955 | return 0; | |
956 | ||
bce67bbe SS |
957 | r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0); |
958 | if (r < 0) | |
959 | return r; | |
960 | ||
f12629ae | 961 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_rule); |
bce67bbe SS |
962 | } |
963 | ||
446aaaf3 YW |
964 | static int manager_enumerate_nexthop(Manager *m) { |
965 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
c16c7808 SS |
966 | int r; |
967 | ||
968 | assert(m); | |
969 | assert(m->rtnl); | |
970 | ||
bbc05bec YW |
971 | if (!m->manage_foreign_nexthops) |
972 | return 0; | |
973 | ||
c16c7808 SS |
974 | r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0); |
975 | if (r < 0) | |
976 | return r; | |
977 | ||
f12629ae | 978 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop); |
446aaaf3 | 979 | } |
c16c7808 | 980 | |
edb69db2 YW |
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 | ||
96f5f9ef YW |
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 | ||
446aaaf3 YW |
1038 | int manager_enumerate(Manager *m) { |
1039 | int r; | |
c16c7808 | 1040 | |
6119221a YW |
1041 | log_debug("Enumerating..."); |
1042 | ||
446aaaf3 YW |
1043 | r = manager_enumerate_links(m); |
1044 | if (r < 0) | |
1045 | return log_error_errno(r, "Could not enumerate links: %m"); | |
c16c7808 | 1046 | |
6698795e | 1047 | /* If the kernel is built without CONFIG_NET_SCHED, the below will fail with -EOPNOTSUPP. */ |
828a81a9 | 1048 | r = manager_enumerate_qdisc(m); |
15ac2a62 YW |
1049 | if (r == -EOPNOTSUPP) |
1050 | log_debug_errno(r, "Could not enumerate QDiscs, ignoring: %m"); | |
1051 | else if (r < 0) | |
828a81a9 YW |
1052 | return log_error_errno(r, "Could not enumerate QDisc: %m"); |
1053 | ||
6698795e | 1054 | /* If the kernel is built without CONFIG_NET_CLS, the below will fail with -EOPNOTSUPP. */ |
828a81a9 | 1055 | r = manager_enumerate_tclass(m); |
15ac2a62 YW |
1056 | if (r == -EOPNOTSUPP) |
1057 | log_debug_errno(r, "Could not enumerate TClasses, ignoring: %m"); | |
1058 | else if (r < 0) | |
828a81a9 YW |
1059 | return log_error_errno(r, "Could not enumerate TClass: %m"); |
1060 | ||
446aaaf3 YW |
1061 | r = manager_enumerate_addresses(m); |
1062 | if (r < 0) | |
1063 | return log_error_errno(r, "Could not enumerate addresses: %m"); | |
c16c7808 | 1064 | |
446aaaf3 YW |
1065 | r = manager_enumerate_neighbors(m); |
1066 | if (r < 0) | |
1067 | return log_error_errno(r, "Could not enumerate neighbors: %m"); | |
c16c7808 | 1068 | |
0c0585ca | 1069 | r = manager_enumerate_nexthop(m); |
034b69d8 | 1070 | if (r < 0) |
f12629ae | 1071 | return log_error_errno(r, "Could not enumerate nexthops: %m"); |
0c0585ca | 1072 | |
446aaaf3 YW |
1073 | r = manager_enumerate_routes(m); |
1074 | if (r < 0) | |
1075 | return log_error_errno(r, "Could not enumerate routes: %m"); | |
c16c7808 | 1076 | |
6698795e | 1077 | /* If the kernel is built without CONFIG_FIB_RULES, the below will fail with -EOPNOTSUPP. */ |
446aaaf3 | 1078 | r = manager_enumerate_rules(m); |
f12629ae YW |
1079 | if (r == -EOPNOTSUPP) |
1080 | log_debug_errno(r, "Could not enumerate routing policy rules, ignoring: %m"); | |
1081 | else if (r < 0) | |
446aaaf3 | 1082 | return log_error_errno(r, "Could not enumerate routing policy rules: %m"); |
c16c7808 | 1083 | |
4bfbf0fc | 1084 | /* If the kernel is built without CONFIG_WIRELESS, the below will fail with -EOPNOTSUPP. */ |
edb69db2 YW |
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 | ||
96f5f9ef YW |
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 | ||
6119221a | 1103 | log_debug("Enumeration completed."); |
446aaaf3 | 1104 | return 0; |
c16c7808 SS |
1105 | } |
1106 | ||
59eb33e0 | 1107 | static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { |
59eb33e0 | 1108 | const sd_bus_error *e; |
f63e09ef | 1109 | int r; |
59eb33e0 MP |
1110 | |
1111 | assert(m); | |
59eb33e0 MP |
1112 | |
1113 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
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 | } | |
59eb33e0 MP |
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)); | |
d7afd945 | 1126 | |
b3f9c17a YW |
1127 | r = free_and_strdup_warn(&m->dynamic_hostname, hostname); |
1128 | if (r < 0) | |
1129 | return r; | |
59eb33e0 | 1130 | |
5dbec9bd ZJS |
1131 | if (sd_bus_is_ready(m->bus) <= 0) { |
1132 | log_debug("Not connected to system bus, setting system hostname later."); | |
59eb33e0 MP |
1133 | return 0; |
1134 | } | |
1135 | ||
d2775306 | 1136 | r = bus_call_method_async( |
59eb33e0 MP |
1137 | m->bus, |
1138 | NULL, | |
d2775306 | 1139 | bus_hostname, |
59eb33e0 MP |
1140 | "SetHostname", |
1141 | set_hostname_handler, | |
1142 | m, | |
1143 | "sb", | |
1144 | hostname, | |
1145 | false); | |
59eb33e0 MP |
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) { | |
59eb33e0 | 1153 | const sd_bus_error *e; |
f63e09ef | 1154 | int r; |
59eb33e0 MP |
1155 | |
1156 | assert(m); | |
59eb33e0 MP |
1157 | |
1158 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
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 | } | |
59eb33e0 MP |
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); | |
b3f9c17a YW |
1174 | r = free_and_strdup_warn(&m->dynamic_timezone, tz); |
1175 | if (r < 0) | |
1176 | return r; | |
59eb33e0 | 1177 | |
5dbec9bd ZJS |
1178 | if (sd_bus_is_ready(m->bus) <= 0) { |
1179 | log_debug("Not connected to system bus, setting system timezone later."); | |
59eb33e0 MP |
1180 | return 0; |
1181 | } | |
1182 | ||
b607fd3f | 1183 | r = bus_call_method_async( |
59eb33e0 MP |
1184 | m->bus, |
1185 | NULL, | |
b607fd3f | 1186 | bus_timedate, |
59eb33e0 MP |
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 | } | |
0e07cdb0 | 1198 | |
1e869a5d | 1199 | int manager_reload(Manager *m, sd_bus_message *message) { |
0e07cdb0 LP |
1200 | Link *link; |
1201 | int r; | |
1202 | ||
1203 | assert(m); | |
1204 | ||
6119221a | 1205 | log_debug("Reloading..."); |
b377a7cc | 1206 | (void) notify_reloading(); |
0e07cdb0 | 1207 | |
b3ae4e86 | 1208 | r = netdev_reload(m); |
6119221a YW |
1209 | if (r < 0) { |
1210 | log_debug_errno(r, "Failed to reload .netdev files: %m"); | |
0e07cdb0 | 1211 | goto finish; |
6119221a | 1212 | } |
0e07cdb0 LP |
1213 | |
1214 | r = network_reload(m); | |
6119221a YW |
1215 | if (r < 0) { |
1216 | log_debug_errno(r, "Failed to reload .network files: %m"); | |
0e07cdb0 | 1217 | goto finish; |
6119221a | 1218 | } |
0e07cdb0 | 1219 | |
2b07a321 YW |
1220 | HASHMAP_FOREACH(link, m->links_by_index) |
1221 | (void) link_reconfigure_full(link, /* flags = */ 0, message, | |
1222 | /* counter = */ message ? &m->reloading : NULL); | |
0e07cdb0 | 1223 | |
6119221a | 1224 | log_debug("Reloaded."); |
0e07cdb0 LP |
1225 | r = 0; |
1226 | finish: | |
792a8bfb | 1227 | (void) sd_notify(/* unset_environment= */ false, NOTIFY_READY_MESSAGE); |
0e07cdb0 LP |
1228 | return r; |
1229 | } |