network/dhcp-server: introduce PersistLeases= setting

Requested at https://github.com/systemd/systemd/pull/31772#issuecomment-2000053357.
This commit is contained in:
Yu Watanabe 2024-03-16 02:32:50 +09:00 committed by Luca Boccassi
parent f824cd660a
commit a3ed665a29
10 changed files with 71 additions and 5 deletions

View file

@ -283,6 +283,27 @@ DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00</programlisting>
</variablelist>
</refsect1>
<refsect1>
<title>[DHCPServer] Section Options</title>
<para>This section configures the default setting of the DHCP server. The following options are available
in the [DHCPServer] section:</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>PersistLeases=</varname></term>
<listitem>
<para>Specifies the default value for per-network <varname>PersistLeases=</varname>.
Takes a boolean. See for details in
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
Defaults to <literal>yes</literal>.</para>
<xi:include href="version-info.xml" xpointer="v256"/>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">

View file

@ -428,9 +428,12 @@
Defaults to <literal>no</literal>. Further settings for the DHCP server may be set in the
[DHCPServer] section described below.</para>
<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
<para>Even if this is enabled, the DHCP server will not be started automatically and wait for the
persistent storage being ready to load/save leases in the storage, unless
<varname>RelayTarget=</varname> or <varname>PersistLeases=no</varname> are specified in the
[DHCPServer] section. 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>
@ -3903,6 +3906,22 @@ ServerAddress=192.168.0.1/24</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PersistLeases=</varname></term>
<listitem>
<para>Takes a boolean. When true, the DHCP server will load and save leases in the persistent
storage. When false, the DHCP server will neither load nor save leases in the persistent storage.
Hence, bound leases will be lost when the interface is reconfigured e.g. by
<command>networkctl reconfigure</command>, or <filename>systemd-networkd.service</filename>
is restarted. That may cause address conflict on the network. So, please take an extra care when
disable this setting. When unspecified, the value specified in the same setting in
<citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
which defaults to <literal>yes</literal>, will be used.</para>
<xi:include href="version-info.xml" xpointer="v256"/>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View file

@ -147,6 +147,20 @@ 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;
@ -168,6 +182,9 @@ int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *addr
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. */
@ -208,7 +225,7 @@ int link_start_dhcp4_server(Link *link) {
/* 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)) {
if (dhcp_server_persist_leases(link)) {
if (link->manager->persistent_storage_fd < 0)
return 0; /* persistent storage is not ready. */
@ -239,7 +256,7 @@ void manager_toggle_dhcp4_server_state(Manager *manager, bool start) {
HASHMAP_FOREACH(link, manager->links_by_index) {
if (!link->dhcp_server)
continue;
if (sd_dhcp_server_is_in_relay_mode(link->dhcp_server))
if (!dhcp_server_persist_leases(link))
continue;
/* Even if 'start' is true, first we need to stop the server. Otherwise, we cannot (re)set

View file

@ -34,6 +34,7 @@ DHCPv4.DUIDType, config_parse_duid_type,
DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp_duid)
DHCPv6.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp6_duid)
DHCPv6.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp6_duid)
DHCPServer.PersistLeases, config_parse_bool, 0, offsetof(Manager, dhcp_server_persist_leases)
/* Deprecated */
DHCP.DUIDType, config_parse_manager_duid_type, 0, 0
DHCP.DUIDRawData, config_parse_manager_duid_rawdata, 0, 0

View file

@ -602,6 +602,7 @@ int manager_new(Manager **ret, bool test_mode) {
.dhcp_duid.type = DUID_TYPE_EN,
.dhcp6_duid.type = DUID_TYPE_EN,
.duid_product_uuid.type = DUID_TYPE_UUID,
.dhcp_server_persist_leases = true,
.ip_forwarding = { -1, -1, },
};

View file

@ -42,6 +42,7 @@ struct Manager {
bool manage_foreign_routes;
bool manage_foreign_rules;
bool manage_foreign_nexthops;
bool dhcp_server_persist_leases;
Set *dirty_links;
Set *new_wlan_ifindices;

View file

@ -350,6 +350,7 @@ DHCPServer.BootServerAddress, config_parse_in_addr_non_null,
DHCPServer.BootServerName, config_parse_dns_name, 0, offsetof(Network, dhcp_server_boot_server_name)
DHCPServer.BootFilename, config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, offsetof(Network, dhcp_server_boot_filename)
DHCPServer.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp_server_rapid_commit)
SHCPServer.PersistLeases, config_parse_tristate, 0, offsetof(Network, dhcp_server_persist_leases)
DHCPServerStaticLease.Address, config_parse_dhcp_static_lease_address, 0, 0
DHCPServerStaticLease.MACAddress, config_parse_dhcp_static_lease_hwaddr, 0, 0
Bridge.Cost, config_parse_uint32, 0, offsetof(Network, cost)

View file

@ -426,6 +426,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp_server_emit_router = true,
.dhcp_server_emit_timezone = true,
.dhcp_server_rapid_commit = true,
.dhcp_server_persist_leases = -1,
.router_lifetime_usec = RADV_DEFAULT_ROUTER_LIFETIME_USEC,
.router_dns_lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,

View file

@ -230,6 +230,7 @@ struct Network {
char *dhcp_server_boot_filename;
usec_t dhcp_server_ipv6_only_preferred_usec;
bool dhcp_server_rapid_commit;
int dhcp_server_persist_leases;
/* link-local addressing support */
AddressFamily link_local;

View file

@ -32,3 +32,6 @@
[DHCPv6]
#DUIDType=vendor
#DUIDRawData=
[DHCPServer]
#PersistLeases=yes