1
0
mirror of https://github.com/systemd/systemd synced 2025-10-05 16:03:15 +02:00

network/dhcp-server: improvements for saving/loading leases (#37835)

This commit is contained in:
Lennart Poettering
2025-06-17 14:31:22 +02:00
committed by GitHub
20 changed files with 159 additions and 54 deletions

4
NEWS
View File

@@ -398,6 +398,10 @@ CHANGES WITH 258 in spe:
networkd.conf. (Previously this had to be configured individually in networkd.conf. (Previously this had to be configured individually in
each .network file.) each .network file.)
* PersistLeases= setting in [DHCPServer] section now also accepts
"runtime", to make the DHCP server saves and loads bound leases on
the runtime storage.
* A new Preference= setting has been added to the [IPv6RoutePrefix] * A new Preference= setting has been added to the [IPv6RoutePrefix]
section to configure the route preference field. section to configure the route preference field.

View File

@@ -404,7 +404,7 @@ DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00</programlisting>
<term><varname>PersistLeases=</varname></term> <term><varname>PersistLeases=</varname></term>
<listitem> <listitem>
<para>Specifies the default value for per-network <varname>PersistLeases=</varname>. <para>Specifies the default value for per-network <varname>PersistLeases=</varname>.
Takes a boolean. See for details in Takes a boolean or special value <literal>runtime</literal>. See for details in
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>. <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
Defaults to <literal>yes</literal>.</para> Defaults to <literal>yes</literal>.</para>

View File

@@ -443,7 +443,7 @@
<para>Even if this is enabled, the DHCP server will not be started automatically and wait for the <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 persistent storage being ready to load/save leases in the storage, unless
<varname>RelayTarget=</varname> or <varname>PersistLeases=no</varname> are specified in the <varname>RelayTarget=</varname> or <varname>PersistLeases=no/runtime</varname> are specified in the
[DHCPServer] section. It will be started after [DHCPServer] section. It will be started after
<filename>systemd-networkd-persistent-storage.service</filename> is started, which calls <filename>systemd-networkd-persistent-storage.service</filename> is started, which calls
<command>networkctl persistent-storage yes</command>. See <command>networkctl persistent-storage yes</command>. See
@@ -4140,16 +4140,24 @@ ServerAddress=192.168.0.1/24</programlisting>
<varlistentry> <varlistentry>
<term><varname>PersistLeases=</varname></term> <term><varname>PersistLeases=</varname></term>
<listitem> <listitem>
<para>Takes a boolean. When true, the DHCP server will load and save leases in the persistent <para>Takes a boolean or special value <literal>runtime</literal>. When <literal>yes</literal>, the
storage. When false, the DHCP server will neither load nor save leases in the persistent storage. DHCP server will load and save leases in the persistent storage. When <literal>runtime</literal>,
Hence, bound leases will be lost when the interface is reconfigured e.g. by the DHCP server will load and save leases in the runtime storage, hence bound leases will be lost
when the runtime storage is cleared by e.g. by calling
<command>systemctl clean systemd-networkd.service</command> or the system is rebooted. When
<literal>no</literal>, 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 <command>networkctl reconfigure</command>, or
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
is restarted. That may cause address conflict on the network. So, please take an extra care when is restarted. Using <literal>runtime</literal> and <literal>no</literal> may cause address conflict
disable this setting. When unspecified, the value specified in the same setting in on the network after the leases are lost. 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>, <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
which defaults to <literal>yes</literal>, will be used.</para> which defaults to <literal>yes</literal>, will be used.</para>
<para>When <varname>RelayTarget=</varname> is specified, this setting will be ignored and no leases
will be saved, as there will be no bound lease on the server.</para>
<xi:include href="version-info.xml" xpointer="v256"/> <xi:include href="version-info.xml" xpointer="v256"/>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@@ -29,4 +29,4 @@ IPv6AcceptRA=no
IPv6SendRA=yes IPv6SendRA=yes
[DHCPServer] [DHCPServer]
PersistLeases=no PersistLeases=runtime

View File

@@ -28,4 +28,4 @@ IPv6AcceptRA=no
IPv6SendRA=yes IPv6SendRA=yes
[DHCPServer] [DHCPServer]
PersistLeases=no PersistLeases=runtime

View File

@@ -29,4 +29,4 @@ IPv6AcceptRA=no
IPv6SendRA=yes IPv6SendRA=yes
[DHCPServer] [DHCPServer]
PersistLeases=no PersistLeases=runtime

View File

@@ -29,4 +29,4 @@ IPv6AcceptRA=no
IPv6SendRA=yes IPv6SendRA=yes
[DHCPServer] [DHCPServer]
PersistLeases=no PersistLeases=runtime

View File

@@ -28,4 +28,4 @@ IPv6AcceptRA=no
IPv6SendRA=yes IPv6SendRA=yes
[DHCPServer] [DHCPServer]
PersistLeases=no PersistLeases=runtime

View File

@@ -1605,9 +1605,13 @@ int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, int dir_fd, const char
if (!path_is_safe(path)) if (!path_is_safe(path))
return -EINVAL; return -EINVAL;
_cleanup_close_ int fd = fd_reopen(dir_fd, O_CLOEXEC | O_DIRECTORY | O_PATH); _cleanup_close_ int fd = AT_FDCWD; /* Unlike our usual coding style, AT_FDCWD needs to be set,
if (fd < 0) * to pass a 'valid' fd. */
return fd; if (dir_fd >= 0) {
fd = fd_reopen(dir_fd, O_CLOEXEC | O_DIRECTORY | O_PATH);
if (fd < 0)
return fd;
}
r = free_and_strdup(&server->lease_file, path); r = free_and_strdup(&server->lease_file, path);
if (r < 0) if (r < 0)

View File

@@ -27,6 +27,7 @@
#include "path-util.h" #include "path-util.h"
#include "set.h" #include "set.h"
#include "socket-netlink.h" #include "socket-netlink.h"
#include "string-table.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
@@ -150,13 +151,13 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
return 0; return 0;
} }
static bool dhcp_server_persist_leases(Link *link) { static DHCPServerPersistLeases link_get_dhcp_server_persist_leases(Link *link) {
assert(link); assert(link);
assert(link->manager); assert(link->manager);
assert(link->network); assert(link->network);
if (in4_addr_is_set(&link->network->dhcp_server_relay_target)) if (in4_addr_is_set(&link->network->dhcp_server_relay_target))
return false; /* On relay mode. Nothing saved in the persistent storage. */ return DHCP_SERVER_PERSIST_LEASES_NO; /* On relay mode. Nothing saved in the persistent storage. */
if (link->network->dhcp_server_persist_leases >= 0) if (link->network->dhcp_server_persist_leases >= 0)
return link->network->dhcp_server_persist_leases; return link->network->dhcp_server_persist_leases;
@@ -164,9 +165,47 @@ static bool dhcp_server_persist_leases(Link *link) {
return link->manager->dhcp_server_persist_leases; return link->manager->dhcp_server_persist_leases;
} }
static int link_get_dhcp_server_lease_file(Link *link, int *ret_dir_fd, char **ret_path) {
assert(link);
assert(link->ifname);
assert(ret_dir_fd);
assert(ret_path);
/* This does not copy fd. Do not close fd stored in ret_dir_fd. */
switch (link_get_dhcp_server_persist_leases(link)) {
case DHCP_SERVER_PERSIST_LEASES_NO:
*ret_dir_fd = -EBADF;
*ret_path = NULL;
return 0;
case DHCP_SERVER_PERSIST_LEASES_YES: {
if (link->manager->persistent_storage_fd < 0)
return -EBUSY; /* persistent storage is not ready. */
char *p = path_join("dhcp-server-lease", link->ifname);
if (!p)
return -ENOMEM;
*ret_dir_fd = link->manager->persistent_storage_fd;
*ret_path = p;
return 1;
}
case DHCP_SERVER_PERSIST_LEASES_RUNTIME: {
char *p = path_join("/run/systemd/netif/dhcp-server-lease", link->ifname);
if (!p)
return -ENOMEM;
*ret_dir_fd = AT_FDCWD;
*ret_path = p;
return 1;
}
default:
assert_not_reached();
}
}
int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret) { 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; int r;
assert(link); assert(link);
@@ -185,18 +224,18 @@ int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *addr
if (!link_dhcp4_server_enabled(link)) if (!link_dhcp4_server_enabled(link))
return -ENOENT; return -ENOENT;
if (!dhcp_server_persist_leases(link)) _cleanup_free_ char *lease_file = NULL;
int dir_fd;
r = link_get_dhcp_server_lease_file(link, &dir_fd, &lease_file);
if (r < 0)
return r;
if (r == 0) /* persistent leases is disabled */
return -ENOENT; return -ENOENT;
if (link->manager->persistent_storage_fd < 0) struct in_addr a;
return -EBUSY; /* The persistent storage is not ready, try later again. */ uint8_t prefixlen;
_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( r = dhcp_server_leases_file_get_server_address(
link->manager->persistent_storage_fd, dir_fd,
lease_file, lease_file,
&a, &a,
&prefixlen); &prefixlen);
@@ -234,16 +273,15 @@ 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 /* 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 * the realtime clock in not usable in the early boot stage, and all saved leases may be wrongly
* handled as expired and dropped. */ * handled as expired and dropped. */
if (dhcp_server_persist_leases(link)) { _cleanup_free_ char *lease_file = NULL;
int dir_fd;
if (link->manager->persistent_storage_fd < 0) r = link_get_dhcp_server_lease_file(link, &dir_fd, &lease_file);
return 0; /* persistent storage is not ready. */ if (r == -EBUSY)
return 0; /* persistent storage is not ready. */
_cleanup_free_ char *lease_file = path_join("dhcp-server-lease", link->ifname); if (r < 0)
if (!lease_file) return r;
return -ENOMEM; if (r > 0) {
r = sd_dhcp_server_set_lease_file(link->dhcp_server, dir_fd, lease_file);
r = sd_dhcp_server_set_lease_file(link->dhcp_server, link->manager->persistent_storage_fd, lease_file);
if (r < 0) if (r < 0)
return r; return r;
} }
@@ -265,7 +303,7 @@ void manager_toggle_dhcp4_server_state(Manager *manager, bool start) {
HASHMAP_FOREACH(link, manager->links_by_index) { HASHMAP_FOREACH(link, manager->links_by_index) {
if (!link->dhcp_server) if (!link->dhcp_server)
continue; continue;
if (!dhcp_server_persist_leases(link)) if (link_get_dhcp_server_persist_leases(link) != DHCP_SERVER_PERSIST_LEASES_YES)
continue; continue;
/* Even if 'start' is true, first we need to stop the server. Otherwise, we cannot (re)set /* Even if 'start' is true, first we need to stop the server. Otherwise, we cannot (re)set
@@ -916,3 +954,19 @@ int config_parse_dhcp_server_ipv6_only_preferred(
*usec = t; *usec = t;
return 0; return 0;
} }
static const char* const dhcp_server_persist_leases_table[_DHCP_SERVER_PERSIST_LEASES_MAX] = {
[DHCP_SERVER_PERSIST_LEASES_NO] = "no",
[DHCP_SERVER_PERSIST_LEASES_YES] = "yes",
[DHCP_SERVER_PERSIST_LEASES_RUNTIME] = "runtime",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(
dhcp_server_persist_leases,
DHCPServerPersistLeases,
DHCP_SERVER_PERSIST_LEASES_YES);
DEFINE_CONFIG_PARSE_ENUM(
config_parse_dhcp_server_persist_leases,
dhcp_server_persist_leases,
DHCPServerPersistLeases);

View File

@@ -3,6 +3,14 @@
#include "networkd-forward.h" #include "networkd-forward.h"
typedef enum DHCPServerPersistLeases {
DHCP_SERVER_PERSIST_LEASES_NO,
DHCP_SERVER_PERSIST_LEASES_YES,
DHCP_SERVER_PERSIST_LEASES_RUNTIME,
_DHCP_SERVER_PERSIST_LEASES_MAX,
_DHCP_SERVER_PERSIST_LEASES_INVALID = -EINVAL,
} DHCPServerPersistLeases;
int network_adjust_dhcp_server(Network *network, Set **addresses); int network_adjust_dhcp_server(Network *network, Set **addresses);
int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret); int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret);
int link_request_dhcp_server(Link *link); int link_request_dhcp_server(Link *link);
@@ -14,3 +22,4 @@ 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_emit);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_address); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_ipv6_only_preferred); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_ipv6_only_preferred);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_persist_leases);

View File

@@ -44,7 +44,7 @@ DHCPv4.DUIDRawData, config_parse_duid_rawdata,
DHCPv6.UseDomains, config_parse_use_domains, 0, offsetof(Manager, dhcp6_use_domains) DHCPv6.UseDomains, config_parse_use_domains, 0, offsetof(Manager, dhcp6_use_domains)
DHCPv6.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp6_duid) DHCPv6.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp6_duid)
DHCPv6.DUIDRawData, config_parse_duid_rawdata, 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) DHCPServer.PersistLeases, config_parse_dhcp_server_persist_leases, 0, offsetof(Manager, dhcp_server_persist_leases)
/* Deprecated */ /* Deprecated */
DHCP.DUIDType, config_parse_manager_duid_type, 0, 0 DHCP.DUIDType, config_parse_manager_duid_type, 0, 0
DHCP.DUIDRawData, config_parse_manager_duid_rawdata, 0, 0 DHCP.DUIDRawData, config_parse_manager_duid_rawdata, 0, 0

View File

@@ -635,7 +635,7 @@ int manager_new(Manager **ret, bool test_mode) {
.dhcp_duid.type = DUID_TYPE_EN, .dhcp_duid.type = DUID_TYPE_EN,
.dhcp6_duid.type = DUID_TYPE_EN, .dhcp6_duid.type = DUID_TYPE_EN,
.duid_product_uuid.type = DUID_TYPE_UUID, .duid_product_uuid.type = DUID_TYPE_UUID,
.dhcp_server_persist_leases = true, .dhcp_server_persist_leases = DHCP_SERVER_PERSIST_LEASES_YES,
.serialization_fd = -EBADF, .serialization_fd = -EBADF,
.ip_forwarding = { -1, -1, }, .ip_forwarding = { -1, -1, },
#if HAVE_VMLINUX_H #if HAVE_VMLINUX_H

View File

@@ -36,7 +36,7 @@ typedef struct Manager {
bool manage_foreign_routes; bool manage_foreign_routes;
bool manage_foreign_rules; bool manage_foreign_rules;
bool manage_foreign_nexthops; bool manage_foreign_nexthops;
bool dhcp_server_persist_leases; DHCPServerPersistLeases dhcp_server_persist_leases;
Set *dirty_links; Set *dirty_links;
Set *new_wlan_ifindices; Set *new_wlan_ifindices;

View File

@@ -389,7 +389,7 @@ DHCPServer.BootServerAddress, config_parse_in_addr_non_null,
DHCPServer.BootServerName, config_parse_dns_name, 0, offsetof(Network, dhcp_server_boot_server_name) 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.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) DHCPServer.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp_server_rapid_commit)
DHCPServer.PersistLeases, config_parse_tristate, 0, offsetof(Network, dhcp_server_persist_leases) DHCPServer.PersistLeases, config_parse_dhcp_server_persist_leases, 0, offsetof(Network, dhcp_server_persist_leases)
DHCPServerStaticLease.Address, config_parse_dhcp_static_lease_address, 0, 0 DHCPServerStaticLease.Address, config_parse_dhcp_static_lease_address, 0, 0
DHCPServerStaticLease.MACAddress, config_parse_dhcp_static_lease_hwaddr, 0, 0 DHCPServerStaticLease.MACAddress, config_parse_dhcp_static_lease_hwaddr, 0, 0
Bridge.Cost, config_parse_uint32, 0, offsetof(Network, cost) Bridge.Cost, config_parse_uint32, 0, offsetof(Network, cost)

View File

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

View File

@@ -11,6 +11,7 @@
#include "network-util.h" #include "network-util.h"
#include "networkd-bridge-vlan.h" #include "networkd-bridge-vlan.h"
#include "networkd-dhcp-common.h" #include "networkd-dhcp-common.h"
#include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h" #include "networkd-dhcp4.h"
#include "networkd-dhcp6.h" #include "networkd-dhcp6.h"
#include "networkd-dns.h" #include "networkd-dns.h"
@@ -228,7 +229,7 @@ typedef struct Network {
char *dhcp_server_boot_filename; char *dhcp_server_boot_filename;
usec_t dhcp_server_ipv6_only_preferred_usec; usec_t dhcp_server_ipv6_only_preferred_usec;
bool dhcp_server_rapid_commit; bool dhcp_server_rapid_commit;
int dhcp_server_persist_leases; DHCPServerPersistLeases dhcp_server_persist_leases;
/* link-local addressing support */ /* link-local addressing support */
AddressFamily link_local; AddressFamily link_local;

View File

@@ -69,8 +69,9 @@ static int run(int argc, char *argv[]) {
/* Always create the directories people can create inotify watches in. It is necessary to create the /* Always create the directories people can create inotify watches in. It is necessary to create the
* following subdirectories after drop_privileges() to make them owned by systemd-network. */ * following subdirectories after drop_privileges() to make them owned by systemd-network. */
FOREACH_STRING(p, FOREACH_STRING(p,
"/run/systemd/netif/links/", "/run/systemd/netif/dhcp-server-lease/",
"/run/systemd/netif/leases/") { "/run/systemd/netif/leases/",
"/run/systemd/netif/links/") {
r = mkdir_safe_label(p, 0755, UID_INVALID, GID_INVALID, MKDIR_WARN_MODE); r = mkdir_safe_label(p, 0755, UID_INVALID, GID_INVALID, MKDIR_WARN_MODE);
if (r < 0) if (r < 0)
log_warning_errno(r, "Could not create directory '%s': %m", p); log_warning_errno(r, "Could not create directory '%s': %m", p);

View File

@@ -0,0 +1,3 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[DHCPServer]
PersistLeases=runtime

View File

@@ -7110,7 +7110,7 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
def tearDown(self): def tearDown(self):
tear_down_common() tear_down_common()
def check_dhcp_server(self, persist_leases=True): def check_dhcp_server(self, persist_leases='yes'):
output = networkctl_status('veth99') output = networkctl_status('veth99')
print(output) print(output)
self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)') self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)')
@@ -7122,11 +7122,16 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
print(output) print(output)
self.assertRegex(output, "Offered DHCP leases: 192.168.5.[0-9]*") self.assertRegex(output, "Offered DHCP leases: 192.168.5.[0-9]*")
if persist_leases: if persist_leases == 'yes':
with open('/var/lib/systemd/network/dhcp-server-lease/veth-peer', encoding='utf-8') as f: path = '/var/lib/systemd/network/dhcp-server-lease/veth-peer'
check_json(f.read()) elif persist_leases == 'runtime':
path = '/run/systemd/netif/dhcp-server-lease/veth-peer'
else: else:
self.assertFalse(os.path.exists('/var/lib/systemd/network/dhcp-server-lease/veth-peer')) path = None
if path:
with open(path, encoding='utf-8') as f:
check_json(f.read())
def test_dhcp_server(self): def test_dhcp_server(self):
copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network') copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
@@ -7152,7 +7157,7 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
start_networkd() start_networkd()
self.wait_online('veth99:routable', 'veth-peer:routable') self.wait_online('veth99:routable', 'veth-peer:routable')
self.check_dhcp_server(persist_leases=False) self.check_dhcp_server(persist_leases='no')
remove_networkd_conf_dropin('persist-leases-no.conf') remove_networkd_conf_dropin('persist-leases-no.conf')
with open(os.path.join(network_unit_dir, '25-dhcp-server.network'), mode='a', encoding='utf-8') as f: with open(os.path.join(network_unit_dir, '25-dhcp-server.network'), mode='a', encoding='utf-8') as f:
@@ -7160,7 +7165,23 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
restart_networkd() restart_networkd()
self.wait_online('veth99:routable', 'veth-peer:routable') self.wait_online('veth99:routable', 'veth-peer:routable')
self.check_dhcp_server(persist_leases=False) self.check_dhcp_server(persist_leases='no')
def test_dhcp_server_persist_leases_runtime(self):
copy_networkd_conf_dropin('persist-leases-runtime.conf')
copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
start_networkd()
self.wait_online('veth99:routable', 'veth-peer:routable')
self.check_dhcp_server(persist_leases='runtime')
remove_networkd_conf_dropin('persist-leases-runtime.conf')
with open(os.path.join(network_unit_dir, '25-dhcp-server.network'), mode='a', encoding='utf-8') as f:
f.write('[DHCPServer]\nPersistLeases=runtime')
restart_networkd()
self.wait_online('veth99:routable', 'veth-peer:routable')
self.check_dhcp_server(persist_leases='runtime')
def test_dhcp_server_null_server_address(self): def test_dhcp_server_null_server_address(self):
copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-null-server-address.network') copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-null-server-address.network')