diff options
author | Luca Boccassi <bluca@debian.org> | 2024-03-18 12:08:21 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-18 12:08:21 +0100 |
commit | 48570c927368484f3866538c5525d487568416c4 (patch) | |
tree | b118b95445fd8b1da0dac8fc95d307cc500d3abd | |
parent | Add unittest file for basic:label (diff) | |
parent | network/dhcp-server: use the pinned fd of persistent storge (diff) | |
download | systemd-48570c927368484f3866538c5525d487568416c4.tar.xz systemd-48570c927368484f3866538c5525d487568416c4.zip |
Merge pull request #31811 from yuwata/network-pin-persistent-storage
network: pin file descriptor of persistent storage
-rw-r--r-- | docs/ENVIRONMENT.md | 7 | ||||
-rw-r--r-- | src/network/networkd-dhcp-server.c | 46 | ||||
-rw-r--r-- | src/network/networkd-manager-varlink.c | 45 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 36 | ||||
-rw-r--r-- | src/network/networkd-manager.h | 2 | ||||
-rwxr-xr-x | test/networkd-test.py | 2 |
6 files changed, 87 insertions, 51 deletions
diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index cd6d66a81f..e5768eb971 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -618,6 +618,13 @@ SYSTEMD_HOME_DEBUG_SUFFIX=foo \ `nftables`. Selects the firewall backend to use. If not specified tries to use `nftables` and falls back to `iptables` if that's not available. +`systemd-networkd`: + +* `$SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY` – takes a boolean. If true, + systemd-networkd tries to open the persistent storage on start. To make this + work, ProtectSystem=strict in systemd-networkd.service needs to be downgraded + or disabled. + `systemd-storagetm`: * `$SYSTEMD_NVME_MODEL`, `$SYSTEMD_NVME_FIRMWARE`, `$SYSTEMD_NVME_SERIAL`, diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index b7bae37a4d..a1869a8559 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -156,12 +156,25 @@ int link_start_dhcp4_server(Link *link) { if (!link_has_carrier(link)) return 0; + if (sd_dhcp_server_is_running(link->dhcp_server)) + return 0; /* already started. */ + /* TODO: Maybe, also check the system time is synced. If the system does not have RTC battery, then * the realtime clock in not usable in the early boot stage, and all saved leases may be wrongly * handled as expired and dropped. */ - if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server) && - !link->manager->persistent_storage_is_ready) - return 0; + if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server)) { + + if (link->manager->persistent_storage_fd < 0) + return 0; /* persistent storage is not ready. */ + + _cleanup_free_ char *lease_file = path_join("dhcp-server-lease", link->ifname); + if (!lease_file) + return -ENOMEM; + + r = sd_dhcp_server_set_lease_file(link->dhcp_server, link->manager->persistent_storage_fd, lease_file); + if (r < 0) + return r; + } r = sd_dhcp_server_start(link->dhcp_server); if (r < 0) @@ -183,13 +196,18 @@ void manager_toggle_dhcp4_server_state(Manager *manager, bool start) { if (sd_dhcp_server_is_in_relay_mode(link->dhcp_server)) continue; - if (start) - r = link_start_dhcp4_server(link); - else - r = sd_dhcp_server_stop(link->dhcp_server); + /* Even if 'start' is true, first we need to stop the server. Otherwise, we cannot (re)set + * the lease file in link_start_dhcp4_server(). */ + r = sd_dhcp_server_stop(link->dhcp_server); if (r < 0) - log_link_debug_errno(link, r, "Failed to %s DHCP server, ignoring: %m", - start ? "start" : "stop"); + log_link_debug_errno(link, r, "Failed to stop DHCP server, ignoring: %m"); + + if (!start) + continue; + + r = link_start_dhcp4_server(link); + if (r < 0) + log_link_debug_errno(link, r, "Failed to start DHCP server, ignoring: %m"); } } @@ -572,16 +590,6 @@ static int dhcp4_server_configure(Link *link) { return log_link_error_errno(link, r, "Failed to set DHCPv4 static lease for DHCP server: %m"); } - if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server)) { - _cleanup_free_ char *lease_file = path_join("/var/lib/systemd/network/dhcp-server-lease/", link->ifname); - if (!lease_file) - return log_oom(); - - r = sd_dhcp_server_set_lease_file(link->dhcp_server, AT_FDCWD, lease_file); - if (r < 0) - log_link_warning_errno(link, r, "Failed to load DHCPv4 server leases, ignoring: %m"); - } - r = link_start_dhcp4_server(link); if (r < 0) return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m"); diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index c86505b039..b1b60ac48f 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -3,7 +3,7 @@ #include <unistd.h> #include "bus-polkit.h" -#include "fs-util.h" +#include "fd-util.h" #include "lldp-rx-internal.h" #include "networkd-dhcp-server.h" #include "networkd-manager-varlink.h" @@ -185,13 +185,32 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet return r; if (ready) { - r = path_is_read_only_fs("/var/lib/systemd/network/"); + _cleanup_close_ int fd = -EBADF; + struct stat st, st_prev; + + fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH); + if (fd < 0) + return log_warning_errno(errno, "Failed to open /var/lib/systemd/network/: %m"); + + r = fd_is_read_only_fs(fd); if (r < 0) - return log_warning_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m"); + return log_warning_errno(r, "Failed to check if the persistent storage is writable: %m"); if (r > 0) { - log_warning("The directory /var/lib/systemd/network/ is read-only."); + log_warning("The persistent storage is on read-only filesystem."); return varlink_error(vlink, "io.systemd.Network.StorageReadOnly", NULL); } + + if (fstat(fd, &st) < 0) + return log_warning_errno(r, "Failed to stat the persistent storage: %m"); + + if (manager->persistent_storage_fd >= 0 && + fstat(manager->persistent_storage_fd, &st_prev) >= 0 && + stat_inode_same(&st, &st_prev)) + return varlink_reply(vlink, NULL); + + } else { + if (manager->persistent_storage_fd < 0) + return varlink_reply(vlink, NULL); } r = varlink_verify_polkit_async( @@ -203,16 +222,16 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet if (r <= 0) return r; - manager->persistent_storage_is_ready = ready; - if (ready) { - r = touch("/run/systemd/netif/persistent-storage-ready"); - if (r < 0) - log_debug_errno(r, "Failed to create /run/systemd/netif/persistent-storage-ready, ignoring: %m"); - } else { - if (unlink("/run/systemd/netif/persistent-storage-ready") < 0 && errno != ENOENT) - log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m"); - } + _cleanup_close_ int fd = -EBADF; + + fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH); + if (fd < 0) + return log_warning_errno(errno, "Failed to open /var/lib/systemd/network/: %m"); + + close_and_replace(manager->persistent_storage_fd, fd); + } else + manager->persistent_storage_fd = safe_close(manager->persistent_storage_fd); manager_toggle_dhcp4_server_state(manager, ready); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 2545521b99..5c50b3c98a 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -23,6 +23,7 @@ #include "device-private.h" #include "device-util.h" #include "dns-domain.h" +#include "env-util.h" #include "fd-util.h" #include "fileio.h" #include "firewall-util.h" @@ -557,27 +558,27 @@ int manager_setup(Manager *m) { return 0; } -static bool persistent_storage_is_ready(void) { +static int persistent_storage_open(void) { + _cleanup_close_ int fd = -EBADF; int r; - if (access("/run/systemd/netif/persistent-storage-ready", F_OK) < 0) { - if (errno != ENOENT) - log_debug_errno(errno, "Failed to check if /run/systemd/netif/persistent-storage-ready exists, assuming not: %m"); - return false; - } + r = getenv_bool("SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY"); + if (r < 0 && r != -ENXIO) + return log_debug_errno(r, "Failed to parse $SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY environment variable, ignoring: %m"); + if (r <= 0) + return -EBADF; - r = path_is_read_only_fs("/var/lib/systemd/network/"); - if (r == 0) - return true; - if (r < 0) - log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m"); - else - log_debug("The directory /var/lib/systemd/network/ is read-only."); + fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH); + if (fd < 0) + return log_debug_errno(errno, "Failed to open /var/lib/systemd/network/, ignoring: %m"); - if (unlink("/run/systemd/netif/persistent-storage-ready") < 0 && errno != ENOENT) - log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m"); + r = fd_is_read_only_fs(fd); + if (r < 0) + return log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m"); + if (r > 0) + return log_debug_errno(SYNTHETIC_ERRNO(EROFS), "The directory /var/lib/systemd/network/ is on read-only filesystem."); - return false; + return TAKE_FD(fd); } int manager_new(Manager **ret, bool test_mode) { @@ -591,13 +592,13 @@ int manager_new(Manager **ret, bool test_mode) { .keep_configuration = _KEEP_CONFIGURATION_INVALID, .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO, .test_mode = test_mode, - .persistent_storage_is_ready = persistent_storage_is_ready(), .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL, .online_state = _LINK_ONLINE_STATE_INVALID, .manage_foreign_routes = true, .manage_foreign_rules = true, .manage_foreign_nexthops = true, .ethtool_fd = -EBADF, + .persistent_storage_fd = persistent_storage_open(), .dhcp_duid.type = DUID_TYPE_EN, .dhcp6_duid.type = DUID_TYPE_EN, .duid_product_uuid.type = DUID_TYPE_UUID, @@ -672,6 +673,7 @@ Manager* manager_free(Manager *m) { free(m->dynamic_hostname); safe_close(m->ethtool_fd); + safe_close(m->persistent_storage_fd); m->fw_ctx = fw_ctx_free(m->fw_ctx); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 320b859bfd..fd9ab341c8 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -30,6 +30,7 @@ struct Manager { sd_device_monitor *device_monitor; Hashmap *polkit_registry; int ethtool_fd; + int persistent_storage_fd; KeepConfiguration keep_configuration; IPv6PrivacyExtensions ipv6_privacy_extensions; @@ -41,7 +42,6 @@ struct Manager { bool manage_foreign_routes; bool manage_foreign_rules; bool manage_foreign_nexthops; - bool persistent_storage_is_ready; Set *dirty_links; Set *new_wlan_ifindices; diff --git a/test/networkd-test.py b/test/networkd-test.py index ab30928c27..4ea76e1a94 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -921,7 +921,7 @@ EOF # For the networkd instance invoked below cannot support varlink connection. # Hence, 'networkctl persistent-storage yes' cannot be used. -touch /run/systemd/netif/persistent-storage-ready +export SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY=1 # run networkd as in systemd-networkd.service exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ {{ s/^.*=//; s/^[@+-]//; s/^!*//; p}}') |