summaryrefslogtreecommitdiffstats
path: root/src/network/networkd-dhcp-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/networkd-dhcp-server.c')
-rw-r--r--src/network/networkd-dhcp-server.c149
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;
}