]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
f579559b | 2 | |
9aa5d8ba | 3 | #include <netinet/in.h> |
091a364c | 4 | #include <sys/socket.h> |
9aa5d8ba | 5 | #include <unistd.h> |
bbf7c048 | 6 | #include <linux/if.h> |
bce67bbe | 7 | #include <linux/fib_rules.h> |
c16c7808 | 8 | #include <linux/nexthop.h> |
3bef724f | 9 | |
fc2f9534 | 10 | #include "sd-daemon.h" |
07630cea | 11 | #include "sd-netlink.h" |
fc2f9534 | 12 | |
b5efdb8a | 13 | #include "alloc-util.h" |
f63e09ef | 14 | #include "bus-error.h" |
ac9f55ed | 15 | #include "bus-log-control-api.h" |
269e4d2d | 16 | #include "bus-polkit.h" |
a97dcc12 | 17 | #include "bus-util.h" |
07630cea | 18 | #include "conf-parser.h" |
a97dcc12 | 19 | #include "def.h" |
a7f95575 | 20 | #include "device-private.h" |
21486d9e | 21 | #include "device-util.h" |
482d1aeb | 22 | #include "dns-domain.h" |
3ffd4af2 | 23 | #include "fd-util.h" |
0d39fa9c | 24 | #include "fileio.h" |
761cf19d | 25 | #include "firewall-util.h" |
af664001 | 26 | #include "fs-util.h" |
4f5f911e | 27 | #include "local-addresses.h" |
07630cea | 28 | #include "netlink-util.h" |
dc0d4078 | 29 | #include "network-internal.h" |
bfbf150e | 30 | #include "networkd-address-pool.h" |
cf72a786 | 31 | #include "networkd-dhcp-server-bus.h" |
ca5ad760 | 32 | #include "networkd-dhcp6.h" |
6a1af3d4 | 33 | #include "networkd-link-bus.h" |
79a59fa5 | 34 | #include "networkd-manager-bus.h" |
23f53b99 | 35 | #include "networkd-manager.h" |
1939ebeb | 36 | #include "networkd-neighbor.h" |
ceac2c2b | 37 | #include "networkd-network-bus.h" |
75156ccb | 38 | #include "networkd-nexthop.h" |
ca183bf8 | 39 | #include "networkd-routing-policy-rule.h" |
a879e1a4 | 40 | #include "networkd-speed-meter.h" |
00616955 | 41 | #include "ordered-set.h" |
b0c82192 | 42 | #include "path-lookup.h" |
07630cea | 43 | #include "path-util.h" |
92b555aa | 44 | #include "selinux-util.h" |
07630cea | 45 | #include "set.h" |
ab76be55 | 46 | #include "signal-util.h" |
d31f33e3 | 47 | #include "stat-util.h" |
21486d9e | 48 | #include "strv.h" |
4b600505 | 49 | #include "sysctl-util.h" |
e4de7287 | 50 | #include "tmpfile-util.h" |
299ad32d | 51 | #include "udev-util.h" |
505f8da7 | 52 | |
48d0248e YW |
53 | /* use 128 MB for receive socket kernel queue. */ |
54 | #define RCVBUF_SIZE (128*1024*1024) | |
be660c37 | 55 | |
9c0a72f9 TG |
56 | static int manager_reset_all(Manager *m) { |
57 | Link *link; | |
9c0a72f9 TG |
58 | int r; |
59 | ||
60 | assert(m); | |
61 | ||
90e74a66 | 62 | HASHMAP_FOREACH(link, m->links) { |
9c0a72f9 TG |
63 | r = link_carrier_reset(link); |
64 | if (r < 0) | |
2f3cf1f9 | 65 | log_link_warning_errno(link, r, "Could not reset carrier: %m"); |
9c0a72f9 TG |
66 | } |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
19070062 | 71 | static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { |
9c0a72f9 TG |
72 | Manager *m = userdata; |
73 | int b, r; | |
74 | ||
19070062 | 75 | assert(message); |
d7afd945 | 76 | assert(m); |
9c0a72f9 TG |
77 | |
78 | r = sd_bus_message_read(message, "b", &b); | |
79 | if (r < 0) { | |
d67b1d18 | 80 | bus_log_parse_error(r); |
9c0a72f9 TG |
81 | return 0; |
82 | } | |
83 | ||
84 | if (b) | |
85 | return 0; | |
86 | ||
87 | log_debug("Coming back from suspend, resetting all connections..."); | |
88 | ||
e1694a75 | 89 | (void) manager_reset_all(m); |
9c0a72f9 TG |
90 | |
91 | return 0; | |
92 | } | |
93 | ||
d7afd945 LP |
94 | static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { |
95 | Manager *m = userdata; | |
9c0a72f9 | 96 | |
d7afd945 | 97 | assert(message); |
9c0a72f9 TG |
98 | assert(m); |
99 | ||
d7afd945 LP |
100 | /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */ |
101 | if (m->dynamic_hostname) | |
102 | (void) manager_set_hostname(m, m->dynamic_hostname); | |
103 | if (m->dynamic_timezone) | |
104 | (void) manager_set_timezone(m, m->dynamic_timezone); | |
27dfc982 YW |
105 | if (m->links_requesting_uuid) |
106 | (void) manager_request_product_uuid(m, NULL); | |
9c0a72f9 | 107 | |
d7afd945 LP |
108 | return 0; |
109 | } | |
9c0a72f9 | 110 | |
d7afd945 LP |
111 | int manager_connect_bus(Manager *m) { |
112 | int r; | |
113 | ||
114 | assert(m); | |
9c0a72f9 | 115 | |
d7afd945 | 116 | if (m->bus) |
9c0a72f9 | 117 | return 0; |
7d6884b6 | 118 | |
621e4509 | 119 | r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network"); |
9c0a72f9 | 120 | if (r < 0) |
d7afd945 | 121 | return log_error_errno(r, "Failed to connect to bus: %m"); |
9c0a72f9 | 122 | |
e331e246 TG |
123 | r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m); |
124 | if (r < 0) | |
125 | return log_error_errno(r, "Failed to add manager object vtable: %m"); | |
126 | ||
127 | r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.Link", link_vtable, link_object_find, m); | |
128 | if (r < 0) | |
129 | return log_error_errno(r, "Failed to add link object vtable: %m"); | |
130 | ||
cf72a786 MAL |
131 | r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.DHCPServer", dhcp_server_vtable, link_object_find, m); |
132 | if (r < 0) | |
133 | return log_error_errno(r, "Failed to add link object vtable: %m"); | |
134 | ||
e331e246 TG |
135 | r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/link", link_node_enumerator, m); |
136 | if (r < 0) | |
137 | return log_error_errno(r, "Failed to add link enumerator: %m"); | |
3175fcde TG |
138 | |
139 | r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/network", "org.freedesktop.network1.Network", network_vtable, network_object_find, m); | |
140 | if (r < 0) | |
141 | return log_error_errno(r, "Failed to add network object vtable: %m"); | |
142 | ||
143 | r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/network", network_node_enumerator, m); | |
144 | if (r < 0) | |
145 | return log_error_errno(r, "Failed to add network enumerator: %m"); | |
e331e246 | 146 | |
ac9f55ed LP |
147 | r = bus_log_control_api_register(m->bus); |
148 | if (r < 0) | |
149 | return r; | |
150 | ||
696fc836 | 151 | r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL); |
e331e246 | 152 | if (r < 0) |
0c0b9306 | 153 | return log_error_errno(r, "Failed to request name: %m"); |
e331e246 TG |
154 | |
155 | r = sd_bus_attach_event(m->bus, m->event, 0); | |
156 | if (r < 0) | |
157 | return log_error_errno(r, "Failed to attach bus to event loop: %m"); | |
158 | ||
d7afd945 LP |
159 | r = sd_bus_match_signal_async( |
160 | m->bus, | |
cad43595 | 161 | NULL, |
d7afd945 LP |
162 | "org.freedesktop.DBus.Local", |
163 | NULL, | |
164 | "org.freedesktop.DBus.Local", | |
165 | "Connected", | |
166 | on_connected, NULL, m); | |
167 | if (r < 0) | |
168 | return log_error_errno(r, "Failed to request match on Connected signal: %m"); | |
169 | ||
170 | r = sd_bus_match_signal_async( | |
171 | m->bus, | |
cad43595 | 172 | NULL, |
d7afd945 LP |
173 | "org.freedesktop.login1", |
174 | "/org/freedesktop/login1", | |
175 | "org.freedesktop.login1.Manager", | |
176 | "PrepareForSleep", | |
177 | match_prepare_for_sleep, NULL, m); | |
178 | if (r < 0) | |
179 | log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m"); | |
7901cea1 | 180 | |
9c0a72f9 TG |
181 | return 0; |
182 | } | |
183 | ||
d2ebf952 YW |
184 | static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) { |
185 | Manager *m = userdata; | |
a7f95575 | 186 | DeviceAction action; |
5fae368b TG |
187 | Link *link = NULL; |
188 | int r, ifindex; | |
5544ee85 | 189 | |
5fae368b TG |
190 | assert(m); |
191 | assert(device); | |
5544ee85 | 192 | |
a7f95575 | 193 | r = device_get_action(device, &action); |
21486d9e | 194 | if (r < 0) { |
a7f95575 | 195 | log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m"); |
5fae368b | 196 | return 0; |
21486d9e YW |
197 | } |
198 | ||
cd17bb6e LP |
199 | /* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents |
200 | * are "positive" events in some form, i.e. inform us about a changed or new network interface, that | |
201 | * still exists — and we are interested in that. */ | |
202 | if (action == DEVICE_ACTION_REMOVE) | |
21486d9e | 203 | return 0; |
5544ee85 | 204 | |
51517f9e | 205 | r = sd_device_get_ifindex(device, &ifindex); |
7606377e | 206 | if (r < 0) { |
cd17bb6e LP |
207 | log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m", |
208 | device_action_to_string(action)); | |
5fae368b | 209 | return 0; |
5544ee85 TG |
210 | } |
211 | ||
299ad32d YW |
212 | r = device_is_renaming(device); |
213 | if (r < 0) { | |
a7f95575 YW |
214 | log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m", |
215 | device_action_to_string(action)); | |
299ad32d YW |
216 | return 0; |
217 | } | |
218 | if (r > 0) { | |
1cdea1a2 | 219 | log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed."); |
299ad32d YW |
220 | return 0; |
221 | } | |
222 | ||
5fae368b | 223 | r = link_get(m, ifindex, &link); |
d2ebf952 YW |
224 | if (r < 0) { |
225 | if (r != -ENODEV) | |
226 | log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex); | |
5fae368b | 227 | return 0; |
d2ebf952 | 228 | } |
02b59d57 | 229 | |
d2ebf952 | 230 | (void) link_initialized(link, device); |
e1694a75 | 231 | |
f579559b TG |
232 | return 0; |
233 | } | |
234 | ||
5fae368b TG |
235 | static int manager_connect_udev(Manager *m) { |
236 | int r; | |
f579559b | 237 | |
d31f33e3 YW |
238 | /* udev does not initialize devices inside containers, so we rely on them being already |
239 | * initialized before entering the container. */ | |
240 | if (path_is_read_only_fs("/sys") > 0) | |
5fae368b | 241 | return 0; |
f579559b | 242 | |
d2ebf952 | 243 | r = sd_device_monitor_new(&m->device_monitor); |
02b59d57 | 244 | if (r < 0) |
d2ebf952 | 245 | return log_error_errno(r, "Failed to initialize device monitor: %m"); |
02b59d57 | 246 | |
a725efb0 YW |
247 | r = sd_device_monitor_set_receive_buffer_size(m->device_monitor, RCVBUF_SIZE); |
248 | if (r < 0) | |
249 | log_warning_errno(r, "Failed to increase buffer size for device monitor, ignoring: %m"); | |
250 | ||
d2ebf952 YW |
251 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL); |
252 | if (r < 0) | |
253 | return log_error_errno(r, "Could not add device monitor filter: %m"); | |
505f8da7 | 254 | |
deb2b734 | 255 | r = sd_device_monitor_attach_event(m->device_monitor, m->event); |
5fae368b | 256 | if (r < 0) |
d2ebf952 | 257 | return log_error_errno(r, "Failed to attach event to device monitor: %m"); |
505f8da7 | 258 | |
deb2b734 | 259 | r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m); |
505f8da7 | 260 | if (r < 0) |
d2ebf952 | 261 | return log_error_errno(r, "Failed to start device monitor: %m"); |
11a7f229 | 262 | |
505f8da7 TG |
263 | return 0; |
264 | } | |
f579559b | 265 | |
8dfed23d | 266 | static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { |
505f8da7 | 267 | Link *link = NULL; |
4d473d5d | 268 | NetDev *netdev = NULL; |
f2236469 | 269 | uint16_t type; |
ca4e095a | 270 | const char *name; |
505f8da7 | 271 | int r, ifindex; |
f579559b | 272 | |
505f8da7 TG |
273 | assert(rtnl); |
274 | assert(message); | |
f579559b TG |
275 | assert(m); |
276 | ||
1c4baffc TG |
277 | if (sd_netlink_message_is_error(message)) { |
278 | r = sd_netlink_message_get_errno(message); | |
45af44d4 | 279 | if (r < 0) |
5ecb131d | 280 | log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring"); |
45af44d4 TG |
281 | |
282 | return 0; | |
283 | } | |
284 | ||
1c4baffc | 285 | r = sd_netlink_message_get_type(message, &type); |
f2236469 | 286 | if (r < 0) { |
e1694a75 | 287 | log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m"); |
f2236469 | 288 | return 0; |
25a1bffc | 289 | } else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) { |
7f474ed7 | 290 | log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type); |
cdfee943 | 291 | return 0; |
f2236469 TG |
292 | } |
293 | ||
505f8da7 | 294 | r = sd_rtnl_message_link_get_ifindex(message, &ifindex); |
45af44d4 | 295 | if (r < 0) { |
7f474ed7 | 296 | log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m"); |
45af44d4 TG |
297 | return 0; |
298 | } else if (ifindex <= 0) { | |
7f474ed7 | 299 | log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex); |
505f8da7 | 300 | return 0; |
a0db8e46 | 301 | } |
f579559b | 302 | |
1c4baffc | 303 | r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name); |
45af44d4 | 304 | if (r < 0) { |
e1694a75 | 305 | log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m"); |
4d473d5d | 306 | return 0; |
a0db8e46 ZJS |
307 | } |
308 | ||
309 | (void) link_get(m, ifindex, &link); | |
310 | (void) netdev_get(m, name, &netdev); | |
4d473d5d TG |
311 | |
312 | switch (type) { | |
313 | case RTM_NEWLINK: | |
314 | if (!link) { | |
315 | /* link is new, so add it */ | |
316 | r = link_add(m, message, &link); | |
317 | if (r < 0) { | |
7f474ed7 | 318 | log_warning_errno(r, "Could not process new link message, ignoring: %m"); |
4d473d5d TG |
319 | return 0; |
320 | } | |
321 | } | |
322 | ||
323 | if (netdev) { | |
324 | /* netdev exists, so make sure the ifindex matches */ | |
505f8da7 TG |
325 | r = netdev_set_ifindex(netdev, message); |
326 | if (r < 0) { | |
7f474ed7 | 327 | log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m"); |
505f8da7 TG |
328 | return 0; |
329 | } | |
330 | } | |
e1202047 | 331 | |
f2236469 | 332 | r = link_update(link, message); |
e1694a75 | 333 | if (r < 0) { |
7f474ed7 | 334 | log_warning_errno(r, "Could not process link message, ignoring: %m"); |
f2236469 | 335 | return 0; |
e1694a75 | 336 | } |
4d473d5d TG |
337 | |
338 | break; | |
339 | ||
340 | case RTM_DELLINK: | |
341 | link_drop(link); | |
342 | netdev_drop(netdev); | |
343 | ||
344 | break; | |
345 | ||
346 | default: | |
7f474ed7 | 347 | assert_not_reached("Received link message with invalid RTNL message type."); |
f2236469 | 348 | } |
505f8da7 TG |
349 | |
350 | return 1; | |
351 | } | |
352 | ||
5fae368b TG |
353 | static int systemd_netlink_fd(void) { |
354 | int n, fd, rtnl_fd = -EINVAL; | |
355 | ||
356 | n = sd_listen_fds(true); | |
357 | if (n <= 0) | |
358 | return -EINVAL; | |
359 | ||
360 | for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { | |
361 | if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { | |
362 | if (rtnl_fd >= 0) | |
363 | return -EINVAL; | |
364 | ||
365 | rtnl_fd = fd; | |
366 | } | |
367 | } | |
368 | ||
369 | return rtnl_fd; | |
370 | } | |
371 | ||
05d0c2e3 JT |
372 | static int manager_connect_genl(Manager *m) { |
373 | int r; | |
374 | ||
375 | assert(m); | |
376 | ||
377 | r = sd_genl_socket_open(&m->genl); | |
378 | if (r < 0) | |
379 | return r; | |
380 | ||
381 | r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE); | |
382 | if (r < 0) | |
8c63924c | 383 | log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m"); |
05d0c2e3 JT |
384 | |
385 | r = sd_netlink_attach_event(m->genl, m->event, 0); | |
386 | if (r < 0) | |
387 | return r; | |
388 | ||
389 | return 0; | |
390 | } | |
391 | ||
5fae368b TG |
392 | static int manager_connect_rtnl(Manager *m) { |
393 | int fd, r; | |
505f8da7 TG |
394 | |
395 | assert(m); | |
505f8da7 | 396 | |
5fae368b TG |
397 | fd = systemd_netlink_fd(); |
398 | if (fd < 0) | |
1c4baffc | 399 | r = sd_netlink_open(&m->rtnl); |
5fae368b | 400 | else |
1c4baffc | 401 | r = sd_netlink_open_fd(&m->rtnl, fd); |
505f8da7 TG |
402 | if (r < 0) |
403 | return r; | |
404 | ||
e13af7bd YW |
405 | /* Bump receiver buffer, but only if we are not called via socket activation, as in that |
406 | * case systemd sets the receive buffer size for us, and the value in the .socket unit | |
407 | * should take full effect. */ | |
408 | if (fd < 0) { | |
409 | r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE); | |
410 | if (r < 0) | |
411 | log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m"); | |
412 | } | |
f579559b | 413 | |
1c4baffc | 414 | r = sd_netlink_attach_event(m->rtnl, m->event, 0); |
505f8da7 TG |
415 | if (r < 0) |
416 | return r; | |
f579559b | 417 | |
8dfed23d | 418 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
419 | if (r < 0) |
420 | return r; | |
505f8da7 | 421 | |
8dfed23d | 422 | r = netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
423 | if (r < 0) |
424 | return r; | |
45af44d4 | 425 | |
8dfed23d | 426 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
427 | if (r < 0) |
428 | return r; | |
429 | ||
8dfed23d | 430 | r = netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
431 | if (r < 0) |
432 | return r; | |
433 | ||
8dfed23d | 434 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
435 | if (r < 0) |
436 | return r; | |
437 | ||
8dfed23d | 438 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
439 | if (r < 0) |
440 | return r; | |
441 | ||
8dfed23d | 442 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
443 | if (r < 0) |
444 | return r; | |
445 | ||
8dfed23d | 446 | r = netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
447 | if (r < 0) |
448 | return r; | |
449 | ||
8dfed23d | 450 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
451 | if (r < 0) |
452 | return r; | |
453 | ||
8dfed23d | 454 | r = netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
455 | if (r < 0) |
456 | return r; | |
457 | ||
8dfed23d | 458 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
459 | if (r < 0) |
460 | return r; | |
461 | ||
8dfed23d | 462 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
463 | if (r < 0) |
464 | return r; | |
465 | ||
5fae368b | 466 | return 0; |
45af44d4 | 467 | } |
505f8da7 | 468 | |
87d64897 | 469 | static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) { |
e77bd3fd | 470 | const char *p; |
84de38c5 TG |
471 | int r; |
472 | ||
473 | assert(s); | |
e77bd3fd | 474 | assert(dns); |
5512a963 | 475 | |
87d64897 YW |
476 | if (dns->ifindex != 0 && dns->ifindex != ifindex) |
477 | return 0; | |
478 | ||
e77bd3fd YW |
479 | p = in_addr_full_to_string(dns); |
480 | if (!p) | |
481 | return 0; | |
5512a963 | 482 | |
e77bd3fd | 483 | r = ordered_set_put_strdup(s, p); |
5512a963 LP |
484 | if (r == -EEXIST) |
485 | return 0; | |
486 | ||
487 | return r; | |
488 | } | |
489 | ||
87d64897 | 490 | static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) { |
5512a963 | 491 | int r, c = 0; |
5512a963 LP |
492 | |
493 | assert(s); | |
e77bd3fd | 494 | assert(dns || n == 0); |
5512a963 | 495 | |
995606ad | 496 | for (unsigned i = 0; i < n; i++) { |
87d64897 | 497 | r = ordered_set_put_dns_server(s, ifindex, dns[i]); |
5512a963 LP |
498 | if (r < 0) |
499 | return r; | |
500 | ||
501 | c += r; | |
502 | } | |
503 | ||
504 | return c; | |
505 | } | |
506 | ||
507 | static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) { | |
508 | char *p; | |
509 | int r; | |
510 | ||
511 | assert(s); | |
512 | assert(address); | |
84de38c5 TG |
513 | |
514 | r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p); | |
515 | if (r < 0) | |
516 | return r; | |
517 | ||
00616955 | 518 | r = ordered_set_consume(s, p); |
84de38c5 TG |
519 | if (r == -EEXIST) |
520 | return 0; | |
521 | ||
522 | return r; | |
523 | } | |
524 | ||
072320ea TH |
525 | static int ordered_set_put_in4_addrv(OrderedSet *s, |
526 | const struct in_addr *addresses, | |
527 | size_t n, | |
528 | bool (*predicate)(const struct in_addr *addr)) { | |
5512a963 | 529 | int r, c = 0; |
84de38c5 TG |
530 | |
531 | assert(s); | |
5512a963 | 532 | assert(n == 0 || addresses); |
84de38c5 | 533 | |
995606ad | 534 | for (size_t i = 0; i < n; i++) { |
072320ea TH |
535 | if (predicate && !predicate(&addresses[i])) |
536 | continue; | |
5512a963 | 537 | r = ordered_set_put_in4_addr(s, addresses+i); |
84de38c5 TG |
538 | if (r < 0) |
539 | return r; | |
540 | ||
541 | c += r; | |
542 | } | |
543 | ||
544 | return c; | |
545 | } | |
546 | ||
84de38c5 | 547 | static int manager_save(Manager *m) { |
2a71d57f | 548 | _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL; |
299d578f | 549 | const char *operstate_str, *carrier_state_str, *address_state_str; |
84de38c5 | 550 | LinkOperationalState operstate = LINK_OPERSTATE_OFF; |
7f3c07ad YW |
551 | LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF; |
552 | LinkAddressState address_state = LINK_ADDRESS_STATE_OFF; | |
299d578f SS |
553 | _cleanup_free_ char *temp_path = NULL; |
554 | _cleanup_strv_free_ char **p = NULL; | |
555 | _cleanup_fclose_ FILE *f = NULL; | |
556 | Link *link; | |
84de38c5 TG |
557 | int r; |
558 | ||
559 | assert(m); | |
560 | assert(m->state_file); | |
561 | ||
562 | /* We add all NTP and DNS server to a set, to filter out duplicates */ | |
00616955 | 563 | dns = ordered_set_new(&string_hash_ops); |
84de38c5 TG |
564 | if (!dns) |
565 | return -ENOMEM; | |
566 | ||
00616955 | 567 | ntp = ordered_set_new(&string_hash_ops); |
84de38c5 TG |
568 | if (!ntp) |
569 | return -ENOMEM; | |
570 | ||
284e8fd0 SS |
571 | sip = ordered_set_new(&string_hash_ops); |
572 | if (!sip) | |
299d578f SS |
573 | return -ENOMEM; |
574 | ||
482d1aeb | 575 | search_domains = ordered_set_new(&dns_name_hash_ops); |
3df9bec5 LP |
576 | if (!search_domains) |
577 | return -ENOMEM; | |
578 | ||
482d1aeb | 579 | route_domains = ordered_set_new(&dns_name_hash_ops); |
3df9bec5 | 580 | if (!route_domains) |
84de38c5 TG |
581 | return -ENOMEM; |
582 | ||
90e74a66 | 583 | HASHMAP_FOREACH(link, m->links) { |
2a71d57f LP |
584 | const struct in_addr *addresses; |
585 | ||
84de38c5 TG |
586 | if (link->flags & IFF_LOOPBACK) |
587 | continue; | |
588 | ||
589 | if (link->operstate > operstate) | |
590 | operstate = link->operstate; | |
591 | ||
7f3c07ad YW |
592 | if (link->carrier_state > carrier_state) |
593 | carrier_state = link->carrier_state; | |
594 | ||
595 | if (link->address_state > address_state) | |
596 | address_state = link->address_state; | |
597 | ||
84de38c5 TG |
598 | if (!link->network) |
599 | continue; | |
600 | ||
601 | /* First add the static configured entries */ | |
87d64897 YW |
602 | if (link->n_dns != (unsigned) -1) |
603 | r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns); | |
604 | else | |
605 | r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns); | |
84de38c5 TG |
606 | if (r < 0) |
607 | return r; | |
608 | ||
15761549 | 609 | r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp); |
84de38c5 TG |
610 | if (r < 0) |
611 | return r; | |
612 | ||
15761549 | 613 | r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains); |
3df9bec5 LP |
614 | if (r < 0) |
615 | return r; | |
616 | ||
15761549 | 617 | r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains); |
84de38c5 TG |
618 | if (r < 0) |
619 | return r; | |
620 | ||
621 | if (!link->dhcp_lease) | |
622 | continue; | |
623 | ||
624 | /* Secondly, add the entries acquired via DHCP */ | |
27cb34f5 | 625 | if (link->network->dhcp_use_dns) { |
84de38c5 TG |
626 | r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); |
627 | if (r > 0) { | |
072320ea | 628 | r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local); |
84de38c5 TG |
629 | if (r < 0) |
630 | return r; | |
631 | } else if (r < 0 && r != -ENODATA) | |
632 | return r; | |
633 | } | |
634 | ||
27cb34f5 | 635 | if (link->network->dhcp_use_ntp) { |
84de38c5 TG |
636 | r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); |
637 | if (r > 0) { | |
072320ea | 638 | r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local); |
84de38c5 TG |
639 | if (r < 0) |
640 | return r; | |
641 | } else if (r < 0 && r != -ENODATA) | |
642 | return r; | |
643 | } | |
644 | ||
299d578f | 645 | if (link->network->dhcp_use_sip) { |
299d578f SS |
646 | r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses); |
647 | if (r > 0) { | |
648 | r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local); | |
649 | if (r < 0) | |
650 | return r; | |
651 | } else if (r < 0 && r != -ENODATA) | |
652 | return r; | |
653 | } | |
654 | ||
b2a81c0b | 655 | if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { |
84de38c5 | 656 | const char *domainname; |
b85bc551 | 657 | char **domains = NULL; |
84de38c5 | 658 | |
b85bc551 | 659 | OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains; |
84de38c5 TG |
660 | r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); |
661 | if (r >= 0) { | |
b85bc551 DW |
662 | r = ordered_set_put_strdup(target_domains, domainname); |
663 | if (r < 0) | |
664 | return r; | |
665 | } else if (r != -ENODATA) | |
666 | return r; | |
b2a81c0b | 667 | |
b85bc551 DW |
668 | r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains); |
669 | if (r >= 0) { | |
670 | r = ordered_set_put_strdupv(target_domains, domains); | |
84de38c5 TG |
671 | if (r < 0) |
672 | return r; | |
673 | } else if (r != -ENODATA) | |
674 | return r; | |
675 | } | |
676 | } | |
677 | ||
7f3c07ad YW |
678 | if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED) |
679 | carrier_state = LINK_CARRIER_STATE_CARRIER; | |
680 | ||
84de38c5 TG |
681 | operstate_str = link_operstate_to_string(operstate); |
682 | assert(operstate_str); | |
683 | ||
ac999bf0 YW |
684 | carrier_state_str = link_carrier_state_to_string(carrier_state); |
685 | assert(carrier_state_str); | |
686 | ||
687 | address_state_str = link_address_state_to_string(address_state); | |
688 | assert(address_state_str); | |
689 | ||
84de38c5 TG |
690 | r = fopen_temporary(m->state_file, &f, &temp_path); |
691 | if (r < 0) | |
692 | return r; | |
693 | ||
5512a963 | 694 | (void) fchmod(fileno(f), 0644); |
84de38c5 TG |
695 | |
696 | fprintf(f, | |
697 | "# This is private data. Do not parse.\n" | |
ac999bf0 YW |
698 | "OPER_STATE=%s\n" |
699 | "CARRIER_STATE=%s\n" | |
700 | "ADDRESS_STATE=%s\n", | |
701 | operstate_str, carrier_state_str, address_state_str); | |
84de38c5 | 702 | |
53ae3f64 ZJS |
703 | ordered_set_print(f, "DNS=", dns); |
704 | ordered_set_print(f, "NTP=", ntp); | |
299d578f | 705 | ordered_set_print(f, "SIP=", sip); |
53ae3f64 ZJS |
706 | ordered_set_print(f, "DOMAINS=", search_domains); |
707 | ordered_set_print(f, "ROUTE_DOMAINS=", route_domains); | |
84de38c5 TG |
708 | |
709 | r = fflush_and_check(f); | |
710 | if (r < 0) | |
711 | goto fail; | |
712 | ||
af664001 YW |
713 | r = conservative_rename(temp_path, m->state_file); |
714 | if (r < 0) | |
84de38c5 | 715 | goto fail; |
84de38c5 TG |
716 | |
717 | if (m->operational_state != operstate) { | |
718 | m->operational_state = operstate; | |
7f3c07ad YW |
719 | if (strv_extend(&p, "OperationalState") < 0) |
720 | log_oom(); | |
721 | } | |
722 | ||
723 | if (m->carrier_state != carrier_state) { | |
724 | m->carrier_state = carrier_state; | |
725 | if (strv_extend(&p, "CarrierState") < 0) | |
726 | log_oom(); | |
727 | } | |
728 | ||
729 | if (m->address_state != address_state) { | |
730 | m->address_state = address_state; | |
731 | if (strv_extend(&p, "AddressState") < 0) | |
732 | log_oom(); | |
733 | } | |
734 | ||
735 | if (p) { | |
736 | r = manager_send_changed_strv(m, p); | |
84de38c5 | 737 | if (r < 0) |
7f3c07ad | 738 | log_error_errno(r, "Could not emit changed properties: %m"); |
84de38c5 TG |
739 | } |
740 | ||
741 | m->dirty = false; | |
742 | ||
743 | return 0; | |
744 | ||
745 | fail: | |
746 | (void) unlink(m->state_file); | |
747 | (void) unlink(temp_path); | |
748 | ||
749 | return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file); | |
750 | } | |
751 | ||
752 | static int manager_dirty_handler(sd_event_source *s, void *userdata) { | |
753 | Manager *m = userdata; | |
754 | Link *link; | |
84de38c5 TG |
755 | |
756 | assert(m); | |
757 | ||
758 | if (m->dirty) | |
759 | manager_save(m); | |
760 | ||
90e74a66 | 761 | SET_FOREACH(link, m->dirty_links) |
c2a65950 | 762 | (void) link_save_and_clean(link); |
84de38c5 TG |
763 | |
764 | return 1; | |
765 | } | |
766 | ||
ab76be55 ZJS |
767 | static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
768 | Manager *m = userdata; | |
769 | ||
770 | assert(m); | |
771 | m->restarting = false; | |
772 | ||
773 | log_debug("Terminate operation initiated."); | |
774 | ||
775 | return sd_event_exit(sd_event_source_get_event(s), 0); | |
776 | } | |
777 | ||
778 | static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { | |
779 | Manager *m = userdata; | |
780 | ||
781 | assert(m); | |
782 | m->restarting = true; | |
783 | ||
784 | log_debug("Restart operation initiated."); | |
785 | ||
786 | return sd_event_exit(sd_event_source_get_event(s), 0); | |
787 | } | |
788 | ||
3534a043 | 789 | int manager_new(Manager **ret) { |
8e766630 | 790 | _cleanup_(manager_freep) Manager *m = NULL; |
45af44d4 | 791 | int r; |
f579559b | 792 | |
a879e1a4 | 793 | m = new(Manager, 1); |
5fae368b TG |
794 | if (!m) |
795 | return -ENOMEM; | |
45af44d4 | 796 | |
a879e1a4 YW |
797 | *m = (Manager) { |
798 | .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL, | |
5d3b8017 | 799 | .manage_foreign_routes = true, |
c643bda5 | 800 | .ethtool_fd = -1, |
a879e1a4 YW |
801 | }; |
802 | ||
5fae368b TG |
803 | m->state_file = strdup("/run/systemd/netif/state"); |
804 | if (!m->state_file) | |
805 | return -ENOMEM; | |
806 | ||
3534a043 YW |
807 | r = sd_event_default(&m->event); |
808 | if (r < 0) | |
809 | return r; | |
810 | ||
ab76be55 ZJS |
811 | assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0); |
812 | ||
05e21627 | 813 | (void) sd_event_set_watchdog(m->event, true); |
ab76be55 ZJS |
814 | (void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m); |
815 | (void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m); | |
816 | (void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m); | |
5fae368b | 817 | |
84de38c5 TG |
818 | r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m); |
819 | if (r < 0) | |
820 | return r; | |
821 | ||
5fae368b | 822 | r = manager_connect_rtnl(m); |
45af44d4 TG |
823 | if (r < 0) |
824 | return r; | |
825 | ||
05d0c2e3 JT |
826 | r = manager_connect_genl(m); |
827 | if (r < 0) | |
828 | return r; | |
829 | ||
5fae368b TG |
830 | r = manager_connect_udev(m); |
831 | if (r < 0) | |
832 | return r; | |
45af44d4 | 833 | |
05d0c2e3 JT |
834 | r = sd_resolve_default(&m->resolve); |
835 | if (r < 0) | |
836 | return r; | |
837 | ||
838 | r = sd_resolve_attach_event(m->resolve, m->event, 0); | |
839 | if (r < 0) | |
840 | return r; | |
841 | ||
ed76f585 | 842 | r = address_pool_setup_default(m); |
5fae368b TG |
843 | if (r < 0) |
844 | return r; | |
f579559b | 845 | |
8341a5c3 | 846 | m->duid.type = DUID_TYPE_EN; |
413708d1 | 847 | |
1cc6c93a | 848 | *ret = TAKE_PTR(m); |
f579559b | 849 | |
f579559b TG |
850 | return 0; |
851 | } | |
852 | ||
5fae368b | 853 | void manager_free(Manager *m) { |
5fae368b | 854 | Link *link; |
f579559b | 855 | |
5fae368b TG |
856 | if (!m) |
857 | return; | |
505f8da7 | 858 | |
5fae368b | 859 | free(m->state_file); |
505f8da7 | 860 | |
90e74a66 | 861 | HASHMAP_FOREACH(link, m->links) |
2a99eed0 | 862 | (void) link_stop_engines(link, true); |
946f8e14 | 863 | |
1633c457 YW |
864 | m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free); |
865 | m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free); | |
f579559b | 866 | |
c4397d94 | 867 | m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref); |
5f707e12 YW |
868 | m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref); |
869 | m->links = hashmap_free_with_destructor(m->links, link_unref); | |
27dfc982 | 870 | |
5f707e12 | 871 | m->duids_requesting_uuid = set_free(m->duids_requesting_uuid); |
715d398e | 872 | m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref); |
dbffab87 | 873 | |
c4397d94 | 874 | m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref); |
5fae368b | 875 | |
bfbf150e | 876 | ordered_set_free_free(m->address_pools); |
5fae368b | 877 | |
552b90a2 YW |
878 | hashmap_free(m->route_table_names_by_number); |
879 | hashmap_free(m->route_table_numbers_by_name); | |
c038ce46 | 880 | |
f19ee681 YW |
881 | /* routing_policy_rule_free() access m->rules and m->rules_foreign. |
882 | * So, it is necessary to set NULL after the sets are freed. */ | |
8eec0b9d YW |
883 | m->rules = set_free(m->rules); |
884 | m->rules_foreign = set_free(m->rules_foreign); | |
bce67bbe | 885 | |
d4df6326 SS |
886 | sd_netlink_unref(m->rtnl); |
887 | sd_netlink_unref(m->genl); | |
888 | sd_resolve_unref(m->resolve); | |
889 | ||
450fa34b YW |
890 | /* reject (e.g. unreachable) type routes are managed by Manager, but may be referenced by a |
891 | * link. E.g., DHCP6 with prefix delegation creates unreachable routes, and they are referenced | |
892 | * by the upstream link. And the links may be referenced by netlink slots. Hence, two | |
893 | * set_free() must be called after the above sd_netlink_unref(). */ | |
894 | m->routes = set_free(m->routes); | |
895 | m->routes_foreign = set_free(m->routes_foreign); | |
896 | ||
a879e1a4 | 897 | sd_event_source_unref(m->speed_meter_event_source); |
2f5b4a77 | 898 | sd_event_unref(m->event); |
5fae368b | 899 | |
d2ebf952 | 900 | sd_device_monitor_unref(m->device_monitor); |
7d20d375 | 901 | |
15761549 | 902 | bus_verify_polkit_async_registry_free(m->polkit_registry); |
92e31da1 | 903 | sd_bus_flush_close_unref(m->bus); |
7d20d375 | 904 | |
7901cea1 MP |
905 | free(m->dynamic_timezone); |
906 | free(m->dynamic_hostname); | |
907 | ||
c643bda5 YW |
908 | safe_close(m->ethtool_fd); |
909 | ||
761cf19d FW |
910 | m->fw_ctx = fw_ctx_free(m->fw_ctx); |
911 | ||
5fae368b TG |
912 | free(m); |
913 | } | |
914 | ||
b76d99d9 | 915 | int manager_start(Manager *m) { |
84de38c5 | 916 | Link *link; |
a879e1a4 | 917 | int r; |
84de38c5 | 918 | |
a97dcc12 TG |
919 | assert(m); |
920 | ||
a879e1a4 YW |
921 | r = manager_start_speed_meter(m); |
922 | if (r < 0) | |
923 | return log_error_errno(r, "Failed to initialize speed meter: %m"); | |
924 | ||
84de38c5 TG |
925 | /* The dirty handler will deal with future serialization, but the first one |
926 | must be done explicitly. */ | |
927 | ||
928 | manager_save(m); | |
929 | ||
90e74a66 | 930 | HASHMAP_FOREACH(link, m->links) |
c2a65950 | 931 | (void) link_save(link); |
84de38c5 | 932 | |
b76d99d9 | 933 | return 0; |
a97dcc12 TG |
934 | } |
935 | ||
5fae368b TG |
936 | int manager_load_config(Manager *m) { |
937 | int r; | |
938 | ||
939 | /* update timestamp */ | |
dc0d4078 | 940 | paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, true); |
5fae368b | 941 | |
e272b621 | 942 | r = netdev_load(m, false); |
f579559b TG |
943 | if (r < 0) |
944 | return r; | |
945 | ||
7f06b3e1 | 946 | r = network_load(m, &m->networks); |
9021bb9f TG |
947 | if (r < 0) |
948 | return r; | |
949 | ||
f579559b TG |
950 | return 0; |
951 | } | |
f882c247 | 952 | |
5fae368b | 953 | bool manager_should_reload(Manager *m) { |
dc0d4078 | 954 | return paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, false); |
5fae368b TG |
955 | } |
956 | ||
446aaaf3 YW |
957 | static int manager_enumerate_internal( |
958 | Manager *m, | |
959 | sd_netlink_message *req, | |
960 | int (*process)(sd_netlink *, sd_netlink_message *, Manager *), | |
961 | const char *name) { | |
962 | ||
963 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL; | |
f882c247 TG |
964 | int r; |
965 | ||
5da8149f | 966 | assert(m); |
5fae368b | 967 | assert(m->rtnl); |
446aaaf3 YW |
968 | assert(req); |
969 | assert(process); | |
f882c247 | 970 | |
1c4baffc | 971 | r = sd_netlink_message_request_dump(req, true); |
dd3efc09 TG |
972 | if (r < 0) |
973 | return r; | |
974 | ||
1c4baffc | 975 | r = sd_netlink_call(m->rtnl, req, 0, &reply); |
446aaaf3 | 976 | if (r < 0) { |
92b555aa | 977 | if (name && (r == -EOPNOTSUPP || (r == -EINVAL && mac_selinux_enforcing()))) { |
446aaaf3 YW |
978 | log_debug_errno(r, "%s are not supported by the kernel. Ignoring.", name); |
979 | return 0; | |
980 | } | |
981 | ||
f2236469 | 982 | return r; |
446aaaf3 | 983 | } |
f2236469 | 984 | |
446aaaf3 | 985 | for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) { |
5fae368b | 986 | int k; |
2e9f08ea | 987 | |
6a24f148 TG |
988 | m->enumerating = true; |
989 | ||
446aaaf3 YW |
990 | k = process(m->rtnl, reply_one, m); |
991 | if (k < 0 && r >= 0) | |
5fae368b | 992 | r = k; |
6a24f148 TG |
993 | |
994 | m->enumerating = false; | |
5fae368b | 995 | } |
2e9f08ea | 996 | |
5fae368b | 997 | return r; |
f882c247 | 998 | } |
3bef724f | 999 | |
446aaaf3 YW |
1000 | static int manager_enumerate_links(Manager *m) { |
1001 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1346b1f0 TG |
1002 | int r; |
1003 | ||
5fae368b TG |
1004 | assert(m); |
1005 | assert(m->rtnl); | |
bcbca829 | 1006 | |
446aaaf3 | 1007 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); |
5fae368b TG |
1008 | if (r < 0) |
1009 | return r; | |
1010 | ||
446aaaf3 YW |
1011 | return manager_enumerate_internal(m, req, manager_rtnl_process_link, NULL); |
1012 | } | |
5fae368b | 1013 | |
446aaaf3 YW |
1014 | static int manager_enumerate_addresses(Manager *m) { |
1015 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1016 | int r; | |
6a24f148 | 1017 | |
446aaaf3 YW |
1018 | assert(m); |
1019 | assert(m->rtnl); | |
6a24f148 | 1020 | |
446aaaf3 YW |
1021 | r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0); |
1022 | if (r < 0) | |
1023 | return r; | |
5fae368b | 1024 | |
446aaaf3 | 1025 | return manager_enumerate_internal(m, req, manager_rtnl_process_address, NULL); |
1346b1f0 | 1026 | } |
d1bdafd2 | 1027 | |
446aaaf3 YW |
1028 | static int manager_enumerate_neighbors(Manager *m) { |
1029 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
d1bdafd2 WKI |
1030 | int r; |
1031 | ||
1032 | assert(m); | |
1033 | assert(m->rtnl); | |
1034 | ||
1035 | r = sd_rtnl_message_new_neigh(m->rtnl, &req, RTM_GETNEIGH, 0, AF_UNSPEC); | |
1036 | if (r < 0) | |
1037 | return r; | |
1038 | ||
446aaaf3 | 1039 | return manager_enumerate_internal(m, req, manager_rtnl_process_neighbor, NULL); |
d1bdafd2 | 1040 | } |
1346b1f0 | 1041 | |
446aaaf3 YW |
1042 | static int manager_enumerate_routes(Manager *m) { |
1043 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1c8e710c TG |
1044 | int r; |
1045 | ||
1046 | assert(m); | |
1047 | assert(m->rtnl); | |
1048 | ||
5ff1ef31 YW |
1049 | if (!m->manage_foreign_routes) |
1050 | return 0; | |
1051 | ||
1c8e710c TG |
1052 | r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0); |
1053 | if (r < 0) | |
1054 | return r; | |
1055 | ||
446aaaf3 | 1056 | return manager_enumerate_internal(m, req, manager_rtnl_process_route, NULL); |
1c8e710c TG |
1057 | } |
1058 | ||
446aaaf3 YW |
1059 | static int manager_enumerate_rules(Manager *m) { |
1060 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
bce67bbe SS |
1061 | int r; |
1062 | ||
1063 | assert(m); | |
1064 | assert(m->rtnl); | |
1065 | ||
1066 | r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0); | |
1067 | if (r < 0) | |
1068 | return r; | |
1069 | ||
446aaaf3 | 1070 | return manager_enumerate_internal(m, req, manager_rtnl_process_rule, "Routing policy rules"); |
bce67bbe SS |
1071 | } |
1072 | ||
446aaaf3 YW |
1073 | static int manager_enumerate_nexthop(Manager *m) { |
1074 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
c16c7808 SS |
1075 | int r; |
1076 | ||
1077 | assert(m); | |
1078 | assert(m->rtnl); | |
1079 | ||
1080 | r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0); | |
1081 | if (r < 0) | |
1082 | return r; | |
1083 | ||
446aaaf3 YW |
1084 | return manager_enumerate_internal(m, req, manager_rtnl_process_nexthop, "Nexthop rules"); |
1085 | } | |
c16c7808 | 1086 | |
446aaaf3 YW |
1087 | int manager_enumerate(Manager *m) { |
1088 | int r; | |
c16c7808 | 1089 | |
446aaaf3 YW |
1090 | r = manager_enumerate_links(m); |
1091 | if (r < 0) | |
1092 | return log_error_errno(r, "Could not enumerate links: %m"); | |
c16c7808 | 1093 | |
446aaaf3 YW |
1094 | r = manager_enumerate_addresses(m); |
1095 | if (r < 0) | |
1096 | return log_error_errno(r, "Could not enumerate addresses: %m"); | |
c16c7808 | 1097 | |
446aaaf3 YW |
1098 | r = manager_enumerate_neighbors(m); |
1099 | if (r < 0) | |
1100 | return log_error_errno(r, "Could not enumerate neighbors: %m"); | |
c16c7808 | 1101 | |
446aaaf3 YW |
1102 | r = manager_enumerate_routes(m); |
1103 | if (r < 0) | |
1104 | return log_error_errno(r, "Could not enumerate routes: %m"); | |
c16c7808 | 1105 | |
446aaaf3 YW |
1106 | r = manager_enumerate_rules(m); |
1107 | if (r < 0) | |
1108 | return log_error_errno(r, "Could not enumerate routing policy rules: %m"); | |
c16c7808 | 1109 | |
446aaaf3 YW |
1110 | r = manager_enumerate_nexthop(m); |
1111 | if (r < 0) | |
1112 | return log_error_errno(r, "Could not enumerate nexthop rules: %m"); | |
1113 | ||
1114 | return 0; | |
c16c7808 SS |
1115 | } |
1116 | ||
4f5f911e LP |
1117 | Link* manager_find_uplink(Manager *m, Link *exclude) { |
1118 | _cleanup_free_ struct local_address *gateways = NULL; | |
995606ad | 1119 | int n; |
4f5f911e LP |
1120 | |
1121 | assert(m); | |
1122 | ||
1123 | /* Looks for a suitable "uplink", via black magic: an | |
1124 | * interface that is up and where the default route with the | |
1125 | * highest priority points to. */ | |
1126 | ||
1127 | n = local_gateways(m->rtnl, 0, AF_UNSPEC, &gateways); | |
1128 | if (n < 0) { | |
1129 | log_warning_errno(n, "Failed to determine list of default gateways: %m"); | |
1130 | return NULL; | |
1131 | } | |
1132 | ||
995606ad | 1133 | for (int i = 0; i < n; i++) { |
4f5f911e LP |
1134 | Link *link; |
1135 | ||
1136 | link = hashmap_get(m->links, INT_TO_PTR(gateways[i].ifindex)); | |
1137 | if (!link) { | |
c2c940bd | 1138 | log_debug("Weird, found a gateway for a link we don't know. Ignoring."); |
4f5f911e LP |
1139 | continue; |
1140 | } | |
1141 | ||
1142 | if (link == exclude) | |
1143 | continue; | |
1144 | ||
1145 | if (link->operstate < LINK_OPERSTATE_ROUTABLE) | |
1146 | continue; | |
1147 | ||
1148 | return link; | |
1149 | } | |
1150 | ||
1151 | return NULL; | |
1152 | } | |
84de38c5 TG |
1153 | |
1154 | void manager_dirty(Manager *manager) { | |
1155 | assert(manager); | |
1156 | ||
1157 | /* the serialized state in /run is no longer up-to-date */ | |
1158 | manager->dirty = true; | |
1159 | } | |
59eb33e0 MP |
1160 | |
1161 | static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { | |
59eb33e0 | 1162 | const sd_bus_error *e; |
f63e09ef | 1163 | int r; |
59eb33e0 MP |
1164 | |
1165 | assert(m); | |
59eb33e0 MP |
1166 | |
1167 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
1168 | if (e) { |
1169 | r = sd_bus_error_get_errno(e); | |
1170 | log_warning_errno(r, "Could not set hostname: %s", bus_error_message(e, r)); | |
1171 | } | |
59eb33e0 MP |
1172 | |
1173 | return 1; | |
1174 | } | |
1175 | ||
1176 | int manager_set_hostname(Manager *m, const char *hostname) { | |
1177 | int r; | |
1178 | ||
1179 | log_debug("Setting transient hostname: '%s'", strna(hostname)); | |
d7afd945 | 1180 | |
b3f9c17a YW |
1181 | r = free_and_strdup_warn(&m->dynamic_hostname, hostname); |
1182 | if (r < 0) | |
1183 | return r; | |
59eb33e0 | 1184 | |
d7afd945 | 1185 | if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { |
e0d95f03 | 1186 | log_debug("Not connected to system bus, setting hostname later."); |
59eb33e0 MP |
1187 | return 0; |
1188 | } | |
1189 | ||
1190 | r = sd_bus_call_method_async( | |
1191 | m->bus, | |
1192 | NULL, | |
1193 | "org.freedesktop.hostname1", | |
1194 | "/org/freedesktop/hostname1", | |
1195 | "org.freedesktop.hostname1", | |
1196 | "SetHostname", | |
1197 | set_hostname_handler, | |
1198 | m, | |
1199 | "sb", | |
1200 | hostname, | |
1201 | false); | |
1202 | ||
1203 | if (r < 0) | |
1204 | return log_error_errno(r, "Could not set transient hostname: %m"); | |
1205 | ||
1206 | return 0; | |
1207 | } | |
1208 | ||
1209 | static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { | |
59eb33e0 | 1210 | const sd_bus_error *e; |
f63e09ef | 1211 | int r; |
59eb33e0 MP |
1212 | |
1213 | assert(m); | |
59eb33e0 MP |
1214 | |
1215 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
1216 | if (e) { |
1217 | r = sd_bus_error_get_errno(e); | |
1218 | log_warning_errno(r, "Could not set timezone: %s", bus_error_message(e, r)); | |
1219 | } | |
59eb33e0 MP |
1220 | |
1221 | return 1; | |
1222 | } | |
1223 | ||
1224 | int manager_set_timezone(Manager *m, const char *tz) { | |
1225 | int r; | |
1226 | ||
1227 | assert(m); | |
1228 | assert(tz); | |
1229 | ||
1230 | log_debug("Setting system timezone: '%s'", tz); | |
b3f9c17a YW |
1231 | r = free_and_strdup_warn(&m->dynamic_timezone, tz); |
1232 | if (r < 0) | |
1233 | return r; | |
59eb33e0 | 1234 | |
d7afd945 | 1235 | if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { |
e0d95f03 | 1236 | log_debug("Not connected to system bus, setting timezone later."); |
59eb33e0 MP |
1237 | return 0; |
1238 | } | |
1239 | ||
1240 | r = sd_bus_call_method_async( | |
1241 | m->bus, | |
1242 | NULL, | |
1243 | "org.freedesktop.timedate1", | |
1244 | "/org/freedesktop/timedate1", | |
1245 | "org.freedesktop.timedate1", | |
1246 | "SetTimezone", | |
1247 | set_timezone_handler, | |
1248 | m, | |
1249 | "sb", | |
1250 | tz, | |
1251 | false); | |
1252 | if (r < 0) | |
1253 | return log_error_errno(r, "Could not set timezone: %m"); | |
1254 | ||
1255 | return 0; | |
1256 | } |