Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions man/systemd.network.xml
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,22 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>KeepConfiguration=</varname></term>
<listitem>
<para>Takes a boolean or one of <literal>static</literal>, <literal>dhcp-on-stop</literal>,
<literal>dhcp</literal>. When <literal>static</literal>, <command>systemd-networkd</command>
will not drop static addresses and routes on starting up process. When set to
<literal>dhcp-on-stop</literal>, <command>systemd-networkd</command> will not drop addresses
and routes on stopping the daemon. When <literal>dhcp</literal>,
the addresses and routes provided by a DHCP server will never be dropped even if the DHCP
lease expires. This is contrary to the DHCP specification, but may be the best choice if,
e.g., the root filesystem relies on this connection. The setting <literal>dhcp</literal>
implies <literal>dhcp-on-stop</literal>, and <literal>yes</literal> implies
<literal>dhcp</literal> and <literal>static</literal>. Defaults to
<literal>dhcp-on-stop</literal>.</para>
</listitem>
</varlistentry>

</variablelist>

Expand Down Expand Up @@ -1381,17 +1397,6 @@
system. Defaults to <literal>no</literal>.</para></listitem>
</varlistentry>

<varlistentry>
<term><varname>CriticalConnection=</varname></term>
<listitem>
<para>When true, the connection will never be torn down
even if the DHCP lease expires. This is contrary to the
DHCP specification, but may be the best choice if, say,
the root filesystem relies on this connection. Defaults to
false.</para>
</listitem>
</varlistentry>

<varlistentry>
<term><varname>ClientIdentifier=</varname></term>
<listitem>
Expand Down
8 changes: 4 additions & 4 deletions src/network/networkd-dhcp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");

if (!link->network->dhcp_critical) {
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
Expand Down Expand Up @@ -581,7 +581,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
}
}

if (!link->network->dhcp_critical) {
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
Expand Down Expand Up @@ -649,7 +649,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
}

if (link->network->dhcp_critical) {
if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
return 0;
}
Expand All @@ -669,7 +669,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
case SD_DHCP_CLIENT_EVENT_EXPIRED:
case SD_DHCP_CLIENT_EVENT_IP_CHANGE:

if (link->network->dhcp_critical) {
if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
return 0;
}
Expand Down
53 changes: 48 additions & 5 deletions src/network/networkd-link.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,14 +680,15 @@ static void link_enter_unmanaged(Link *link) {
link_dirty(link);
}

int link_stop_clients(Link *link) {
int link_stop_clients(Link *link, bool may_keep_dhcp) {
int r = 0, k;

assert(link);
assert(link->manager);
assert(link->manager->event);

if (link->dhcp_client) {
if (link->dhcp_client && (!may_keep_dhcp || !link->network ||
!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP))) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0)
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
Expand Down Expand Up @@ -731,7 +732,7 @@ void link_enter_failed(Link *link) {

link_set_state(link, LINK_STATE_FAILED);

link_stop_clients(link);
link_stop_clients(link, false);

link_dirty(link);
}
Expand Down Expand Up @@ -2485,6 +2486,33 @@ static bool link_is_static_route_configured(Link *link, Route *route) {
return false;
}

static bool link_address_is_dynamic(Link *link, Address *address) {
Route *route;
Iterator i;

assert(link);
assert(address);

if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
return true;

/* Even when the address is leased from a DHCP server, networkd assign the address
* without lifetime when KeepConfiguration=dhcp. So, let's check that we have
* corresponding routes with RTPROT_DHCP. */
SET_FOREACH(route, link->routes_foreign, i) {
if (route->protocol != RTPROT_DHCP)
continue;

if (address->family != route->family)
continue;

if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc))
return true;
}

return false;
}

static int link_drop_foreign_config(Link *link) {
Address *address;
Route *route;
Expand All @@ -2496,6 +2524,12 @@ static int link_drop_foreign_config(Link *link) {
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
continue;

if (link_address_is_dynamic(link, address)) {
if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
continue;
} else if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
continue;

if (link_is_static_address_configured(link, address)) {
r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
if (r < 0)
Expand All @@ -2512,6 +2546,14 @@ static int link_drop_foreign_config(Link *link) {
if (route->protocol == RTPROT_KERNEL)
continue;

if (route->protocol == RTPROT_STATIC &&
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
continue;

if (route->protocol == RTPROT_DHCP &&
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
continue;

if (link_is_static_route_configured(link, route)) {
r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL);
if (r < 0)
Expand Down Expand Up @@ -2578,7 +2620,8 @@ static int link_configure(Link *link) {

/* Drop foreign config, but ignore loopback or critical devices.
* We do not want to remove loopback address or addresses used for root NFS. */
if (!(link->flags & IFF_LOOPBACK) && !(link->network->dhcp_critical)) {
if (!(link->flags & IFF_LOOPBACK) &&
link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
r = link_drop_foreign_config(link);
if (r < 0)
return r;
Expand Down Expand Up @@ -3264,7 +3307,7 @@ static int link_carrier_lost(Link *link) {
if (link->setting_mtu)
return 0;

r = link_stop_clients(link);
r = link_stop_clients(link, false);
if (r < 0) {
link_enter_failed(link);
return r;
Expand Down
2 changes: 1 addition & 1 deletion src/network/networkd-link.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link, int ir);
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);

int link_stop_clients(Link *link);
int link_stop_clients(Link *link, bool may_keep_dhcp);

const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
Expand Down
2 changes: 1 addition & 1 deletion src/network/networkd-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ void manager_free(Manager *m) {
if (link->dhcp6_client)
(void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client, link);

link_stop_clients(link);
(void) link_stop_clients(link, true);

link_unref(link);
}
Expand Down
3 changes: 2 additions & 1 deletion src/network/networkd-network-gperf.gperf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Network.IPv6ProxyNDPAddress, config_parse_ipv6_proxy_ndp_address,
Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
Network.ConfigureWithoutCarrier, config_parse_bool, 0, offsetof(Network, configure_without_carrier)
Network.IgnoreCarrierLoss, config_parse_bool, 0, offsetof(Network, ignore_carrier_loss)
Network.KeepConfiguration, config_parse_keep_configuration, 0, offsetof(Network, keep_configuration)
Address.Address, config_parse_address, 0, 0
Address.Peer, config_parse_address, 0, 0
Address.Broadcast, config_parse_broadcast, 0, 0
Expand Down Expand Up @@ -143,7 +144,7 @@ DHCP.Anonymize, config_parse_bool,
DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical) /* deprecated */
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0
DHCP.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class)
Expand Down
32 changes: 32 additions & 0 deletions src/network/networkd-network.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,22 @@ int network_verify(Network *network) {
network->dhcp_use_mtu = false;
}

if (network->dhcp_critical >= 0) {
if (network->keep_configuration >= 0)
log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
"Ignoring CriticalConnection=.", network->filename);
else if (network->dhcp_critical)
/* CriticalConnection=yes also preserve foreign static configurations. */
network->keep_configuration = KEEP_CONFIGURATION_YES;
else
/* For backward compatibility, we do not release DHCP addresses on manager stop. */
network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
}

if (network->keep_configuration < 0)
/* For backward compatibility, we do not release DHCP addresses on manager stop. */
network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;

LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
if (address_section_verify(address) < 0)
address_free(address);
Expand Down Expand Up @@ -324,6 +340,7 @@ int network_load_one(Manager *manager, const char *filename) {
.required_for_online = true,
.required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
.dhcp = ADDRESS_FAMILY_NO,
.dhcp_critical = -1,
.dhcp_use_ntp = true,
.dhcp_use_dns = true,
.dhcp_use_hostname = true,
Expand Down Expand Up @@ -392,6 +409,8 @@ int network_load_one(Manager *manager, const char *filename) {
.ipv6_accept_ra_route_table = RT_TABLE_MAIN,
.ipv6_accept_ra_route_table_set = false,

.keep_configuration = _KEEP_CONFIGURATION_INVALID,

.can_triple_sampling = -1,
};

Expand Down Expand Up @@ -1752,3 +1771,16 @@ int config_parse_required_for_online(

return 0;
}

DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
"Failed to parse KeepConfiguration= setting");

static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
[KEEP_CONFIGURATION_NO] = "no",
[KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
[KEEP_CONFIGURATION_DHCP] = "dhcp",
[KEEP_CONFIGURATION_STATIC] = "static",
[KEEP_CONFIGURATION_YES] = "yes",
};

DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
18 changes: 17 additions & 1 deletion src/network/networkd-network.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ typedef enum RADVPrefixDelegation {
_RADV_PREFIX_DELEGATION_INVALID = -1,
} RADVPrefixDelegation;

typedef enum KeepConfiguration {
KEEP_CONFIGURATION_NO = 0,
KEEP_CONFIGURATION_DHCP_ON_START = 1 << 0,
KEEP_CONFIGURATION_DHCP_ON_STOP = 1 << 1,
KEEP_CONFIGURATION_DHCP = KEEP_CONFIGURATION_DHCP_ON_START | KEEP_CONFIGURATION_DHCP_ON_STOP,
KEEP_CONFIGURATION_STATIC = 1 << 2,
KEEP_CONFIGURATION_YES = KEEP_CONFIGURATION_DHCP | KEEP_CONFIGURATION_STATIC,
_KEEP_CONFIGURATION_MAX,
_KEEP_CONFIGURATION_INVALID = -1,
} KeepConfiguration;

typedef struct Manager Manager;

struct Network {
Expand Down Expand Up @@ -119,7 +130,7 @@ struct Network {
bool dhcp_anonymize;
bool dhcp_send_hostname;
bool dhcp_broadcast;
bool dhcp_critical;
int dhcp_critical;
bool dhcp_use_dns;
bool dhcp_use_ntp;
bool dhcp_use_mtu;
Expand Down Expand Up @@ -227,6 +238,7 @@ struct Network {
bool unmanaged;
bool configure_without_carrier;
bool ignore_carrier_loss;
KeepConfiguration keep_configuration;
uint32_t iaid;
DUID duid;

Expand Down Expand Up @@ -318,6 +330,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ntp);
CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration);
/* Legacy IPv4LL support */
CONFIG_PARSER_PROTOTYPE(config_parse_ipv4ll);

Expand All @@ -336,3 +349,6 @@ DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;

const char* radv_prefix_delegation_to_string(RADVPrefixDelegation i) _const_;
RADVPrefixDelegation radv_prefix_delegation_from_string(const char *s) _pure_;

const char* keep_configuration_to_string(KeepConfiguration i) _const_;
KeepConfiguration keep_configuration_from_string(const char *s) _pure_;
1 change: 1 addition & 0 deletions test/fuzz/fuzz-network-parser/directives.network
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ DHCPServer=
BindCarrier=
VRF=
IgnoreCarrierLoss=
KeepConfiguration=
[IPv6Prefix]
Prefix=
OnLink=
Expand Down
5 changes: 5 additions & 0 deletions test/test-network/conf/24-keep-configuration-static.network
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Match]
Name=dummy98

[Network]
KeepConfiguration=static
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ Name=veth99
[Network]
DHCP=ipv4
IPv6AcceptRA=false

[DHCP]
CriticalConnection=true
KeepConfiguration=dhcp-on-stop
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Match]
Name=veth99

[Network]
DHCP=ipv4
IPv6AcceptRA=false
KeepConfiguration=dhcp
Loading