mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
network/dhcp-server: save and load leases in runtime directory when PersistLeases=runtime
With 9ccc369ff3, PersistLeases= is
disabled on the host side virtual interfaces for containers.
However, even it is not necessary to save the leases for containers
on a persistent storage, still we should save them on somewhere.
Otherwise, leases will be lost when networkd on the host is restarted
or the host side interface is reconfigured.
This introduce PersistLeases=runtime to save and load leases on runtime
storage.
This commit is contained in:
@@ -404,7 +404,7 @@ DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00</programlisting>
|
||||
<term><varname>PersistLeases=</varname></term>
|
||||
<listitem>
|
||||
<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>.
|
||||
Defaults to <literal>yes</literal>.</para>
|
||||
|
||||
|
||||
@@ -443,7 +443,7 @@
|
||||
|
||||
<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
|
||||
<varname>RelayTarget=</varname> or <varname>PersistLeases=no/runtime</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
|
||||
@@ -4140,16 +4140,24 @@ ServerAddress=192.168.0.1/24</programlisting>
|
||||
<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
|
||||
<para>Takes a boolean or special value <literal>runtime</literal>. When <literal>yes</literal>, the
|
||||
DHCP server will load and save leases in the persistent storage. When <literal>runtime</literal>,
|
||||
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
|
||||
<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
|
||||
disable this setting. When unspecified, the value specified in the same setting in
|
||||
is restarted. Using <literal>runtime</literal> and <literal>no</literal> may cause address conflict
|
||||
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>,
|
||||
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"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "path-util.h"
|
||||
#include "set.h"
|
||||
#include "socket-netlink.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
@@ -150,13 +151,13 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool dhcp_server_persist_leases(Link *link) {
|
||||
static DHCPServerPersistLeases link_get_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. */
|
||||
return DHCP_SERVER_PERSIST_LEASES_NO; /* On relay mode. Nothing saved in the persistent storage. */
|
||||
|
||||
if (link->network->dhcp_server_persist_leases >= 0)
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
struct in_addr a;
|
||||
uint8_t prefixlen;
|
||||
int r;
|
||||
|
||||
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))
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
struct in_addr a;
|
||||
uint8_t prefixlen;
|
||||
r = dhcp_server_leases_file_get_server_address(
|
||||
link->manager->persistent_storage_fd,
|
||||
dir_fd,
|
||||
lease_file,
|
||||
&a,
|
||||
&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
|
||||
* 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);
|
||||
_cleanup_free_ char *lease_file = NULL;
|
||||
int dir_fd;
|
||||
r = link_get_dhcp_server_lease_file(link, &dir_fd, &lease_file);
|
||||
if (r == -EBUSY)
|
||||
return 0; /* persistent storage is not ready. */
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
r = sd_dhcp_server_set_lease_file(link->dhcp_server, dir_fd, lease_file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -265,7 +303,7 @@ void manager_toggle_dhcp4_server_state(Manager *manager, bool start) {
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
if (!link->dhcp_server)
|
||||
continue;
|
||||
if (!dhcp_server_persist_leases(link))
|
||||
if (link_get_dhcp_server_persist_leases(link) != DHCP_SERVER_PERSIST_LEASES_YES)
|
||||
continue;
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
|
||||
#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 address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret);
|
||||
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_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_ipv6_only_preferred);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_persist_leases);
|
||||
|
||||
@@ -44,7 +44,7 @@ DHCPv4.DUIDRawData, config_parse_duid_rawdata,
|
||||
DHCPv6.UseDomains, config_parse_use_domains, 0, offsetof(Manager, dhcp6_use_domains)
|
||||
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)
|
||||
DHCPServer.PersistLeases, config_parse_dhcp_server_persist_leases, 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
|
||||
|
||||
@@ -635,7 +635,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,
|
||||
.dhcp_server_persist_leases = DHCP_SERVER_PERSIST_LEASES_YES,
|
||||
.serialization_fd = -EBADF,
|
||||
.ip_forwarding = { -1, -1, },
|
||||
#if HAVE_VMLINUX_H
|
||||
|
||||
@@ -36,7 +36,7 @@ typedef struct Manager {
|
||||
bool manage_foreign_routes;
|
||||
bool manage_foreign_rules;
|
||||
bool manage_foreign_nexthops;
|
||||
bool dhcp_server_persist_leases;
|
||||
DHCPServerPersistLeases dhcp_server_persist_leases;
|
||||
|
||||
Set *dirty_links;
|
||||
Set *new_wlan_ifindices;
|
||||
|
||||
@@ -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.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.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.MACAddress, config_parse_dhcp_static_lease_hwaddr, 0, 0
|
||||
Bridge.Cost, config_parse_uint32, 0, offsetof(Network, cost)
|
||||
|
||||
@@ -435,7 +435,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,
|
||||
.dhcp_server_persist_leases = _DHCP_SERVER_PERSIST_LEASES_INVALID,
|
||||
|
||||
.router_lifetime_usec = RADV_DEFAULT_ROUTER_LIFETIME_USEC,
|
||||
.router_dns_lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "network-util.h"
|
||||
#include "networkd-bridge-vlan.h"
|
||||
#include "networkd-dhcp-common.h"
|
||||
#include "networkd-dhcp-server.h"
|
||||
#include "networkd-dhcp4.h"
|
||||
#include "networkd-dhcp6.h"
|
||||
#include "networkd-dns.h"
|
||||
@@ -228,7 +229,7 @@ typedef 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;
|
||||
DHCPServerPersistLeases dhcp_server_persist_leases;
|
||||
|
||||
/* link-local addressing support */
|
||||
AddressFamily link_local;
|
||||
|
||||
@@ -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
|
||||
* following subdirectories after drop_privileges() to make them owned by systemd-network. */
|
||||
FOREACH_STRING(p,
|
||||
"/run/systemd/netif/links/",
|
||||
"/run/systemd/netif/leases/") {
|
||||
"/run/systemd/netif/dhcp-server-lease/",
|
||||
"/run/systemd/netif/leases/",
|
||||
"/run/systemd/netif/links/") {
|
||||
r = mkdir_safe_label(p, 0755, UID_INVALID, GID_INVALID, MKDIR_WARN_MODE);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not create directory '%s': %m", p);
|
||||
|
||||
Reference in New Issue
Block a user