diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 695bcaa0a47..d832e68d71c 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -838,6 +838,22 @@
+
+ KeepConfiguration=
+
+ Takes a boolean or one of static, dhcp-on-stop,
+ dhcp. When static, systemd-networkd
+ will not drop static addresses and routes on starting up process. When set to
+ dhcp-on-stop, systemd-networkd will not drop addresses
+ and routes on stopping the daemon. When dhcp,
+ 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 dhcp
+ implies dhcp-on-stop, and yes implies
+ dhcp and static. Defaults to
+ dhcp-on-stop.
+
+
@@ -1381,17 +1397,6 @@
system. Defaults to no.
-
- CriticalConnection=
-
- 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.
-
-
-
ClientIdentifier=
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 4ed020ea8e5..88a72e39a98 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -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");
@@ -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");
@@ -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;
}
@@ -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;
}
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 6613992a091..3301d0b3ce6 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -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");
@@ -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);
}
@@ -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;
@@ -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)
@@ -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)
@@ -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;
@@ -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;
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index d0290f7c7d5..03db91bbd97 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -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_;
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 6984c5b9679..e1f4d7623f5 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -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);
}
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 9ef07ea372b..2986ff1123d 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -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
@@ -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)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index a5e7cad58a4..0741dfe646d 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -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);
@@ -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,
@@ -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,
};
@@ -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);
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index d2a0b8c5f14..7b92a544266 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -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 {
@@ -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;
@@ -227,6 +238,7 @@ struct Network {
bool unmanaged;
bool configure_without_carrier;
bool ignore_carrier_loss;
+ KeepConfiguration keep_configuration;
uint32_t iaid;
DUID duid;
@@ -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);
@@ -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_;
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index bba8948d352..496c52336cb 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -135,6 +135,7 @@ DHCPServer=
BindCarrier=
VRF=
IgnoreCarrierLoss=
+KeepConfiguration=
[IPv6Prefix]
Prefix=
OnLink=
diff --git a/test/test-network/conf/24-keep-configuration-static.network b/test/test-network/conf/24-keep-configuration-static.network
new file mode 100644
index 00000000000..0c65a1d9e2e
--- /dev/null
+++ b/test/test-network/conf/24-keep-configuration-static.network
@@ -0,0 +1,5 @@
+[Match]
+Name=dummy98
+
+[Network]
+KeepConfiguration=static
diff --git a/test/test-network/conf/dhcp-client-critical-connection.network b/test/test-network/conf/dhcp-client-keep-configuration-dhcp-on-stop.network
similarity index 65%
rename from test/test-network/conf/dhcp-client-critical-connection.network
rename to test/test-network/conf/dhcp-client-keep-configuration-dhcp-on-stop.network
index 0e65dec0ae9..e17c9854021 100644
--- a/test/test-network/conf/dhcp-client-critical-connection.network
+++ b/test/test-network/conf/dhcp-client-keep-configuration-dhcp-on-stop.network
@@ -4,6 +4,4 @@ Name=veth99
[Network]
DHCP=ipv4
IPv6AcceptRA=false
-
-[DHCP]
-CriticalConnection=true
+KeepConfiguration=dhcp-on-stop
diff --git a/test/test-network/conf/dhcp-client-keep-configuration-dhcp.network b/test/test-network/conf/dhcp-client-keep-configuration-dhcp.network
new file mode 100644
index 00000000000..c43f78d1dea
--- /dev/null
+++ b/test/test-network/conf/dhcp-client-keep-configuration-dhcp.network
@@ -0,0 +1,7 @@
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+IPv6AcceptRA=false
+KeepConfiguration=dhcp
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 5ba799036ab..ddb2465e1da 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -1235,6 +1235,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'11-dummy.netdev',
'12-dummy.netdev',
'23-active-slave.network',
+ '24-keep-configuration-static.network',
'24-search-domain.network',
'25-address-link-section.network',
'25-address-preferred-lifetime-zero-ipv6.network',
@@ -1658,6 +1659,28 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'DNS: 192.168.42.1')
self.assertRegex(output, 'Search Domains: one')
+ def test_keep_configuration_static(self):
+ check_output('systemctl stop systemd-networkd')
+
+ check_output('ip link add name dummy98 type dummy')
+ check_output('ip address add 10.1.2.3/16 dev dummy98')
+ check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
+ output = check_output('ip address show dummy98')
+ print(output)
+ self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
+ self.assertRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
+ output = check_output('ip route show dev dummy98')
+ print(output)
+
+ copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
+ start_networkd(0)
+ wait_online(['dummy98:routable'])
+
+ output = check_output('ip address show dummy98')
+ print(output)
+ self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
+ self.assertNotRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
+
class NetworkdBondTests(unittest.TestCase, Utilities):
links = [
'bond199',
@@ -2026,13 +2049,14 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
'25-vrf.netdev',
'25-vrf.network',
'dhcp-client-anonymize.network',
- 'dhcp-client-critical-connection.network',
'dhcp-client-gateway-onlink-implicit.network',
'dhcp-client-ipv4-dhcp-settings.network',
'dhcp-client-ipv4-only-ipv6-disabled.network',
'dhcp-client-ipv4-only.network',
'dhcp-client-ipv6-only.network',
'dhcp-client-ipv6-rapid-commit.network',
+ 'dhcp-client-keep-configuration-dhcp-on-stop.network',
+ 'dhcp-client-keep-configuration-dhcp.network',
'dhcp-client-listen-port.network',
'dhcp-client-route-metric.network',
'dhcp-client-route-table.network',
@@ -2210,26 +2234,84 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, 'metric 24')
- def test_dhcp_route_criticalconnection_true(self):
- copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
+ def test_dhcp_keep_configuration_dhcp(self):
+ copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
start_networkd(0)
wait_online(['veth-peer:carrier'])
- start_dnsmasq()
+ start_dnsmasq(lease_time='2m')
wait_online(['veth99:routable', 'veth-peer:routable'])
+ output = check_output('ip address show dev veth99 scope global')
+ print(output)
+ self.assertRegex(output, r'192.168.5.*')
+
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
print(output)
- self.assertRegex(output, '192.168.5.*')
+ self.assertRegex(output, r'192.168.5.*')
# Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
stop_dnsmasq(dnsmasq_pid_file)
# Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
+ print('Wait for the dynamic address to be expired')
time.sleep(125)
+ print('The lease address should be kept after lease expired')
+ output = check_output('ip address show dev veth99 scope global')
+ print(output)
+ self.assertRegex(output, r'192.168.5.*')
+
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
print(output)
- self.assertRegex(output, '192.168.5.*')
+ self.assertRegex(output, r'192.168.5.*')
+
+ check_output('systemctl stop systemd-networkd')
+
+ print('The lease address should be kept after networkd stopped')
+ output = check_output('ip address show dev veth99 scope global')
+ print(output)
+ self.assertRegex(output, r'192.168.5.*')
+
+ output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
+ print(output)
+ self.assertRegex(output, r'192.168.5.*')
+
+ check_output('systemctl start systemd-networkd')
+ wait_online(['veth-peer:routable'])
+
+ print('Still the lease address should be kept after networkd restarted')
+ output = check_output('ip address show dev veth99 scope global')
+ print(output)
+ self.assertRegex(output, r'192.168.5.*')
+
+ output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
+ print(output)
+ self.assertRegex(output, r'192.168.5.*')
+
+ def test_dhcp_keep_configuration_dhcp_on_stop(self):
+ copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
+ start_networkd(0)
+ wait_online(['veth-peer:carrier'])
+ start_dnsmasq(lease_time='2m')
+ wait_online(['veth99:routable', 'veth-peer:routable'])
+
+ output = check_output('ip address show dev veth99 scope global')
+ print(output)
+ self.assertRegex(output, r'192.168.5.*')
+
+ stop_dnsmasq(dnsmasq_pid_file)
+ check_output('systemctl stop systemd-networkd')
+
+ output = check_output('ip address show dev veth99 scope global')
+ print(output)
+ self.assertRegex(output, r'192.168.5.*')
+
+ start_networkd(0)
+ wait_online(['veth-peer:routable'])
+
+ output = check_output('ip address show dev veth99 scope global')
+ print(output)
+ self.assertNotRegex(output, r'192.168.5.*')
def test_dhcp_client_reuse_address_as_static(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')