]>
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 | |
af7a86b8 YW |
208 | static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) { |
209 | _cleanup_strv_free_ char **names = NULL; | |
254d1313 | 210 | int n, rtnl_fd = -EBADF; |
5fae368b | 211 | |
af7a86b8 YW |
212 | assert(m); |
213 | assert(ret_rtnl_fd); | |
214 | ||
215 | n = sd_listen_fds_with_names(/* unset_environment = */ true, &names); | |
216 | if (n < 0) | |
217 | return n; | |
218 | ||
af7a86b8 YW |
219 | for (int i = 0; i < n; i++) { |
220 | int fd = i + SD_LISTEN_FDS_START; | |
221 | ||
5fae368b | 222 | if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { |
af7a86b8 YW |
223 | if (rtnl_fd >= 0) { |
224 | log_debug("Received multiple netlink socket, ignoring."); | |
ae659748 | 225 | goto unused; |
af7a86b8 | 226 | } |
5fae368b TG |
227 | |
228 | rtnl_fd = fd; | |
af7a86b8 | 229 | continue; |
5fae368b | 230 | } |
5fae368b | 231 | |
c321d332 YW |
232 | if (manager_set_serialization_fd(m, fd, names[i]) >= 0) |
233 | continue; | |
234 | ||
af7a86b8 YW |
235 | if (manager_add_tuntap_fd(m, fd, names[i]) >= 0) |
236 | continue; | |
237 | ||
ae659748 | 238 | unused: |
af7a86b8 YW |
239 | if (m->test_mode) |
240 | safe_close(fd); | |
241 | else | |
242 | close_and_notify_warn(fd, names[i]); | |
243 | } | |
244 | ||
245 | *ret_rtnl_fd = rtnl_fd; | |
246 | return 0; | |
5fae368b TG |
247 | } |
248 | ||
05d0c2e3 JT |
249 | static int manager_connect_genl(Manager *m) { |
250 | int r; | |
251 | ||
252 | assert(m); | |
253 | ||
254 | r = sd_genl_socket_open(&m->genl); | |
255 | if (r < 0) | |
256 | return r; | |
257 | ||
78cca583 | 258 | r = sd_netlink_increase_rxbuf(m->genl, RCVBUF_SIZE); |
05d0c2e3 | 259 | if (r < 0) |
8c63924c | 260 | log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m"); |
05d0c2e3 JT |
261 | |
262 | r = sd_netlink_attach_event(m->genl, m->event, 0); | |
263 | if (r < 0) | |
264 | return r; | |
265 | ||
4bfbf0fc | 266 | /* If the kernel is built without CONFIG_WIRELESS, the below will fail with -EOPNOTSUPP. */ |
96f5f9ef YW |
267 | r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_CONFIG, 0, |
268 | &manager_genl_process_nl80211_config, NULL, m, "network-genl_process_nl80211_config"); | |
269 | if (r < 0 && r != -EOPNOTSUPP) | |
270 | return r; | |
271 | ||
272 | r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_MLME, 0, | |
273 | &manager_genl_process_nl80211_mlme, NULL, m, "network-genl_process_nl80211_mlme"); | |
274 | if (r < 0 && r != -EOPNOTSUPP) | |
275 | return r; | |
276 | ||
05d0c2e3 JT |
277 | return 0; |
278 | } | |
279 | ||
26a8be48 YW |
280 | static int manager_setup_rtnl_filter(Manager *manager) { |
281 | struct sock_filter filter[] = { | |
282 | /* Check the packet length. */ | |
283 | BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ | |
284 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr), 1, 0), /* A (packet length) >= sizeof(struct nlmsghdr) ? */ | |
285 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
286 | /* Always accept multipart message. */ | |
287 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_flags)), /* A <- message flags */ | |
288 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NLM_F_MULTI), 0, 1), /* message flags has NLM_F_MULTI ? */ | |
289 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
290 | /* Accept all message types except for RTM_NEWNEIGH or RTM_DELNEIGH. */ | |
291 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_type)), /* A <- message type */ | |
292 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_NEWNEIGH), 2, 0), /* message type == RTM_NEWNEIGH ? */ | |
293 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_DELNEIGH), 1, 0), /* message type == RTM_DELNEIGH ? */ | |
294 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
295 | /* Check the packet length. */ | |
296 | BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ | |
297 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr) + sizeof(struct ndmsg), 1, 0), | |
298 | /* packet length >= sizeof(struct nlmsghdr) + sizeof(struct ndmsg) ? */ | |
299 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
300 | /* Reject the message when the neighbor state does not have NUD_PERMANENT flag. */ | |
301 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, sizeof(struct nlmsghdr) + offsetof(struct ndmsg, ndm_state)), | |
302 | /* A <- neighbor state */ | |
303 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NUD_PERMANENT), 1, 0), /* neighbor state has NUD_PERMANENT ? */ | |
304 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
305 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
306 | }; | |
307 | ||
308 | assert(manager); | |
309 | assert(manager->rtnl); | |
310 | ||
311 | return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter); | |
312 | } | |
313 | ||
af7a86b8 YW |
314 | static int manager_connect_rtnl(Manager *m, int fd) { |
315 | _unused_ _cleanup_close_ int fd_close = fd; | |
316 | int r; | |
505f8da7 TG |
317 | |
318 | assert(m); | |
505f8da7 | 319 | |
af7a86b8 YW |
320 | /* This takes input fd. */ |
321 | ||
5fae368b | 322 | if (fd < 0) |
1c4baffc | 323 | r = sd_netlink_open(&m->rtnl); |
5fae368b | 324 | else |
1c4baffc | 325 | r = sd_netlink_open_fd(&m->rtnl, fd); |
505f8da7 TG |
326 | if (r < 0) |
327 | return r; | |
af7a86b8 | 328 | TAKE_FD(fd_close); |
505f8da7 | 329 | |
e13af7bd YW |
330 | /* Bump receiver buffer, but only if we are not called via socket activation, as in that |
331 | * case systemd sets the receive buffer size for us, and the value in the .socket unit | |
332 | * should take full effect. */ | |
333 | if (fd < 0) { | |
78cca583 | 334 | r = sd_netlink_increase_rxbuf(m->rtnl, RCVBUF_SIZE); |
e13af7bd YW |
335 | if (r < 0) |
336 | log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m"); | |
337 | } | |
f579559b | 338 | |
1c4baffc | 339 | r = sd_netlink_attach_event(m->rtnl, m->event, 0); |
505f8da7 TG |
340 | if (r < 0) |
341 | return r; | |
f579559b | 342 | |
8dfed23d | 343 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
344 | if (r < 0) |
345 | return r; | |
505f8da7 | 346 | |
8dfed23d | 347 | r = netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
348 | if (r < 0) |
349 | return r; | |
45af44d4 | 350 | |
828a81a9 YW |
351 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); |
352 | if (r < 0) | |
353 | return r; | |
354 | ||
355 | r = netlink_add_match(m->rtnl, NULL, RTM_DELQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); | |
356 | if (r < 0) | |
357 | return r; | |
358 | ||
359 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); | |
360 | if (r < 0) | |
361 | return r; | |
362 | ||
363 | r = netlink_add_match(m->rtnl, NULL, RTM_DELTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); | |
364 | if (r < 0) | |
365 | return r; | |
366 | ||
8dfed23d | 367 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
368 | if (r < 0) |
369 | return r; | |
370 | ||
8dfed23d | 371 | r = netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
372 | if (r < 0) |
373 | return r; | |
374 | ||
8dfed23d | 375 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
376 | if (r < 0) |
377 | return r; | |
378 | ||
8dfed23d | 379 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
380 | if (r < 0) |
381 | return r; | |
382 | ||
8dfed23d | 383 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
384 | if (r < 0) |
385 | return r; | |
386 | ||
8dfed23d | 387 | r = netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
388 | if (r < 0) |
389 | return r; | |
390 | ||
8dfed23d | 391 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
392 | if (r < 0) |
393 | return r; | |
394 | ||
8dfed23d | 395 | r = netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
396 | if (r < 0) |
397 | return r; | |
398 | ||
8dfed23d | 399 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
400 | if (r < 0) |
401 | return r; | |
402 | ||
8dfed23d | 403 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
404 | if (r < 0) |
405 | return r; | |
406 | ||
26a8be48 | 407 | return manager_setup_rtnl_filter(m); |
45af44d4 | 408 | } |
505f8da7 | 409 | |
2e1113b7 YW |
410 | static int manager_post_handler(sd_event_source *s, void *userdata) { |
411 | Manager *manager = ASSERT_PTR(userdata); | |
84de38c5 | 412 | |
db68e990 YW |
413 | /* To release dynamic leases, we need to process queued remove requests before stopping networkd. |
414 | * This is especially important when KeepConfiguration=no. See issue #34837. */ | |
85a6f300 | 415 | (void) manager_process_remove_requests(manager); |
db68e990 YW |
416 | |
417 | switch (manager->state) { | |
418 | case MANAGER_RUNNING: | |
419 | (void) manager_process_requests(manager); | |
420 | (void) manager_clean_all(manager); | |
421 | return 0; | |
422 | ||
423 | case MANAGER_TERMINATING: | |
424 | case MANAGER_RESTARTING: | |
425 | if (!ordered_set_isempty(manager->remove_request_queue)) | |
426 | return 0; /* There are some unissued remove requests. */ | |
427 | ||
428 | if (netlink_get_reply_callback_count(manager->rtnl) > 0 || | |
429 | netlink_get_reply_callback_count(manager->genl) > 0 || | |
430 | fw_ctx_get_reply_callback_count(manager->fw_ctx) > 0) | |
431 | return 0; /* There are some message calls waiting for their replies. */ | |
432 | ||
c321d332 | 433 | (void) manager_serialize(manager); |
db68e990 YW |
434 | manager->state = MANAGER_STOPPED; |
435 | return sd_event_exit(sd_event_source_get_event(s), 0); | |
436 | ||
437 | default: | |
438 | assert_not_reached(); | |
439 | } | |
440 | ||
2e1113b7 | 441 | return 0; |
84de38c5 TG |
442 | } |
443 | ||
db68e990 YW |
444 | static int manager_stop(Manager *manager, ManagerState state) { |
445 | assert(manager); | |
446 | assert(IN_SET(state, MANAGER_TERMINATING, MANAGER_RESTARTING)); | |
ab76be55 | 447 | |
db68e990 YW |
448 | if (manager->state != MANAGER_RUNNING) { |
449 | log_debug("Already terminating or restarting systemd-networkd, refusing further operation request."); | |
450 | return 0; | |
451 | } | |
ab76be55 | 452 | |
db68e990 YW |
453 | switch (state) { |
454 | case MANAGER_TERMINATING: | |
455 | log_debug("Terminate operation initiated."); | |
456 | break; | |
457 | case MANAGER_RESTARTING: | |
458 | log_debug("Restart operation initiated."); | |
459 | break; | |
460 | default: | |
461 | assert_not_reached(); | |
462 | } | |
ab76be55 | 463 | |
db68e990 | 464 | manager->state = state; |
ab76be55 | 465 | |
db68e990 | 466 | Link *link; |
49e50134 | 467 | HASHMAP_FOREACH(link, manager->links_by_index) |
80a89d1a | 468 | (void) link_stop_engines(link, /* may_keep_dynamic = */ true); |
ab76be55 | 469 | |
db68e990 YW |
470 | return 0; |
471 | } | |
ab76be55 | 472 | |
db68e990 YW |
473 | static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
474 | return manager_stop(userdata, MANAGER_TERMINATING); | |
475 | } | |
ab76be55 | 476 | |
db68e990 YW |
477 | static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
478 | return manager_stop(userdata, MANAGER_RESTARTING); | |
ab76be55 ZJS |
479 | } |
480 | ||
0e07cdb0 LP |
481 | static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
482 | Manager *m = ASSERT_PTR(userdata); | |
483 | ||
1e869a5d | 484 | (void) manager_reload(m, /* message = */ NULL); |
0e07cdb0 LP |
485 | |
486 | return 0; | |
487 | } | |
488 | ||
ea853de5 YW |
489 | static int manager_set_keep_configuration(Manager *m) { |
490 | int r; | |
491 | ||
492 | assert(m); | |
493 | ||
494 | if (in_initrd()) { | |
80a89d1a YW |
495 | log_debug("Running in initrd, keep dynamically assigned configurations on stopping networkd by default."); |
496 | m->keep_configuration = KEEP_CONFIGURATION_DYNAMIC_ON_STOP; | |
ea853de5 YW |
497 | return 0; |
498 | } | |
499 | ||
c0323de6 YW |
500 | r = path_is_network_fs_harder("/"); |
501 | if (r < 0) { | |
502 | log_warning_errno(r, "Failed to detect if root is network filesystem, assuming not: %m"); | |
503 | return 0; | |
504 | } | |
ea853de5 YW |
505 | if (r == 0) { |
506 | m->keep_configuration = _KEEP_CONFIGURATION_INVALID; | |
507 | return 0; | |
508 | } | |
509 | ||
510 | log_debug("Running on network filesystem, enabling KeepConfiguration= by default."); | |
511 | m->keep_configuration = KEEP_CONFIGURATION_YES; | |
512 | return 0; | |
513 | } | |
514 | ||
4c78dc17 | 515 | int manager_setup(Manager *m) { |
254d1313 | 516 | _cleanup_close_ int rtnl_fd = -EBADF; |
45af44d4 | 517 | int r; |
f579559b | 518 | |
96243149 | 519 | assert(m); |
5fae368b | 520 | |
3534a043 YW |
521 | r = sd_event_default(&m->event); |
522 | if (r < 0) | |
523 | return r; | |
524 | ||
05e21627 | 525 | (void) sd_event_set_watchdog(m->event, true); |
0e07cdb0 LP |
526 | (void) sd_event_add_signal(m->event, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m); |
527 | (void) sd_event_add_signal(m->event, NULL, SIGINT | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m); | |
528 | (void) sd_event_add_signal(m->event, NULL, SIGUSR2 | SD_EVENT_SIGNAL_PROCMASK, signal_restart_callback, m); | |
529 | (void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, signal_reload_callback, m); | |
6daaeafe LP |
530 | (void) sd_event_add_signal(m->event, NULL, (SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL); |
531 | ||
532 | r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL); | |
533 | if (r < 0) | |
534 | log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m"); | |
5fae368b | 535 | |
2e1113b7 | 536 | r = sd_event_add_post(m->event, NULL, manager_post_handler, m); |
84de38c5 TG |
537 | if (r < 0) |
538 | return r; | |
539 | ||
af7a86b8 YW |
540 | r = manager_listen_fds(m, &rtnl_fd); |
541 | if (r < 0) | |
542 | return r; | |
543 | ||
544 | r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd)); | |
45af44d4 TG |
545 | if (r < 0) |
546 | return r; | |
547 | ||
05d0c2e3 JT |
548 | r = manager_connect_genl(m); |
549 | if (r < 0) | |
550 | return r; | |
551 | ||
4c78dc17 | 552 | if (m->test_mode) |
96243149 YW |
553 | return 0; |
554 | ||
c5c74d85 LP |
555 | r = manager_connect_varlink(m); |
556 | if (r < 0) | |
557 | return r; | |
558 | ||
96243149 YW |
559 | r = manager_connect_bus(m); |
560 | if (r < 0) | |
561 | return r; | |
562 | ||
5fae368b TG |
563 | r = manager_connect_udev(m); |
564 | if (r < 0) | |
565 | return r; | |
45af44d4 | 566 | |
05d0c2e3 JT |
567 | r = sd_resolve_default(&m->resolve); |
568 | if (r < 0) | |
569 | return r; | |
570 | ||
571 | r = sd_resolve_attach_event(m->resolve, m->event, 0); | |
572 | if (r < 0) | |
573 | return r; | |
574 | ||
ed76f585 | 575 | r = address_pool_setup_default(m); |
5fae368b TG |
576 | if (r < 0) |
577 | return r; | |
f579559b | 578 | |
ea853de5 YW |
579 | r = manager_set_keep_configuration(m); |
580 | if (r < 0) | |
581 | return r; | |
582 | ||
96243149 YW |
583 | m->state_file = strdup("/run/systemd/netif/state"); |
584 | if (!m->state_file) | |
585 | return -ENOMEM; | |
586 | ||
587 | return 0; | |
588 | } | |
589 | ||
013359ac YW |
590 | static int persistent_storage_open(void) { |
591 | _cleanup_close_ int fd = -EBADF; | |
f90eb086 YW |
592 | int r; |
593 | ||
013359ac YW |
594 | r = getenv_bool("SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY"); |
595 | if (r < 0 && r != -ENXIO) | |
596 | return log_debug_errno(r, "Failed to parse $SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY environment variable, ignoring: %m"); | |
597 | if (r <= 0) | |
598 | return -EBADF; | |
f90eb086 | 599 | |
fb6f98ae | 600 | fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY); |
013359ac | 601 | if (fd < 0) |
42ba9974 | 602 | return log_debug_errno(errno, "Failed to open %s, ignoring: %m", "/var/lib/systemd/network/"); |
f90eb086 | 603 | |
013359ac YW |
604 | r = fd_is_read_only_fs(fd); |
605 | if (r < 0) | |
606 | return log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m"); | |
607 | if (r > 0) | |
608 | return log_debug_errno(SYNTHETIC_ERRNO(EROFS), "The directory /var/lib/systemd/network/ is on read-only filesystem."); | |
f90eb086 | 609 | |
013359ac | 610 | return TAKE_FD(fd); |
f90eb086 YW |
611 | } |
612 | ||
4c78dc17 | 613 | int manager_new(Manager **ret, bool test_mode) { |
96243149 | 614 | _cleanup_(manager_freep) Manager *m = NULL; |
f579559b | 615 | |
96243149 YW |
616 | m = new(Manager, 1); |
617 | if (!m) | |
618 | return -ENOMEM; | |
619 | ||
620 | *m = (Manager) { | |
ea853de5 | 621 | .keep_configuration = _KEEP_CONFIGURATION_INVALID, |
932ef6ec | 622 | .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO, |
4c78dc17 | 623 | .test_mode = test_mode, |
96243149 YW |
624 | .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL, |
625 | .online_state = _LINK_ONLINE_STATE_INVALID, | |
626 | .manage_foreign_routes = true, | |
627 | .manage_foreign_rules = true, | |
bbc05bec | 628 | .manage_foreign_nexthops = true, |
254d1313 | 629 | .ethtool_fd = -EBADF, |
013359ac | 630 | .persistent_storage_fd = persistent_storage_open(), |
7a169cb4 YW |
631 | .dhcp_use_domains = _USE_DOMAINS_INVALID, |
632 | .dhcp6_use_domains = _USE_DOMAINS_INVALID, | |
418f2dc7 | 633 | .ndisc_use_domains = _USE_DOMAINS_INVALID, |
7bbe9ad7 | 634 | .dhcp_client_identifier = DHCP_CLIENT_ID_DUID, |
96243149 YW |
635 | .dhcp_duid.type = DUID_TYPE_EN, |
636 | .dhcp6_duid.type = DUID_TYPE_EN, | |
637 | .duid_product_uuid.type = DUID_TYPE_UUID, | |
a145343b | 638 | .dhcp_server_persist_leases = DHCP_SERVER_PERSIST_LEASES_YES, |
c321d332 | 639 | .serialization_fd = -EBADF, |
3976c430 | 640 | .ip_forwarding = { -1, -1, }, |
4d6ad22f | 641 | #if HAVE_VMLINUX_H |
6d9ef22a | 642 | .cgroup_fd = -EBADF, |
4d6ad22f | 643 | #endif |
96243149 YW |
644 | }; |
645 | ||
646 | *ret = TAKE_PTR(m); | |
f579559b TG |
647 | return 0; |
648 | } | |
649 | ||
75db809a | 650 | Manager* manager_free(Manager *m) { |
5fae368b | 651 | if (!m) |
75db809a | 652 | return NULL; |
505f8da7 | 653 | |
22583a00 | 654 | manager_remove_sysctl_monitor(m); |
6d9ef22a | 655 | |
5fae368b | 656 | free(m->state_file); |
505f8da7 | 657 | |
40b12fa2 | 658 | m->request_queue = ordered_set_free(m->request_queue); |
85a6f300 | 659 | m->remove_request_queue = ordered_set_free(m->remove_request_queue); |
19d9a5ad | 660 | |
9c5b8d46 | 661 | m->new_wlan_ifindices = set_free(m->new_wlan_ifindices); |
4cf443e6 YW |
662 | |
663 | m->dirty_links = set_free(m->dirty_links); | |
0b54c870 | 664 | m->links_by_name = hashmap_free(m->links_by_name); |
fe321d45 | 665 | m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr); |
a27588d4 | 666 | m->links_by_dhcp_pd_subnet_prefix = hashmap_free(m->links_by_dhcp_pd_subnet_prefix); |
4cf443e6 | 667 | m->links_by_index = hashmap_free(m->links_by_index); |
27dfc982 | 668 | |
a27588d4 | 669 | m->dhcp_pd_subnet_ids = set_free(m->dhcp_pd_subnet_ids); |
a85f73fa | 670 | m->networks = ordered_hashmap_free(m->networks); |
dbffab87 | 671 | |
bdf4f200 | 672 | /* The same object may be registered with multiple names, and netdev_detach() may drop multiple entries. */ |
36ca0164 YW |
673 | for (NetDev *n; (n = hashmap_first(m->netdevs)); ) |
674 | netdev_detach(n); | |
675 | m->netdevs = hashmap_free(m->netdevs); | |
5fae368b | 676 | |
af7a86b8 YW |
677 | m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name); |
678 | ||
edb69db2 | 679 | m->wiphy_by_name = hashmap_free(m->wiphy_by_name); |
52278e06 | 680 | m->wiphy_by_index = hashmap_free(m->wiphy_by_index); |
edb69db2 | 681 | |
04b7949e | 682 | ordered_set_free(m->address_pools); |
5fae368b | 683 | |
552b90a2 YW |
684 | hashmap_free(m->route_table_names_by_number); |
685 | hashmap_free(m->route_table_numbers_by_name); | |
c038ce46 | 686 | |
eb72fa3a | 687 | set_free(m->rules); |
bce67bbe | 688 | |
d4df6326 SS |
689 | sd_netlink_unref(m->rtnl); |
690 | sd_netlink_unref(m->genl); | |
691 | sd_resolve_unref(m->resolve); | |
692 | ||
450fa34b | 693 | m->routes = set_free(m->routes); |
450fa34b | 694 | |
69e244e3 | 695 | m->nexthops_by_id = hashmap_free(m->nexthops_by_id); |
fb126bb1 | 696 | m->nexthop_ids = set_free(m->nexthop_ids); |
69e244e3 | 697 | |
489671d2 YW |
698 | m->address_labels_by_section = hashmap_free(m->address_labels_by_section); |
699 | ||
a879e1a4 | 700 | sd_event_source_unref(m->speed_meter_event_source); |
2f5b4a77 | 701 | sd_event_unref(m->event); |
5fae368b | 702 | |
d2ebf952 | 703 | sd_device_monitor_unref(m->device_monitor); |
7d20d375 | 704 | |
c5c74d85 | 705 | manager_varlink_done(m); |
2a1ffd3e | 706 | hashmap_free(m->polkit_registry); |
92e31da1 | 707 | sd_bus_flush_close_unref(m->bus); |
7d20d375 | 708 | |
7901cea1 MP |
709 | free(m->dynamic_timezone); |
710 | free(m->dynamic_hostname); | |
711 | ||
c643bda5 | 712 | safe_close(m->ethtool_fd); |
013359ac | 713 | safe_close(m->persistent_storage_fd); |
c643bda5 | 714 | |
761cf19d FW |
715 | m->fw_ctx = fw_ctx_free(m->fw_ctx); |
716 | ||
c321d332 YW |
717 | m->serialization_fd = safe_close(m->serialization_fd); |
718 | ||
75db809a | 719 | return mfree(m); |
5fae368b TG |
720 | } |
721 | ||
b76d99d9 | 722 | int manager_start(Manager *m) { |
84de38c5 | 723 | Link *link; |
a879e1a4 | 724 | int r; |
84de38c5 | 725 | |
a97dcc12 TG |
726 | assert(m); |
727 | ||
6119221a YW |
728 | log_debug("Starting..."); |
729 | ||
22583a00 | 730 | (void) manager_install_sysctl_monitor(m); |
6d9ef22a MC |
731 | |
732 | /* Loading BPF programs requires CAP_SYS_ADMIN and CAP_BPF. | |
733 | * Drop the capabilities here, regardless if the load succeeds or not. */ | |
734 | r = drop_capability(CAP_SYS_ADMIN); | |
735 | if (r < 0) | |
64e03ca8 | 736 | log_warning_errno(r, "Failed to drop CAP_SYS_ADMIN, ignoring: %m."); |
6d9ef22a MC |
737 | |
738 | r = drop_capability(CAP_BPF); | |
739 | if (r < 0) | |
64e03ca8 | 740 | log_warning_errno(r, "Failed to drop CAP_BPF, ignoring: %m."); |
6d9ef22a | 741 | |
3976c430 YW |
742 | manager_set_sysctl(m); |
743 | ||
489671d2 YW |
744 | r = manager_request_static_address_labels(m); |
745 | if (r < 0) | |
746 | return r; | |
747 | ||
a879e1a4 YW |
748 | r = manager_start_speed_meter(m); |
749 | if (r < 0) | |
750 | return log_error_errno(r, "Failed to initialize speed meter: %m"); | |
751 | ||
9c402e3a YW |
752 | HASHMAP_FOREACH(link, m->links_by_index) { |
753 | if (link->state != LINK_STATE_PENDING) | |
754 | continue; | |
755 | ||
756 | r = link_check_initialized(link); | |
757 | if (r < 0) { | |
758 | log_link_warning_errno(link, r, "Failed to check if link is initialized: %m"); | |
759 | link_enter_failed(link); | |
760 | } | |
761 | } | |
762 | ||
84de38c5 TG |
763 | /* The dirty handler will deal with future serialization, but the first one |
764 | must be done explicitly. */ | |
765 | ||
d23a66f2 YW |
766 | r = manager_save(m); |
767 | if (r < 0) | |
768 | log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file); | |
84de38c5 | 769 | |
6eab614d | 770 | HASHMAP_FOREACH(link, m->links_by_index) { |
ac4a6950 | 771 | r = link_save_and_clean(link); |
d23a66f2 YW |
772 | if (r < 0) |
773 | log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file); | |
774 | } | |
84de38c5 | 775 | |
6119221a | 776 | log_debug("Started."); |
b76d99d9 | 777 | return 0; |
a97dcc12 TG |
778 | } |
779 | ||
5fae368b TG |
780 | int manager_load_config(Manager *m) { |
781 | int r; | |
782 | ||
6119221a YW |
783 | log_debug("Loading..."); |
784 | ||
173c9f63 | 785 | r = netdev_load(m); |
f579559b | 786 | if (r < 0) |
6119221a | 787 | return log_debug_errno(r, "Failed to load .netdev files: %m"); |
f579559b | 788 | |
af7a86b8 YW |
789 | manager_clear_unmanaged_tuntap_fds(m); |
790 | ||
7f06b3e1 | 791 | r = network_load(m, &m->networks); |
9021bb9f | 792 | if (r < 0) |
6119221a | 793 | return log_debug_errno(r, "Failed to load .network files: %m"); |
9021bb9f | 794 | |
fb126bb1 YW |
795 | r = manager_build_dhcp_pd_subnet_ids(m); |
796 | if (r < 0) | |
6119221a | 797 | return log_debug_errno(r, "Failed to build DHCP-PD subnet ID map: %m"); |
fb126bb1 YW |
798 | |
799 | r = manager_build_nexthop_ids(m); | |
800 | if (r < 0) | |
6119221a | 801 | return log_debug_errno(r, "Failed to build nexthop ID map: %m"); |
fb126bb1 | 802 | |
6119221a | 803 | log_debug("Loaded."); |
fb126bb1 | 804 | return 0; |
f579559b | 805 | } |
f882c247 | 806 | |
41476186 | 807 | int manager_enumerate_internal( |
446aaaf3 | 808 | Manager *m, |
bdcd4ab2 | 809 | sd_netlink *nl, |
446aaaf3 | 810 | sd_netlink_message *req, |
f12629ae | 811 | int (*process)(sd_netlink *, sd_netlink_message *, Manager *)) { |
446aaaf3 YW |
812 | |
813 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL; | |
1339b950 | 814 | int r; |
f882c247 | 815 | |
5da8149f | 816 | assert(m); |
bdcd4ab2 | 817 | assert(nl); |
446aaaf3 YW |
818 | assert(req); |
819 | assert(process); | |
f882c247 | 820 | |
24c0f385 | 821 | r = sd_netlink_message_set_request_dump(req, true); |
dd3efc09 TG |
822 | if (r < 0) |
823 | return r; | |
824 | ||
bdcd4ab2 | 825 | r = sd_netlink_call(nl, req, 0, &reply); |
f12629ae | 826 | if (r < 0) |
f2236469 TG |
827 | return r; |
828 | ||
a6b08423 | 829 | m->enumerating = true; |
1339b950 ZJS |
830 | for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) |
831 | RET_GATHER(r, process(nl, reply_one, m)); | |
a6b08423 | 832 | m->enumerating = false; |
2e9f08ea | 833 | |
5fae368b | 834 | return r; |
f882c247 | 835 | } |
3bef724f | 836 | |
446aaaf3 YW |
837 | static int manager_enumerate_links(Manager *m) { |
838 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1346b1f0 TG |
839 | int r; |
840 | ||
5fae368b TG |
841 | assert(m); |
842 | assert(m->rtnl); | |
bcbca829 | 843 | |
446aaaf3 | 844 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); |
5fae368b TG |
845 | if (r < 0) |
846 | return r; | |
847 | ||
11cee6ef YW |
848 | r = manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); |
849 | if (r < 0) | |
850 | return r; | |
851 | ||
852 | req = sd_netlink_message_unref(req); | |
853 | ||
854 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); | |
855 | if (r < 0) | |
856 | return r; | |
857 | ||
858 | r = sd_rtnl_message_link_set_family(req, AF_BRIDGE); | |
859 | if (r < 0) | |
860 | return r; | |
861 | ||
f12629ae | 862 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); |
446aaaf3 | 863 | } |
5fae368b | 864 | |
828a81a9 YW |
865 | static int manager_enumerate_qdisc(Manager *m) { |
866 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
867 | int r; | |
868 | ||
869 | assert(m); | |
870 | assert(m->rtnl); | |
871 | ||
872 | r = sd_rtnl_message_new_traffic_control(m->rtnl, &req, RTM_GETQDISC, 0, 0, 0); | |
873 | if (r < 0) | |
874 | return r; | |
875 | ||
876 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_qdisc); | |
877 | } | |
878 | ||
879 | static int manager_enumerate_tclass(Manager *m) { | |
41476186 YW |
880 | Link *link; |
881 | int r = 0; | |
828a81a9 YW |
882 | |
883 | assert(m); | |
884 | assert(m->rtnl); | |
885 | ||
41476186 YW |
886 | /* TC class can be enumerated only per link. See tc_dump_tclass() in net/sched/sched_api.c. */ |
887 | ||
888 | HASHMAP_FOREACH(link, m->links_by_index) | |
889 | RET_GATHER(r, link_enumerate_tclass(link, 0)); | |
828a81a9 | 890 | |
41476186 | 891 | return r; |
828a81a9 YW |
892 | } |
893 | ||
446aaaf3 YW |
894 | static int manager_enumerate_addresses(Manager *m) { |
895 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
896 | int r; | |
6a24f148 | 897 | |
446aaaf3 YW |
898 | assert(m); |
899 | assert(m->rtnl); | |
6a24f148 | 900 | |
446aaaf3 YW |
901 | r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0); |
902 | if (r < 0) | |
903 | return r; | |
5fae368b | 904 | |
f12629ae | 905 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_address); |
1346b1f0 | 906 | } |
d1bdafd2 | 907 | |
446aaaf3 YW |
908 | static int manager_enumerate_neighbors(Manager *m) { |
909 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
d1bdafd2 WKI |
910 | int r; |
911 | ||
912 | assert(m); | |
913 | assert(m->rtnl); | |
914 | ||
915 | r = sd_rtnl_message_new_neigh(m->rtnl, &req, RTM_GETNEIGH, 0, AF_UNSPEC); | |
916 | if (r < 0) | |
917 | return r; | |
918 | ||
f12629ae | 919 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_neighbor); |
d1bdafd2 | 920 | } |
1346b1f0 | 921 | |
446aaaf3 YW |
922 | static int manager_enumerate_routes(Manager *m) { |
923 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1c8e710c TG |
924 | int r; |
925 | ||
926 | assert(m); | |
927 | assert(m->rtnl); | |
928 | ||
5ff1ef31 YW |
929 | if (!m->manage_foreign_routes) |
930 | return 0; | |
931 | ||
1c8e710c TG |
932 | r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0); |
933 | if (r < 0) | |
934 | return r; | |
935 | ||
f12629ae | 936 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_route); |
1c8e710c TG |
937 | } |
938 | ||
446aaaf3 YW |
939 | static int manager_enumerate_rules(Manager *m) { |
940 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
bce67bbe SS |
941 | int r; |
942 | ||
943 | assert(m); | |
944 | assert(m->rtnl); | |
945 | ||
d94dfe70 YW |
946 | if (!m->manage_foreign_rules) |
947 | return 0; | |
948 | ||
bce67bbe SS |
949 | r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0); |
950 | if (r < 0) | |
951 | return r; | |
952 | ||
f12629ae | 953 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_rule); |
bce67bbe SS |
954 | } |
955 | ||
446aaaf3 YW |
956 | static int manager_enumerate_nexthop(Manager *m) { |
957 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
c16c7808 SS |
958 | int r; |
959 | ||
960 | assert(m); | |
961 | assert(m->rtnl); | |
962 | ||
bbc05bec YW |
963 | if (!m->manage_foreign_nexthops) |
964 | return 0; | |
965 | ||
c16c7808 SS |
966 | r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0); |
967 | if (r < 0) | |
968 | return r; | |
969 | ||
f12629ae | 970 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop); |
446aaaf3 | 971 | } |
c16c7808 | 972 | |
edb69db2 YW |
973 | static int manager_enumerate_nl80211_wiphy(Manager *m) { |
974 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
975 | int r; | |
976 | ||
977 | assert(m); | |
978 | assert(m->genl); | |
979 | ||
980 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_WIPHY, &req); | |
981 | if (r < 0) | |
982 | return r; | |
983 | ||
984 | return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_wiphy); | |
985 | } | |
986 | ||
96f5f9ef YW |
987 | static int manager_enumerate_nl80211_config(Manager *m) { |
988 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
989 | int r; | |
990 | ||
991 | assert(m); | |
992 | assert(m->genl); | |
993 | ||
994 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &req); | |
995 | if (r < 0) | |
996 | return r; | |
997 | ||
998 | return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_config); | |
999 | } | |
1000 | ||
1001 | static int manager_enumerate_nl80211_mlme(Manager *m) { | |
1002 | Link *link; | |
1003 | int r; | |
1004 | ||
1005 | assert(m); | |
1006 | assert(m->genl); | |
1007 | ||
1008 | HASHMAP_FOREACH(link, m->links_by_index) { | |
1009 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1010 | ||
1011 | if (link->wlan_iftype != NL80211_IFTYPE_STATION) | |
1012 | continue; | |
1013 | ||
1014 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &req); | |
1015 | if (r < 0) | |
1016 | return r; | |
1017 | ||
1018 | r = sd_netlink_message_append_u32(req, NL80211_ATTR_IFINDEX, link->ifindex); | |
1019 | if (r < 0) | |
1020 | return r; | |
1021 | ||
1022 | r = manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_mlme); | |
1023 | if (r < 0) | |
1024 | return r; | |
1025 | } | |
1026 | ||
1027 | return 0; | |
1028 | } | |
1029 | ||
446aaaf3 YW |
1030 | int manager_enumerate(Manager *m) { |
1031 | int r; | |
c16c7808 | 1032 | |
6119221a YW |
1033 | log_debug("Enumerating..."); |
1034 | ||
446aaaf3 YW |
1035 | r = manager_enumerate_links(m); |
1036 | if (r < 0) | |
1037 | return log_error_errno(r, "Could not enumerate links: %m"); | |
c16c7808 | 1038 | |
6698795e | 1039 | /* If the kernel is built without CONFIG_NET_SCHED, the below will fail with -EOPNOTSUPP. */ |
828a81a9 | 1040 | r = manager_enumerate_qdisc(m); |
15ac2a62 YW |
1041 | if (r == -EOPNOTSUPP) |
1042 | log_debug_errno(r, "Could not enumerate QDiscs, ignoring: %m"); | |
1043 | else if (r < 0) | |
828a81a9 YW |
1044 | return log_error_errno(r, "Could not enumerate QDisc: %m"); |
1045 | ||
6698795e | 1046 | /* If the kernel is built without CONFIG_NET_CLS, the below will fail with -EOPNOTSUPP. */ |
828a81a9 | 1047 | r = manager_enumerate_tclass(m); |
15ac2a62 YW |
1048 | if (r == -EOPNOTSUPP) |
1049 | log_debug_errno(r, "Could not enumerate TClasses, ignoring: %m"); | |
1050 | else if (r < 0) | |
828a81a9 YW |
1051 | return log_error_errno(r, "Could not enumerate TClass: %m"); |
1052 | ||
446aaaf3 YW |
1053 | r = manager_enumerate_addresses(m); |
1054 | if (r < 0) | |
1055 | return log_error_errno(r, "Could not enumerate addresses: %m"); | |
c16c7808 | 1056 | |
446aaaf3 YW |
1057 | r = manager_enumerate_neighbors(m); |
1058 | if (r < 0) | |
1059 | return log_error_errno(r, "Could not enumerate neighbors: %m"); | |
c16c7808 | 1060 | |
0c0585ca | 1061 | r = manager_enumerate_nexthop(m); |
034b69d8 | 1062 | if (r < 0) |
f12629ae | 1063 | return log_error_errno(r, "Could not enumerate nexthops: %m"); |
0c0585ca | 1064 | |
446aaaf3 YW |
1065 | r = manager_enumerate_routes(m); |
1066 | if (r < 0) | |
1067 | return log_error_errno(r, "Could not enumerate routes: %m"); | |
c16c7808 | 1068 | |
6698795e | 1069 | /* If the kernel is built without CONFIG_FIB_RULES, the below will fail with -EOPNOTSUPP. */ |
446aaaf3 | 1070 | r = manager_enumerate_rules(m); |
f12629ae YW |
1071 | if (r == -EOPNOTSUPP) |
1072 | log_debug_errno(r, "Could not enumerate routing policy rules, ignoring: %m"); | |
1073 | else if (r < 0) | |
446aaaf3 | 1074 | return log_error_errno(r, "Could not enumerate routing policy rules: %m"); |
c16c7808 | 1075 | |
4bfbf0fc | 1076 | /* If the kernel is built without CONFIG_WIRELESS, the below will fail with -EOPNOTSUPP. */ |
edb69db2 YW |
1077 | r = manager_enumerate_nl80211_wiphy(m); |
1078 | if (r == -EOPNOTSUPP) | |
1079 | log_debug_errno(r, "Could not enumerate wireless LAN phy, ignoring: %m"); | |
1080 | else if (r < 0) | |
1081 | return log_error_errno(r, "Could not enumerate wireless LAN phy: %m"); | |
1082 | ||
96f5f9ef YW |
1083 | r = manager_enumerate_nl80211_config(m); |
1084 | if (r == -EOPNOTSUPP) | |
1085 | log_debug_errno(r, "Could not enumerate wireless LAN interfaces, ignoring: %m"); | |
1086 | else if (r < 0) | |
1087 | return log_error_errno(r, "Could not enumerate wireless LAN interfaces: %m"); | |
1088 | ||
1089 | r = manager_enumerate_nl80211_mlme(m); | |
1090 | if (r == -EOPNOTSUPP) | |
1091 | log_debug_errno(r, "Could not enumerate wireless LAN stations, ignoring: %m"); | |
1092 | else if (r < 0) | |
1093 | return log_error_errno(r, "Could not enumerate wireless LAN stations: %m"); | |
1094 | ||
6119221a | 1095 | log_debug("Enumeration completed."); |
446aaaf3 | 1096 | return 0; |
c16c7808 SS |
1097 | } |
1098 | ||
59eb33e0 | 1099 | static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { |
59eb33e0 | 1100 | const sd_bus_error *e; |
f63e09ef | 1101 | int r; |
59eb33e0 MP |
1102 | |
1103 | assert(m); | |
59eb33e0 MP |
1104 | |
1105 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
1106 | if (e) { |
1107 | r = sd_bus_error_get_errno(e); | |
1108 | log_warning_errno(r, "Could not set hostname: %s", bus_error_message(e, r)); | |
1109 | } | |
59eb33e0 MP |
1110 | |
1111 | return 1; | |
1112 | } | |
1113 | ||
1114 | int manager_set_hostname(Manager *m, const char *hostname) { | |
1115 | int r; | |
1116 | ||
1117 | log_debug("Setting transient hostname: '%s'", strna(hostname)); | |
d7afd945 | 1118 | |
b3f9c17a YW |
1119 | r = free_and_strdup_warn(&m->dynamic_hostname, hostname); |
1120 | if (r < 0) | |
1121 | return r; | |
59eb33e0 | 1122 | |
5dbec9bd ZJS |
1123 | if (sd_bus_is_ready(m->bus) <= 0) { |
1124 | log_debug("Not connected to system bus, setting system hostname later."); | |
59eb33e0 MP |
1125 | return 0; |
1126 | } | |
1127 | ||
d2775306 | 1128 | r = bus_call_method_async( |
59eb33e0 MP |
1129 | m->bus, |
1130 | NULL, | |
d2775306 | 1131 | bus_hostname, |
59eb33e0 MP |
1132 | "SetHostname", |
1133 | set_hostname_handler, | |
1134 | m, | |
1135 | "sb", | |
1136 | hostname, | |
1137 | false); | |
59eb33e0 MP |
1138 | if (r < 0) |
1139 | return log_error_errno(r, "Could not set transient hostname: %m"); | |
1140 | ||
1141 | return 0; | |
1142 | } | |
1143 | ||
1144 | static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { | |
59eb33e0 | 1145 | const sd_bus_error *e; |
f63e09ef | 1146 | int r; |
59eb33e0 MP |
1147 | |
1148 | assert(m); | |
59eb33e0 MP |
1149 | |
1150 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
1151 | if (e) { |
1152 | r = sd_bus_error_get_errno(e); | |
1153 | log_warning_errno(r, "Could not set timezone: %s", bus_error_message(e, r)); | |
1154 | } | |
59eb33e0 MP |
1155 | |
1156 | return 1; | |
1157 | } | |
1158 | ||
1159 | int manager_set_timezone(Manager *m, const char *tz) { | |
1160 | int r; | |
1161 | ||
1162 | assert(m); | |
1163 | assert(tz); | |
1164 | ||
1165 | log_debug("Setting system timezone: '%s'", tz); | |
b3f9c17a YW |
1166 | r = free_and_strdup_warn(&m->dynamic_timezone, tz); |
1167 | if (r < 0) | |
1168 | return r; | |
59eb33e0 | 1169 | |
5dbec9bd ZJS |
1170 | if (sd_bus_is_ready(m->bus) <= 0) { |
1171 | log_debug("Not connected to system bus, setting system timezone later."); | |
59eb33e0 MP |
1172 | return 0; |
1173 | } | |
1174 | ||
b607fd3f | 1175 | r = bus_call_method_async( |
59eb33e0 MP |
1176 | m->bus, |
1177 | NULL, | |
b607fd3f | 1178 | bus_timedate, |
59eb33e0 MP |
1179 | "SetTimezone", |
1180 | set_timezone_handler, | |
1181 | m, | |
1182 | "sb", | |
1183 | tz, | |
1184 | false); | |
1185 | if (r < 0) | |
1186 | return log_error_errno(r, "Could not set timezone: %m"); | |
1187 | ||
1188 | return 0; | |
1189 | } | |
0e07cdb0 | 1190 | |
1e869a5d | 1191 | int manager_reload(Manager *m, sd_bus_message *message) { |
0e07cdb0 LP |
1192 | Link *link; |
1193 | int r; | |
1194 | ||
1195 | assert(m); | |
1196 | ||
6119221a | 1197 | log_debug("Reloading..."); |
b377a7cc | 1198 | (void) notify_reloading(); |
0e07cdb0 | 1199 | |
b3ae4e86 | 1200 | r = netdev_reload(m); |
6119221a YW |
1201 | if (r < 0) { |
1202 | log_debug_errno(r, "Failed to reload .netdev files: %m"); | |
0e07cdb0 | 1203 | goto finish; |
6119221a | 1204 | } |
0e07cdb0 LP |
1205 | |
1206 | r = network_reload(m); | |
6119221a YW |
1207 | if (r < 0) { |
1208 | log_debug_errno(r, "Failed to reload .network files: %m"); | |
0e07cdb0 | 1209 | goto finish; |
6119221a | 1210 | } |
0e07cdb0 | 1211 | |
2b07a321 YW |
1212 | HASHMAP_FOREACH(link, m->links_by_index) |
1213 | (void) link_reconfigure_full(link, /* flags = */ 0, message, | |
1214 | /* counter = */ message ? &m->reloading : NULL); | |
0e07cdb0 | 1215 | |
6119221a | 1216 | log_debug("Reloaded."); |
0e07cdb0 LP |
1217 | r = 0; |
1218 | finish: | |
792a8bfb | 1219 | (void) sd_notify(/* unset_environment= */ false, NOTIFY_READY_MESSAGE); |
0e07cdb0 LP |
1220 | return r; |
1221 | } |