network/dhcp-server: save leases in state directory

Then, we can read the lease file on restart, and the DHCP server will be
able to manage previously assigned addresses.

To save leases in the state directory /var/lib/systemd/network/, this
adds systemd-networkd-dhcp-server.service, and by default
systemd-networkd does not start the DHCP server without the heler
service started.

Closes #29991.
This commit is contained in:
Yu Watanabe 2024-03-01 12:10:49 +09:00
parent 35b2c1b0c8
commit 5582b36c38
4 changed files with 74 additions and 3 deletions

View file

@ -428,7 +428,13 @@
Defaults to <literal>no</literal>. Further settings for the DHCP server may be set in the
[DHCPServer] section described below.</para>
<xi:include href="version-info.xml" xpointer="v215"/>
<para>Even if this is enabled, the DHCP server will not be started automatically. It will be
started after <filename>systemd-networkd-persistent-storage.service</filename> is started, which
calls <command>networkctl persistent-storage yes</command>. See
<citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for more details.</para>
<xi:include href="version-info.xml" xpointer="v215"/>
</listitem>
</varlistentry>

View file

@ -20,6 +20,7 @@
#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"
@ -143,6 +144,55 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
return 0;
}
static 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;
/* 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;
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 (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);
if (r < 0)
log_link_debug_errno(link, r, "Failed to %s DHCP server, ignoring: %m",
start ? "start" : "stop");
}
}
static int dhcp_server_find_uplink(Link *link, Link **ret) {
assert(link);
@ -522,11 +572,20 @@ 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);
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, 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");
log_link_debug(link, "Offering DHCPv4 leases");
return 0;
}

View file

@ -5,12 +5,15 @@
#include "set.h"
typedef struct Link Link;
typedef struct Manager Manager;
typedef struct Network Network;
int network_adjust_dhcp_server(Network *network, Set **addresses);
int link_request_dhcp_server(Link *link);
void manager_toggle_dhcp4_server_state(Manager *manager, bool start);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_address);

View file

@ -5,6 +5,7 @@
#include "bus-polkit.h"
#include "fs-util.h"
#include "lldp-rx-internal.h"
#include "networkd-dhcp-server.h"
#include "networkd-manager-varlink.h"
#include "stat-util.h"
#include "varlink.h"
@ -211,6 +212,8 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet
log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m");
}
manager_toggle_dhcp4_server_state(manager, ready);
return varlink_reply(vlink, NULL);
}