Merge pull request #28568 from yuwata/network-address-next

network: bunch of cleanups and fixes for addressing
This commit is contained in:
Yu Watanabe
2023-08-01 02:14:19 +09:00
committed by GitHub
8 changed files with 572 additions and 278 deletions
+99 -75
View File
@@ -345,7 +345,7 @@ static uint32_t address_prefix(const Address *a) {
return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
}
static void address_kernel_hash_func(const Address *a, struct siphash *state) {
static void address_hash_func(const Address *a, struct siphash *state) {
assert(a);
siphash24_compress(&a->family, sizeof(a->family), state);
@@ -367,7 +367,7 @@ static void address_kernel_hash_func(const Address *a, struct siphash *state) {
}
}
static int address_kernel_compare_func(const Address *a1, const Address *a2) {
static int address_compare_func(const Address *a1, const Address *a2) {
int r;
r = CMP(a1->family, a2->family);
@@ -396,65 +396,93 @@ static int address_kernel_compare_func(const Address *a1, const Address *a2) {
}
DEFINE_PRIVATE_HASH_OPS(
address_kernel_hash_ops,
address_hash_ops,
Address,
address_kernel_hash_func,
address_kernel_compare_func);
address_hash_func,
address_compare_func);
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
address_kernel_hash_ops_free,
address_hash_ops_free,
Address,
address_kernel_hash_func,
address_kernel_compare_func,
address_hash_func,
address_compare_func,
address_free);
int address_compare_func(const Address *a1, const Address *a2) {
int r;
static bool address_can_update(const Address *la, const Address *na) {
assert(la);
assert(la->link);
assert(na);
assert(na->network);
r = CMP(a1->family, a2->family);
if (r != 0)
return r;
/*
* property | IPv4 | IPv6
* -----------------------------------------
* family | ✗ | ✗
* prefixlen | ✗ | ✗
* address | ✗ | ✗
* scope | ✗ | -
* label | ✗ | -
* broadcast | ✗ | -
* peer | ✗ | ✓
* flags | ✗ | ✓
* lifetime | ✓ | ✓
* route metric | ✓ | ✓
* protocol | ✓ | ✓
*
* ✗ : cannot be changed
* ✓ : can be changed
* - : unused
*
* IPv4 : See inet_rtm_newaddr() in net/ipv4/devinet.c.
* IPv6 : See inet6_addr_modify() in net/ipv6/addrconf.c.
*/
if (!IN_SET(a1->family, AF_INET, AF_INET6))
return 0;
r = CMP(a1->prefixlen, a2->prefixlen);
if (r != 0)
return r;
r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
if (r != 0)
return r;
r = memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family));
if (r != 0)
return r;
if (a1->family == AF_INET) {
/* On update, the kernel ignores the address label and broadcast address, hence we need
* to distinguish addresses with different labels or broadcast addresses. Otherwise,
* the label or broadcast address change will not be applied when we reconfigure the
* interface. */
r = strcmp_ptr(a1->label, a2->label);
if (r != 0)
return r;
r = CMP(a1->broadcast.s_addr, a2->broadcast.s_addr);
if (r != 0)
return r;
}
return 0;
}
int address_equal(const Address *a1, const Address *a2) {
if (a1 == a2)
return true;
if (!a1 || !a2)
if (la->family != na->family)
return false;
return address_compare_func(a1, a2) == 0;
if (la->prefixlen != na->prefixlen)
return false;
/* When a null address is requested, the address to be assigned/updated will be determined later. */
if (!address_is_static_null(na) &&
in_addr_equal(la->family, &la->in_addr, &na->in_addr) <= 0)
return false;
switch (la->family) {
case AF_INET: {
struct in_addr bcast;
if (la->scope != na->scope)
return false;
if (((la->flags ^ na->flags) & KNOWN_FLAGS & ~IPV6ONLY_FLAGS & ~UNMANAGED_FLAGS) != 0)
return false;
if (!streq_ptr(la->label, na->label))
return false;
if (!in4_addr_equal(&la->in_addr_peer.in, &na->in_addr_peer.in))
return false;
if (address_get_broadcast(na, la->link, &bcast) >= 0) {
/* If the broadcast address can be determined now, check if they match. */
if (!in4_addr_equal(&la->broadcast, &bcast))
return false;
} else {
/* When a null address is requested, then the broadcast address will be
* automatically calculated from the acquired address, e.g.
* 192.168.0.10/24 -> 192.168.0.255
* So, here let's only check if the broadcast is the last address in the range, e.g.
* 0.0.0.0/24 -> 0.0.0.255 */
if (!FLAGS_SET(la->broadcast.s_addr, htobe32(UINT32_C(0xffffffff) >> la->prefixlen)))
return false;
}
break;
}
case AF_INET6:
break;
default:
assert_not_reached();
}
return true;
}
int address_dup(const Address *src, Address **ret) {
@@ -533,7 +561,7 @@ static int address_add(Link *link, Address *address) {
assert(link);
assert(address);
r = set_ensure_put(&link->addresses, &address_kernel_hash_ops_free, address);
r = set_ensure_put(&link->addresses, &address_hash_ops_free, address);
if (r < 0)
return r;
if (r == 0)
@@ -630,8 +658,8 @@ static int address_get_request(Link *link, const Address *address, Request **ret
.link = link,
.type = REQUEST_TYPE_ADDRESS,
.userdata = (void*) address,
.hash_func = (hash_func_t) address_kernel_hash_func,
.compare_func = (compare_func_t) address_kernel_compare_func,
.hash_func = (hash_func_t) address_hash_func,
.compare_func = (compare_func_t) address_compare_func,
});
if (req) {
if (ret)
@@ -1116,17 +1144,7 @@ int link_drop_foreign_addresses(Link *link) {
if (address_get(link, address, &existing) < 0)
continue;
/* On update, the kernel ignores the address label and broadcast address. Hence we need to
* distinguish addresses with different labels or broadcast addresses. Thus, we need to check
* the existing address with address_equal(). Otherwise, the label or broadcast address
* change will not be applied when we reconfigure the interface. */
if (address_is_static_null(address)) {
/* If the static configuration has null address, then the broadcast address will be
* determined automatically. Hence, here we need to compare only address label. */
if (address->family == AF_INET && !streq_ptr(address->label, existing->label))
continue;
} else if (!address_equal(address, existing))
if (!address_can_update(existing, address))
continue;
/* Found matching static configuration. Keep the existing address. */
@@ -1256,7 +1274,7 @@ static int address_configure(const Address *address, const struct ifa_cacheinfo
if (r < 0)
return r;
if (in_addr_is_set(address->family, &address->in_addr_peer)) {
if (address->family == AF_INET6 || in_addr_is_set(address->family, &address->in_addr_peer)) {
r = netlink_message_append_in_addr_union(m, IFA_ADDRESS, address->family, &address->in_addr_peer);
if (r < 0)
return r;
@@ -1320,7 +1338,7 @@ static int address_process_request(Request *req, Link *link, Address *address) {
address_cancel_requesting(address);
if (address_get(link, address, &existing) >= 0)
address_enter_configuring(existing);
address_cancel_requesting(existing);
return 1;
}
@@ -1388,8 +1406,8 @@ int link_request_address(
r = link_queue_request_safe(link, REQUEST_TYPE_ADDRESS,
tmp,
address_free,
address_kernel_hash_func,
address_kernel_compare_func,
address_hash_func,
address_compare_func,
address_process_request,
message_counter, netlink_handler, ret);
if (r < 0)
@@ -1479,8 +1497,8 @@ void address_cancel_request(Address *address) {
.link = address->link,
.type = REQUEST_TYPE_ADDRESS,
.userdata = address,
.hash_func = (hash_func_t) address_kernel_hash_func,
.compare_func = (compare_func_t) address_kernel_compare_func,
.hash_func = (hash_func_t) address_hash_func,
.compare_func = (compare_func_t) address_compare_func,
};
request_detach(address->link->manager, &req);
@@ -1825,7 +1843,7 @@ int config_parse_address(
r = in_addr_prefix_from_string_auto(rvalue, &f, &buffer, &prefixlen);
if (r >= 0)
log_syntax(unit, LOG_WARNING, filename, line, r,
"Address '%s' is specified without prefix length. Assuming the prefix length is %u."
"Address '%s' is specified without prefix length. Assuming the prefix length is %u. "
"Please specify the prefix length explicitly.", rvalue, prefixlen);
}
if (r < 0) {
@@ -1895,6 +1913,12 @@ int config_parse_label(
return 0;
}
if (isempty(rvalue)) {
n->label = mfree(n->label);
TAKE_PTR(n);
return 0;
}
if (!address_label_valid(rvalue)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Interface label is too long or invalid, ignoring assignment: %s", rvalue);
@@ -2318,9 +2342,9 @@ int network_drop_invalid_addresses(Network *network) {
address_free(dup);
}
/* Use address_kernel_hash_ops, instead of address_kernel_hash_ops_free. Otherwise, the
* Address objects will be freed. */
r = set_ensure_put(&addresses, &address_kernel_hash_ops, address);
/* Use address_hash_ops, instead of address_hash_ops_free. Otherwise, the Address objects
* will be freed. */
r = set_ensure_put(&addresses, &address_hash_ops, address);
if (r < 0)
return log_oom();
assert(r > 0);
-3
View File
@@ -119,9 +119,6 @@ int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, Ma
int network_drop_invalid_addresses(Network *network);
int address_compare_func(const Address *a1, const Address *a2);
int address_equal(const Address *a1, const Address *a2);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address);
void link_mark_addresses(Link *link, NetworkConfigSource source);
-49
View File
@@ -180,54 +180,6 @@ static int test_load_config(Manager *manager) {
return 0;
}
static void test_address_equality(void) {
_cleanup_(address_freep) Address *a1 = NULL, *a2 = NULL;
assert_se(address_new(&a1) >= 0);
assert_se(address_new(&a2) >= 0);
assert_se(address_equal(NULL, NULL));
assert_se(!address_equal(a1, NULL));
assert_se(!address_equal(NULL, a2));
assert_se(address_equal(a1, a2));
a1->family = AF_INET;
assert_se(!address_equal(a1, a2));
a2->family = AF_INET;
assert_se(address_equal(a1, a2));
assert_se(in_addr_from_string(AF_INET, "192.168.3.9", &a1->in_addr) >= 0);
assert_se(!address_equal(a1, a2));
assert_se(in_addr_from_string(AF_INET, "192.168.3.9", &a2->in_addr) >= 0);
assert_se(address_equal(a1, a2));
assert_se(in_addr_from_string(AF_INET, "192.168.3.10", &a1->in_addr_peer) >= 0);
assert_se(!address_equal(a1, a2));
assert_se(in_addr_from_string(AF_INET, "192.168.3.11", &a2->in_addr_peer) >= 0);
assert_se(!address_equal(a1, a2));
assert_se(in_addr_from_string(AF_INET, "192.168.3.10", &a2->in_addr_peer) >= 0);
assert_se(address_equal(a1, a2));
a1->prefixlen = 10;
assert_se(!address_equal(a1, a2));
a2->prefixlen = 10;
assert_se(address_equal(a1, a2));
a1->family = AF_INET6;
assert_se(!address_equal(a1, a2));
a2->family = AF_INET6;
assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a1->in_addr) >= 0);
assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a2->in_addr) >= 0);
assert_se(address_equal(a1, a2));
a2->prefixlen = 8;
assert_se(!address_equal(a1, a2));
a2->prefixlen = 10;
assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::1", &a2->in_addr) >= 0);
assert_se(!address_equal(a1, a2));
}
static void test_dhcp_hostname_shorten_overlong(void) {
int r;
@@ -281,7 +233,6 @@ int main(void) {
test_deserialize_in_addr();
test_deserialize_dhcp_routes();
test_address_equality();
test_dhcp_hostname_shorten_overlong();
assert_se(manager_new(&manager, /* test_mode = */ true) >= 0);
+3 -2
View File
@@ -1030,9 +1030,10 @@ int dns_cache_lookup(
goto miss;
}
if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL)) {
if ((query_flags & (SD_RESOLVED_CLAMP_TTL | SD_RESOLVED_NO_STALE)) != 0) {
/* 'current' is always passed to answer_add_clamp_ttl(), but is only used conditionally.
* We'll do the same assert there to make sure that it was initialized properly. */
* We'll do the same assert there to make sure that it was initialized properly.
* 'current' is also used below when SD_RESOLVED_NO_STALE is set. */
current = now(CLOCK_BOOTTIME);
assert(current > 0);
}
+134 -70
View File
@@ -14,102 +14,166 @@ Address=2001:db8:0:f102::15/64
Address=hogehoge
Address=foofoo
## With Label=
[Address]
Address=10.3.2.3/16
Label=32
Address=10.3.1.1/24
Label=label1
[Address]
Address=10.4.2.3/16
Peer=10.4.2.4/16
Label=33
Address=10.3.2.1/24
Label=label2
[Address]
Address=0.0.0.0/24
Label=34
Address=10.3.3.1/24
Label=
## With Broadcast=
[Address]
Address=0.0.0.0/16
Label=35
[Address]
# this section must be ignored
Peer=hoge
Address=10.10.0.1/16
Label=30
[Address]
# this section must be ignored
Label=30
Peer=hoge
Address=10.10.0.2/16
[Address]
# address and peer must be in the same family
Address=10.10.0.3/16
Peer=2001:db8:0:f103::10/128
[Address]
Address=2001:db8:0:f102::16/64
[Address]
Address=2001:db8:0:f103::20/128
Peer=2001:db8:0:f103::10/128
[Address]
Address=2001:db8:0:f104::16/64
RouteMetric=128
[Address]
Address=::/64
[Network]
# this will later deduped by the following section
Address=10.7.8.9/16
[Address]
Address=10.7.8.9/16
PreferredLifetime=0
Scope=link
[Address]
# this will also deduped
Address=2001:0db8:1:f101::1/64
PreferredLifetime=infinity
[Address]
Address=2001:0db8:1:f101::1/64
PreferredLifetime=0
[Address]
Address=10.8.8.1/16
Broadcast=yes
Broadcast=
Address=10.4.1.1/24
Broadcast=no
[Address]
Address=10.8.8.2/16
Broadcast=10.8.8.128
Address=10.4.2.1/24
Broadcast=yes
[Address]
Address=10.4.3.1/24
Broadcast=10.4.3.63
[Address]
# Invalid broadcast
Address=10.8.8.2/16
Address=10.4.4.1/24
Broadcast=yes
Broadcast=
Broadcast=::1
[Address]
# broadcast cannot set for IPv6 address
Address=2001:0db8:1:f101::2/64
Address=2001:db8:0:f101::2/64
Broadcast=::1
## With/without Peer=
[Address]
Address=10.9.0.1/16
Address=10.5.1.1/24
Peer=10.5.1.101/24
[Address]
Address=10.5.2.1/24
Peer=10.5.2.101/24
[Address]
Address=10.5.3.1/24
#Peer= (no-peer)
[Address]
Address=2001:db8:0:f103::1/128
Peer=2001:db8:0:f103::101/128
[Address]
Address=2001:db8:0:f103::2/128
Peer=2001:db8:0:f103::102/128
[Address]
Address=2001:db8:0:f103::3/128
#Peer= (no-peer)
[Address]
# address and peer must be in the same family
Address=10.5.4.1/24
Peer=2001:db8:0:f103::10/128
[Address]
# address and peer must be in the same family
Address=2001:db8:0:f103::4/64
Peer=192.168.0.1
[Address]
# invalid peer, this section will be ignored
Address=10.5.5.1/24
Peer=hoge
## With Scope=
[Address]
Address=10.6.1.1/24
Scope=global
[Address]
Address=10.6.2.1/24
Scope=link
## For lifetime
[Address]
Address=10.7.1.1/24
PreferredLifetime=infinity
[Address]
Address=10.7.2.1/24
PreferredLifetime=0
[Address]
Address=2001:db8:0:f104::1/64
PreferredLifetime=infinity
[Address]
Address=2001:db8:0:f104::2/64
PreferredLifetime=0
## For RouteMetric=
[Address]
Address=10.8.1.1/24
RouteMetric=128
[Address]
# invalid metric
Address=10.9.0.1/16
Address=10.8.2.1/24
RouteMetric=hoge
[Address]
Address=10.4.3.2/24
Address=2001:db8:0:f105::1/64
RouteMetric=128
## For flags
[Address]
Address=10.9.1.1/24
AddPrefixRoute=no
[Address]
Address=10.9.2.1/24
AddPrefixRoute=yes
[Address]
# invalid flags for IPv4 address
Address=10.9.3.1/24
HomeAddress=yes
ManageTemporaryAddress=yes
[Address]
Address=2001:db8:0:f106::1/64
HomeAddress=no
ManageTemporaryAddress=no
AddPrefixRoute=no
[Address]
Address=2001:db8:0:f106::2/64
HomeAddress=yes
ManageTemporaryAddress=yes
AddPrefixRoute=yes
# TODO: add tests for AutoJoin=
## null address
[Address]
Address=0.0.0.0/16
Label=subnet16
[Address]
Address=0.0.0.0/24
Label=subnet24
[Address]
Address=::/73
[Address]
Address=10.10.1.1/24
# just a random label which should exist
NetLabel=system_u:object_r:root_t:s0
@@ -1,9 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Address]
Address=10.9.0.1/16
RouteMetric=256
[Address]
Address=2001:db8:0:f104::16/64
RouteMetric=256
@@ -0,0 +1,139 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# For checking if each address property is correctly updated.
# Comments are previous values
## For Label=
[Address]
Address=10.3.1.1/24
#Label=label1
Label=new-label1
[Address]
Address=10.3.2.1/24
#Label=label2
Label=
[Address]
Address=10.3.3.1/24
#Label=
Label=new-label3
## For Broadcast=
[Address]
Address=10.4.1.1/24
#Broadcast=no
Broadcast=yes
[Address]
Address=10.4.2.1/24
#Broadcast=yes
Broadcast=no
[Address]
Address=10.4.3.1/24
#Broadcast=10.4.3.63
Broadcast=10.4.3.31
## For Peer=
[Address]
Address=10.5.1.1/24
#Peer=10.5.1.101/24
Peer=10.5.1.102/24
[Address]
Address=10.5.2.1/24
#Peer=10.5.2.101/24
#Peer= (no-peer)
[Address]
Address=10.5.3.1/24
#Peer= (no-peer)
Peer=10.5.3.102/24
[Address]
Address=2001:db8:0:f103::1/128
#Peer=2001:db8:0:f103::101/128
Peer=2001:db8:0:f103::201/128
[Address]
Address=2001:db8:0:f103::2/128
#Peer=2001:db8:0:f103::102/128
#Peer= (no-peer)
[Address]
Address=2001:db8:0:f103::3/128
#Peer= (no-peer)
Peer=2001:db8:0:f103::203/128
## For Scope=
[Address]
Address=10.6.1.1/24
#Scope=global
Scope=link
[Address]
Address=10.6.2.1/24
#Scope=link
Scope=global
## For lifetime
[Address]
Address=10.7.1.1/24
#PreferredLifetime=infinity
PreferredLifetime=0
[Address]
Address=10.7.2.1/24
#PreferredLifetime=0
PreferredLifetime=infinity
[Address]
Address=2001:db8:0:f104::1/64
#PreferredLifetime=infinity
PreferredLifetime=0
[Address]
Address=2001:db8:0:f104::2/64
#PreferredLifetime=0
PreferredLifetime=infinity
## For RouteMetric=
[Address]
Address=10.8.1.1/24
# RouteMetric=128
RouteMetric=256
[Address]
Address=2001:db8:0:f105::1/64
# RouteMetric=128
RouteMetric=256
## For flags
[Address]
Address=10.9.1.1/24
#AddPrefixRoute=no
AddPrefixRoute=yes
[Address]
Address=10.9.2.1/24
#AddPrefixRoute=yes
AddPrefixRoute=no
[Address]
Address=2001:db8:0:f106::1/64
#HomeAddress=no
#ManageTemporaryAddress=no
#AddPrefixRoute=no
HomeAddress=yes
ManageTemporaryAddress=yes
AddPrefixRoute=yes
[Address]
Address=2001:db8:0:f106::2/64
#HomeAddress=yes
#ManageTemporaryAddress=yes
#AddPrefixRoute=yes
HomeAddress=no
ManageTemporaryAddress=no
AddPrefixRoute=no
+197 -70
View File
@@ -2329,107 +2329,234 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
def tearDown(self):
tear_down_common()
def verify_address_static(self, route_metric):
# IPv4 addresses
output = check_output('ip -4 address show dev dummy98')
def verify_address_static(
self,
label1: str,
label2: str,
label3: str,
broadcast1: str,
broadcast2: str,
broadcast3: str,
peer1: str,
peer2: str,
peer3: str,
peer4: str,
peer5: str,
peer6: str,
scope1: str,
scope2: str,
deprecated1: str,
deprecated2: str,
deprecated3: str,
deprecated4: str,
route_metric: int,
flag1: str,
flag2: str,
flag3: str,
flag4: str,
):
output = check_output('ip address show dev dummy98')
print(output)
# simple settings
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
self.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output)
self.assertIn('inet 10.8.8.1/16 scope global dummy98', output)
self.assertIn('inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98', output)
self.assertRegex(output, rf'inet 10.9.0.1/16 (metric {route_metric} |)brd 10.9.255.255 scope global dummy98')
# invalid sections
self.assertNotIn('10.10.0.1/16', output)
self.assertNotIn('10.10.0.2/16', output)
# address labels
output = check_output('ip -4 address show dev dummy98 label 32')
self.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output)
output = check_output('ip -4 address show dev dummy98 label 33')
self.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output)
output = check_output('ip -4 address show dev dummy98 label 34')
self.assertRegex(output, r'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
output = check_output('ip -4 address show dev dummy98 label 35')
self.assertRegex(output, r'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
# check metric of prefix route
output = check_output('ip -4 route show dev dummy98 10.9.0.0/16')
print(output)
self.assertIn(f'10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric {route_metric}', output)
output = check_output('ip -6 route show dev dummy98 2001:db8:0:f104::/64')
print(output)
self.assertIn(f'2001:db8:0:f104::/64 proto kernel metric {route_metric}', output)
# IPv6 addresses
output = check_output('ip -6 address show dev dummy98')
print(output)
self.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output)
self.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output)
self.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output)
self.assertIn('inet6 2001:db8:0:f102::16/64 scope global', output)
self.assertIn('inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global', output)
self.assertRegex(output, rf'inet6 2001:db8:0:f104::16/64 (metric {route_metric} |)scope global')
self.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output)
self.assertRegex(output, r'inet6 fd[0-9a-f:]*1/64 scope global')
# label
self.assertIn(f'inet 10.3.1.1/24 brd 10.3.1.255 scope global {label1}', output)
self.assertIn(f'inet 10.3.2.1/24 brd 10.3.2.255 scope global {label2}', output)
self.assertIn(f'inet 10.3.3.1/24 brd 10.3.3.255 scope global {label3}', output)
# broadcast
self.assertIn(f'inet 10.4.1.1/24{broadcast1} scope global dummy98', output)
self.assertIn(f'inet 10.4.2.1/24{broadcast2} scope global dummy98', output)
self.assertIn(f'inet 10.4.3.1/24{broadcast3} scope global dummy98', output)
# peer
self.assertIn(f'inet 10.5.1.1{peer1} scope global dummy98', output)
self.assertIn(f'inet 10.5.2.1{peer2} scope global dummy98', output)
self.assertIn(f'inet 10.5.3.1{peer3} scope global dummy98', output)
self.assertIn(f'inet6 2001:db8:0:f103::1{peer4} scope global', output)
self.assertIn(f'inet6 2001:db8:0:f103::2{peer5} scope global', output)
self.assertIn(f'inet6 2001:db8:0:f103::3{peer6} scope global', output)
# scope
self.assertIn(f'inet 10.6.1.1/24 brd 10.6.1.255 scope {scope1} dummy98', output)
self.assertIn(f'inet 10.6.2.1/24 brd 10.6.2.255 scope {scope2} dummy98', output)
# lifetime
self.assertIn(f'inet 10.7.1.1/24 brd 10.7.1.255 scope global{deprecated1} dummy98', output)
self.assertIn(f'inet 10.7.2.1/24 brd 10.7.2.255 scope global{deprecated2} dummy98', output)
self.assertIn(f'inet6 2001:db8:0:f104::1/64 scope global{deprecated3}', output)
self.assertIn(f'inet6 2001:db8:0:f104::2/64 scope global{deprecated4}', output)
# route metric
self.assertRegex(output, rf'inet 10.8.1.1/24 (metric {route_metric} |)brd 10.8.1.255 scope global dummy98')
self.assertRegex(output, rf'inet6 2001:db8:0:f105::1/64 (metric {route_metric} |)scope global')
output_route = check_output('ip -4 route show dev dummy98 10.8.1.0/24')
print(output_route)
self.assertIn(f'10.8.1.0/24 proto kernel scope link src 10.8.1.1 metric {route_metric}', output_route)
output_route = check_output('ip -6 route show dev dummy98 2001:db8:0:f105::/64')
print(output_route)
self.assertIn(f'2001:db8:0:f105::/64 proto kernel metric {route_metric}', output_route)
# flags
self.assertIn(f'inet 10.9.1.1/24 brd 10.9.1.255 scope global{flag1} dummy98', output)
self.assertIn(f'inet 10.9.2.1/24 brd 10.9.2.255 scope global{flag2} dummy98', output)
self.assertIn(f'inet6 2001:db8:0:f106::1/64 scope global{flag3}', output)
self.assertIn(f'inet6 2001:db8:0:f106::2/64 scope global{flag4}', output)
# null address
self.assertRegex(output, r'inet [0-9]*.[0-9]*.0.1/16 brd [0-9]*.[0-9]*.255.255 scope global subnet16')
self.assertRegex(output, r'inet [0-9]*.[0-9]*.[0-9]*.1/24 brd [0-9]*.[0-9]*.[0-9]*.255 scope global subnet24')
self.assertRegex(output, r'inet6 [0-9a-f:]*:1/73 scope global')
# invalid sections
self.assertNotIn('10.4.4.1', output)
self.assertNotIn('10.5.4.1', output)
self.assertNotIn('10.5.5.1', output)
self.assertNotIn('10.8.2.1', output)
self.assertNotIn('10.9.3.1', output)
self.assertNotIn('2001:db8:0:f101::2', output)
self.assertNotIn('2001:db8:0:f103::4', output)
# netlabel
self.check_netlabel('dummy98', r'10\.4\.3\.0/24')
self.check_netlabel('dummy98', r'10\.10\.1\.0/24')
output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
check_json(output)
def test_address_static(self):
# test for #22515. The address will be removed and replaced with /64 prefix.
check_output('ip link add dummy98 type dummy')
check_output('ip link set dev dummy98 up')
check_output('ip -6 address add 2001:db8:0:f101::15/128 dev dummy98')
self.wait_address('dummy98', '2001:db8:0:f101::15/128', ipv='-6')
check_output('ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98')
self.wait_address('dummy98', '10.3.2.3/16 brd 10.3.255.250', ipv='-4')
copy_network_unit('25-address-static.network', '12-dummy.netdev', copy_dropins=False)
start_networkd()
self.wait_online(['dummy98:routable'])
self.verify_address_static(route_metric=128)
self.verify_address_static(
label1='label1',
label2='label2',
label3='dummy98',
broadcast1='',
broadcast2=' brd 10.4.2.255',
broadcast3=' brd 10.4.3.63',
peer1=' peer 10.5.1.101/24',
peer2=' peer 10.5.2.101/24',
peer3='/24 brd 10.5.3.255',
peer4=' peer 2001:db8:0:f103::101/128',
peer5=' peer 2001:db8:0:f103::102/128',
peer6='/128',
scope1='global',
scope2='link',
deprecated1='',
deprecated2=' deprecated',
deprecated3='',
deprecated4=' deprecated',
route_metric=128,
flag1=' noprefixroute',
flag2='',
flag3=' noprefixroute',
flag4=' home mngtmpaddr',
)
copy_network_unit('25-address-static.network.d/10-override-route-metric.conf')
copy_network_unit('25-address-static.network.d/10-override.conf')
networkctl_reload()
self.wait_online(['dummy98:routable'])
self.verify_address_static(route_metric=256)
self.verify_address_static(
label1='new-label1',
label2='dummy98',
label3='new-label3',
broadcast1=' brd 10.4.1.255',
broadcast2='',
broadcast3=' brd 10.4.3.31',
peer1=' peer 10.5.1.102/24',
peer2='/24 brd 10.5.2.255',
peer3=' peer 10.5.3.102/24',
peer4=' peer 2001:db8:0:f103::201/128',
peer5='/128',
peer6=' peer 2001:db8:0:f103::203/128',
scope1='link',
scope2='global',
deprecated1=' deprecated',
deprecated2='',
deprecated3=' deprecated',
deprecated4='',
route_metric=256,
flag1='',
flag2=' noprefixroute',
flag3=' home mngtmpaddr',
flag4=' noprefixroute',
)
networkctl_reconfigure('dummy98')
self.wait_online(['dummy98:routable'])
self.verify_address_static(route_metric=256)
self.verify_address_static(
label1='new-label1',
label2='dummy98',
label3='new-label3',
broadcast1=' brd 10.4.1.255',
broadcast2='',
broadcast3=' brd 10.4.3.31',
peer1=' peer 10.5.1.102/24',
peer2='/24 brd 10.5.2.255',
peer3=' peer 10.5.3.102/24',
peer4=' peer 2001:db8:0:f103::201/128',
peer5='/128',
peer6=' peer 2001:db8:0:f103::203/128',
scope1='link',
scope2='global',
deprecated1=' deprecated',
deprecated2='',
deprecated3=' deprecated',
deprecated4='',
route_metric=256,
flag1='',
flag2=' noprefixroute',
flag3=' home mngtmpaddr',
flag4=' noprefixroute',
)
# Tests for #20891.
# 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
check_output('ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever')
check_output('ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever')
output = check_output('ip -4 address show dev dummy98')
check_output('ip address change 10.7.1.1/24 dev dummy98 preferred_lft forever')
check_output('ip address change 2001:db8:0:f104::1/64 dev dummy98 preferred_lft forever')
output = check_output('ip address show dev dummy98')
print(output)
self.assertNotIn('deprecated', output)
output = check_output('ip -6 address show dev dummy98')
print(output)
self.assertNotIn('deprecated', output)
self.assertNotRegex(output, '10.7.1.1/24 .* deprecated')
self.assertNotRegex(output, '2001:db8:0:f104::1/64 .* deprecated')
# 2. reconfigure the interface.
# 2. reconfigure the interface, and check the deprecated flag is set again
networkctl_reconfigure('dummy98')
self.wait_online(['dummy98:routable'])
# 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
output = check_output('ip -4 address show dev dummy98')
print(output)
self.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output)
output = check_output('ip -6 address show dev dummy98')
print(output)
self.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output)
self.verify_address_static(
label1='new-label1',
label2='dummy98',
label3='new-label3',
broadcast1=' brd 10.4.1.255',
broadcast2='',
broadcast3=' brd 10.4.3.31',
peer1=' peer 10.5.1.102/24',
peer2='/24 brd 10.5.2.255',
peer3=' peer 10.5.3.102/24',
peer4=' peer 2001:db8:0:f103::201/128',
peer5='/128',
peer6=' peer 2001:db8:0:f103::203/128',
scope1='link',
scope2='global',
deprecated1=' deprecated',
deprecated2='',
deprecated3=' deprecated',
deprecated4='',
route_metric=256,
flag1='',
flag2=' noprefixroute',
flag3=' home mngtmpaddr',
flag4=' noprefixroute',
)
# test for ENOBUFS issue #17012 (with reload)
copy_network_unit('25-address-static.network.d/10-many-address.conf')