diff options
Diffstat (limited to 'src/network/networkd-dhcp-server.c')
-rw-r--r-- | src/network/networkd-dhcp-server.c | 149 |
1 files changed, 143 insertions, 6 deletions
diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index 607fe00..c35102a 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -7,6 +7,7 @@ #include "sd-dhcp-server.h" #include "dhcp-protocol.h" +#include "dhcp-server-lease-internal.h" #include "fd-util.h" #include "fileio.h" #include "network-common.h" @@ -17,9 +18,11 @@ #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-network.h" +#include "networkd-ntp.h" #include "networkd-queue.h" #include "networkd-route-util.h" #include "parse-util.h" +#include "path-util.h" #include "socket-netlink.h" #include "string-table.h" #include "string-util.h" @@ -81,6 +84,7 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) { /* TODO: check if the prefix length is small enough for the pool. */ network->dhcp_server_address = address; + address->used_by_dhcp_server = true; break; } if (!network->dhcp_server_address) { @@ -92,7 +96,7 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) { } } else { - _cleanup_(address_freep) Address *a = NULL; + _cleanup_(address_unrefp) Address *a = NULL; Address *existing; unsigned line; @@ -127,6 +131,7 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) { a->prefixlen = network->dhcp_server_address_prefixlen; a->in_addr.in = network->dhcp_server_address_in_addr; a->requested_as_null = !in4_addr_is_set(&network->dhcp_server_address_in_addr); + a->used_by_dhcp_server = true; r = address_section_verify(a); if (r < 0) @@ -143,6 +148,139 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) { return 0; } +static bool dhcp_server_persist_leases(Link *link) { + assert(link); + assert(link->manager); + assert(link->network); + + if (in4_addr_is_set(&link->network->dhcp_server_relay_target)) + return false; /* On relay mode. Nothing saved in the persistent storage. */ + + if (link->network->dhcp_server_persist_leases >= 0) + return link->network->dhcp_server_persist_leases; + + return link->manager->dhcp_server_persist_leases; +} + +int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret) { + struct in_addr a; + uint8_t prefixlen; + int r; + + assert(link); + assert(link->manager); + assert(address); + assert(ret); + + /* If the DHCP server address is configured as a null address, reuse the server address of the + * previous instance. */ + if (address->family != AF_INET) + return -ENOENT; + + if (!address->used_by_dhcp_server) + return -ENOENT; + + if (!link_dhcp4_server_enabled(link)) + return -ENOENT; + + if (!dhcp_server_persist_leases(link)) + return -ENOENT; + + if (link->manager->persistent_storage_fd < 0) + return -EBUSY; /* The persistent storage is not ready, try later again. */ + + _cleanup_free_ char *lease_file = path_join("dhcp-server-lease", link->ifname); + if (!lease_file) + return -ENOMEM; + + r = dhcp_server_leases_file_get_server_address( + link->manager->persistent_storage_fd, + lease_file, + &a, + &prefixlen); + if (r == -ENOENT) + return r; + if (r < 0) + return log_warning_errno(r, "Failed to load lease file %s: %s", + lease_file, + r == -ENXIO ? "expected JSON content not found" : + r == -EINVAL ? "invalid JSON" : + STRERROR(r)); + + if (prefixlen != address->prefixlen) + return -ENOENT; + + ret->in = a; + return 0; +} + +int link_start_dhcp4_server(Link *link) { + int r; + + assert(link); + assert(link->manager); + + if (!link->dhcp_server) + return 0; /* Not configured yet. */ + + 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 (dhcp_server_persist_leases(link)) { + + 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) + return r; + + log_link_debug(link, "Offering DHCPv4 leases"); + return 0; +} + +void manager_toggle_dhcp4_server_state(Manager *manager, bool start) { + Link *link; + int r; + + assert(manager); + + HASHMAP_FOREACH(link, manager->links_by_index) { + if (!link->dhcp_server) + continue; + if (!dhcp_server_persist_leases(link)) + continue; + + /* 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 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"); + } +} + static int dhcp_server_find_uplink(Link *link, Link **ret) { assert(link); @@ -205,7 +343,7 @@ static int link_push_uplink_to_dhcp_server( addresses[n_addresses++] = ia; } - use_dhcp_lease_data = link->network->dhcp_use_dns; + use_dhcp_lease_data = link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP4); break; case SD_DHCP_LEASE_NTP: { @@ -228,7 +366,7 @@ static int link_push_uplink_to_dhcp_server( addresses[n_addresses++] = ia.in; } - use_dhcp_lease_data = link->network->dhcp_use_ntp; + use_dhcp_lease_data = link_get_use_ntp(link, NETWORK_CONFIG_SOURCE_DHCP4); break; } @@ -423,7 +561,7 @@ static int dhcp4_server_configure(Link *link) { return log_link_warning_errno(link, r, "Failed to %s Rapid Commit support for DHCPv4 server instance: %m", enable_disable(link->network->dhcp_server_rapid_commit)); - for (sd_dhcp_lease_server_type_t type = 0; type < _SD_DHCP_LEASE_SERVER_TYPE_MAX; type ++) { + for (sd_dhcp_lease_server_type_t type = 0; type < _SD_DHCP_LEASE_SERVER_TYPE_MAX; type++) { if (!link->network->dhcp_server_emit[type].emit) continue; @@ -522,11 +660,10 @@ static int dhcp4_server_configure(Link *link) { return log_link_error_errno(link, r, "Failed to set DHCPv4 static lease for DHCP server: %m"); } - r = sd_dhcp_server_start(link->dhcp_server); + r = link_start_dhcp4_server(link); if (r < 0) return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m"); - log_link_debug(link, "Offering DHCPv4 leases"); return 0; } |