1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-11 05:17:44 +03:00

Merge pull request #21585 from yuwata/network-radv-uplink-interface-auto-with-dhcp6-pd

network: cleanups for uplink interface handling for RADV and DHCP6-PD
This commit is contained in:
Yu Watanabe 2021-12-02 08:16:23 +09:00 committed by GitHub
commit bf1e65a4fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 220 additions and 86 deletions

View File

@ -2106,11 +2106,12 @@ Table=1234</programlisting></para>
<listitem> <listitem>
<para>Allows DHCPv6 client to start without router advertisements's managed or other <para>Allows DHCPv6 client to start without router advertisements's managed or other
address configuration flag. Takes one of <literal>no</literal>, <literal>solicit</literal> address configuration flag. Takes one of <literal>no</literal>, <literal>solicit</literal>
or <literal>information-request</literal>. When this is not specified and or <literal>information-request</literal>. If this is not specified,
<varname>UplinkInterface=:self</varname> is specified, then <literal>solicit</literal> is <literal>solicit</literal> is used when <varname>DHCPv6PrefixDelegation=</varname> is
implied. Otherwise, defaults to <literal>no</literal>, and the DHCPv6 client will be enabled and <varname>UplinkInterface=:self</varname> is specified in the
started when an RA is received. See also <varname>DHCPv6Client=</varname> setting in the [DHCPv6PrefixDelegation] section. Otherwise, defaults to <literal>no</literal>, and the
[IPv6AcceptRA] section.</para> DHCPv6 client will be started when an RA is received. See also
<varname>DHCPv6Client=</varname> setting in the [IPv6AcceptRA] section.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
@ -2711,9 +2712,11 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
<listitem><para>Specifies the name or the index of the uplink interface, or one of the special <listitem><para>Specifies the name or the index of the uplink interface, or one of the special
values <literal>:none</literal> and <literal>:auto</literal>. When emitting DNS servers or values <literal>:none</literal> and <literal>:auto</literal>. When emitting DNS servers or
search domains is enabled but no servers are specified, the servers configured in the uplink search domains is enabled but no servers are specified, the servers configured in the uplink
interface will be emitted. When <literal>:auto</literal>, the link which has a default gateway interface will be emitted. When <literal>:auto</literal>, the value specified to the same
with the highest priority will be automatically selected. When <literal>:none</literal>, no setting in the [DHCPv6PrefixDelegation] section will be used if
uplink interface will be selected. Defaults to <literal>:auto</literal>.</para></listitem> <varname>DHCPv6PrefixDelegation=</varname> is enabled, otherwise the link which has a default
gateway with the highest priority will be automatically selected. When <literal>:none</literal>,
no uplink interface will be selected. Defaults to <literal>:auto</literal>.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -42,25 +42,28 @@ bool link_dhcp6_pd_is_enabled(Link *link) {
return link->network->dhcp6_pd; return link->network->dhcp6_pd;
} }
static int dhcp6_pd_resolve_uplink(Link *link, Link **ret) { static bool dhcp6_pd_is_uplink(Link *link, Link *target, bool accept_auto) {
assert(link);
assert(target);
if (!link_dhcp6_pd_is_enabled(link))
return false;
if (link->network->dhcp6_pd_uplink_name) if (link->network->dhcp6_pd_uplink_name)
return link_get_by_name(link->manager, link->network->dhcp6_pd_uplink_name, ret); return streq_ptr(target->ifname, link->network->dhcp6_pd_uplink_name) ||
strv_contains(target->alternative_names, link->network->dhcp6_pd_uplink_name);
if (link->network->dhcp6_pd_uplink_index > 0) if (link->network->dhcp6_pd_uplink_index > 0)
return link_get_by_index(link->manager, link->network->dhcp6_pd_uplink_index, ret); return target->ifindex == link->network->dhcp6_pd_uplink_index;
if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF) { if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF)
*ret = link; return link == target;
return 0;
}
assert(link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_AUTO); assert(link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_AUTO);
return -ENOENT; return accept_auto;
} }
static DHCP6ClientStartMode link_get_dhcp6_client_start_mode(Link *link) { static DHCP6ClientStartMode link_get_dhcp6_client_start_mode(Link *link) {
Link *uplink;
assert(link); assert(link);
if (!link->network) if (!link->network)
@ -70,11 +73,12 @@ static DHCP6ClientStartMode link_get_dhcp6_client_start_mode(Link *link) {
if (link->network->dhcp6_client_start_mode >= 0) if (link->network->dhcp6_client_start_mode >= 0)
return link->network->dhcp6_client_start_mode; return link->network->dhcp6_client_start_mode;
if (dhcp6_pd_resolve_uplink(link, &uplink) < 0) /* When this interface itself is an uplink interface, then start dhcp6 client in managed mode. */
return DHCP6_CLIENT_START_MODE_NO; if (dhcp6_pd_is_uplink(link, link, /* accept_auto = */ false))
return DHCP6_CLIENT_START_MODE_SOLICIT;
/* When this interface itself is an uplink interface, then start dhcp6 client in managed mode */ /* Otherwise, start dhcp6 client when RA is received. */
return uplink == link ? DHCP6_CLIENT_START_MODE_SOLICIT : DHCP6_CLIENT_START_MODE_NO; return DHCP6_CLIENT_START_MODE_NO;
} }
static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) { static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
@ -527,13 +531,20 @@ static int dhcp6_pd_get_preferred_prefix(
} }
for (uint64_t n = 0; ; n++) { for (uint64_t n = 0; ; n++) {
/* If we do not have an allocation preference just iterate
* through the address space and return the first free prefix. */
r = dhcp6_pd_calculate_prefix(pd_prefix, pd_prefix_len, n, &prefix); r = dhcp6_pd_calculate_prefix(pd_prefix, pd_prefix_len, n, &prefix);
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, return log_link_warning_errno(link, r,
"Couldn't find a suitable prefix. Ran out of address space."); "Couldn't find a suitable prefix. Ran out of address space.");
/* If we do not have an allocation preference just iterate /* Do not use explicitly requested subnet IDs. Note that the corresponding link may not
* through the address space and return the first free prefix. */ * appear yet. So, we need to check the ID is not used in any .network files. */
if (set_contains(link->manager->dhcp6_pd_subnet_ids, &n))
continue;
/* Check that the prefix is not assigned to another link. */
if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix, &assigned_link) < 0 || if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix, &assigned_link) < 0 ||
assigned_link == link) { assigned_link == link) {
*ret = prefix; *ret = prefix;
@ -598,8 +609,7 @@ static int dhcp6_pd_distribute_prefix(
const struct in6_addr *pd_prefix, const struct in6_addr *pd_prefix,
uint8_t pd_prefix_len, uint8_t pd_prefix_len,
usec_t lifetime_preferred_usec, usec_t lifetime_preferred_usec,
usec_t lifetime_valid_usec, usec_t lifetime_valid_usec) {
bool assign_preferred_subnet_id) {
Link *link; Link *link;
int r; int r;
@ -610,12 +620,10 @@ static int dhcp6_pd_distribute_prefix(
assert(pd_prefix_len <= 64); assert(pd_prefix_len <= 64);
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) { HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
Link *uplink;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue; continue;
if (!link_dhcp6_pd_is_enabled(link)) if (!dhcp6_pd_is_uplink(link, dhcp6_link, /* accept_auto = */ true))
continue; continue;
if (link->network->dhcp6_pd_announce && !link->radv) if (link->network->dhcp6_pd_announce && !link->radv)
@ -624,18 +632,6 @@ static int dhcp6_pd_distribute_prefix(
if (link == dhcp6_link && !link->network->dhcp6_pd_assign) if (link == dhcp6_link && !link->network->dhcp6_pd_assign)
continue; continue;
if (assign_preferred_subnet_id != link_has_preferred_subnet_id(link))
continue;
r = dhcp6_pd_resolve_uplink(link, &uplink);
if (r != -ENOENT) {
if (r < 0) /* The uplink interface does not exist yet. */
continue;
if (uplink != dhcp6_link)
continue;
}
r = dhcp6_pd_assign_prefix(link, pd_prefix, pd_prefix_len, lifetime_preferred_usec, lifetime_valid_usec); r = dhcp6_pd_assign_prefix(link, pd_prefix, pd_prefix_len, lifetime_preferred_usec, lifetime_valid_usec);
if (r < 0) { if (r < 0) {
if (link == dhcp6_link) if (link == dhcp6_link)
@ -985,17 +981,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
&pd_prefix, &pd_prefix,
pd_prefix_len, pd_prefix_len,
lifetime_preferred_usec, lifetime_preferred_usec,
lifetime_valid_usec, lifetime_valid_usec);
true);
if (r < 0)
return r;
r = dhcp6_pd_distribute_prefix(dhcp6_link,
&pd_prefix,
pd_prefix_len,
lifetime_preferred_usec,
lifetime_valid_usec,
false);
if (r < 0) if (r < 0)
return r; return r;
} }
@ -1452,28 +1438,38 @@ static bool dhcp6_pd_uplink_is_ready(Link *link) {
return dhcp6_lease_has_pd_prefix(link->dhcp6_lease); return dhcp6_lease_has_pd_prefix(link->dhcp6_lease);
} }
static int dhcp6_pd_find_uplink(Link *link, Link **ret) { int dhcp6_pd_find_uplink(Link *link, Link **ret) {
Link *l; Link *uplink = NULL;
int r = 0;
assert(link); assert(link);
assert(link->manager); assert(link->manager);
assert(link->network); assert(link_dhcp6_pd_is_enabled(link));
assert(ret); assert(ret);
if (dhcp6_pd_resolve_uplink(link, &l) >= 0) { if (link->network->dhcp6_pd_uplink_name)
if (!dhcp6_pd_uplink_is_ready(l)) r = link_get_by_name(link->manager, link->network->dhcp6_pd_uplink_name, &uplink);
else if (link->network->dhcp6_pd_uplink_index > 0)
r = link_get_by_index(link->manager, link->network->dhcp6_pd_uplink_index, &uplink);
else if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF)
uplink = link;
if (r < 0)
return r;
if (uplink) {
if (!dhcp6_pd_uplink_is_ready(uplink))
return -EBUSY; return -EBUSY;
*ret = l; *ret = uplink;
return 0; return 0;
} }
HASHMAP_FOREACH(l, link->manager->links_by_index) { HASHMAP_FOREACH(uplink, link->manager->links_by_index) {
if (!dhcp6_pd_uplink_is_ready(l)) if (!dhcp6_pd_uplink_is_ready(uplink))
continue; continue;
/* Assume that there exists at most one link which acquired delegated prefixes. */ /* Assume that there exists at most one link which acquired delegated prefixes. */
*ret = l; *ret = uplink;
return 0; return 0;
} }

View File

@ -18,6 +18,7 @@ typedef struct Request Request;
bool link_dhcp6_with_address_enabled(Link *link); bool link_dhcp6_with_address_enabled(Link *link);
bool link_dhcp6_pd_is_enabled(Link *link); bool link_dhcp6_pd_is_enabled(Link *link);
int dhcp6_pd_find_uplink(Link *link, Link **ret);
int dhcp6_pd_remove(Link *link, bool only_marked); int dhcp6_pd_remove(Link *link, bool only_marked);
int dhcp6_update_mac(Link *link); int dhcp6_update_mac(Link *link);
int dhcp6_start(Link *link); int dhcp6_start(Link *link);

View File

@ -502,6 +502,7 @@ Manager* manager_free(Manager *m) {
m->links_by_dhcp6_pd_prefix = hashmap_free(m->links_by_dhcp6_pd_prefix); m->links_by_dhcp6_pd_prefix = hashmap_free(m->links_by_dhcp6_pd_prefix);
m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref); m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
m->dhcp6_pd_subnet_ids = set_free(m->dhcp6_pd_subnet_ids);
m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref); m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref); m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
@ -585,7 +586,7 @@ int manager_load_config(Manager *m) {
if (r < 0) if (r < 0)
return r; return r;
return 0; return manager_build_dhcp6_pd_subnet_ids(m);
} }
bool manager_should_reload(Manager *m) { bool manager_should_reload(Manager *m) {

View File

@ -52,6 +52,7 @@ struct Manager {
Hashmap *netdevs; Hashmap *netdevs;
OrderedHashmap *networks; OrderedHashmap *networks;
OrderedSet *address_pools; OrderedSet *address_pools;
Set *dhcp6_pd_subnet_ids;
usec_t network_dirs_ts_usec; usec_t network_dirs_ts_usec;

View File

@ -643,7 +643,7 @@ int network_reload(Manager *manager) {
ordered_hashmap_free_with_destructor(manager->networks, network_unref); ordered_hashmap_free_with_destructor(manager->networks, network_unref);
manager->networks = new_networks; manager->networks = new_networks;
return 0; return manager_build_dhcp6_pd_subnet_ids(manager);
failure: failure:
ordered_hashmap_free_with_destructor(new_networks, network_unref); ordered_hashmap_free_with_destructor(new_networks, network_unref);
@ -651,6 +651,32 @@ failure:
return r; return r;
} }
int manager_build_dhcp6_pd_subnet_ids(Manager *manager) {
Network *n;
int r;
assert(manager);
set_clear(manager->dhcp6_pd_subnet_ids);
ORDERED_HASHMAP_FOREACH(n, manager->networks) {
if (n->unmanaged)
continue;
if (!n->dhcp6_pd)
continue;
if (n->dhcp6_pd_subnet_id < 0)
continue;
r = set_ensure_put(&manager->dhcp6_pd_subnet_ids, &uint64_hash_ops, &n->dhcp6_pd_subnet_id);
if (r < 0)
return r;
}
return 0;
}
static Network *network_free(Network *network) { static Network *network_free(Network *network) {
if (!network) if (!network)
return NULL; return NULL;

View File

@ -365,6 +365,8 @@ int network_reload(Manager *manager);
int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename); int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename);
int network_verify(Network *network); int network_verify(Network *network);
int manager_build_dhcp6_pd_subnet_ids(Manager *manager);
int network_get_by_name(Manager *manager, const char *name, Network **ret); int network_get_by_name(Manager *manager, const char *name, Network **ret);
void network_apply_anonymize_if_set(Network *network); void network_apply_anonymize_if_set(Network *network);

View File

@ -410,6 +410,8 @@ set_domains:
} }
static int radv_find_uplink(Link *link, Link **ret) { static int radv_find_uplink(Link *link, Link **ret) {
int r;
assert(link); assert(link);
if (link->network->router_uplink_name) if (link->network->router_uplink_name)
@ -419,8 +421,12 @@ static int radv_find_uplink(Link *link, Link **ret) {
return link_get_by_index(link->manager, link->network->router_uplink_index, ret); return link_get_by_index(link->manager, link->network->router_uplink_index, ret);
if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) { if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) {
/* It is not necessary to propagate error in automatic selection. */ if (link_dhcp6_pd_is_enabled(link))
if (manager_find_uplink(link->manager, AF_INET6, link, ret) < 0) r = dhcp6_pd_find_uplink(link, ret); /* When DHCPv6PD is enabled, use its uplink. */
else
r = manager_find_uplink(link->manager, AF_INET6, link, ret);
if (r < 0)
/* It is not necessary to propagate error in automatic selection. */
*ret = NULL; *ret = NULL;
return 0; return 0;
} }

View File

@ -0,0 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[NetDev]
Name=veth97
Kind=veth
MACAddress=12:34:56:78:9a:ce
[Peer]
Name=veth97-peer
MACAddress=12:34:56:78:9a:cf

View File

@ -10,7 +10,7 @@ DHCPv6PrefixDelegation=yes
[DHCPv6PrefixDelegation] [DHCPv6PrefixDelegation]
UplinkInterface=veth99 UplinkInterface=veth99
SubnetId=6 SubnetId=1
Announce=no Announce=no
Token=eui64 Token=eui64
Token=::1a:2b:3c:4d Token=::1a:2b:3c:4d

View File

@ -10,7 +10,7 @@ DHCPv6PrefixDelegation=yes
[DHCPv6PrefixDelegation] [DHCPv6PrefixDelegation]
UplinkInterface=veth99 UplinkInterface=veth99
SubnetId=3 SubnetId=2
Announce=no Announce=no
Token=eui64 Token=eui64
Token=::1a:2b:3c:4d Token=::1a:2b:3c:4d

View File

@ -0,0 +1,11 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=veth97-peer
[Network]
IPv6PrivacyExtensions=yes
IPv6AcceptRA=yes
[IPv6AcceptRA]
Token=eui64
Token=::1a:2b:3c:4e

View File

@ -0,0 +1,20 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=veth97
[Network]
IPv6PrivacyExtensions=yes
IPv6AcceptRA=no
DHCP=no
DHCPv6PrefixDelegation=yes
IPv6SendRA=yes
[DHCPv6PrefixDelegation]
SubnetId=8
Announce=yes
Token=eui64
Token=::1a:2b:3c:4d
[IPv6SendRA]
EmitDNS=no
EmitDomains=no

View File

@ -17,6 +17,5 @@ Token=eui64
Token=::1a:2b:3c:4d Token=::1a:2b:3c:4d
[IPv6SendRA] [IPv6SendRA]
UplinkInterface=:none
EmitDNS=no EmitDNS=no
EmitDomains=no EmitDomains=no

View File

@ -5002,6 +5002,7 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
'dummy98', 'dummy98',
'dummy99', 'dummy99',
'test1', 'test1',
'veth97',
'veth98', 'veth98',
'veth99', 'veth99',
] ]
@ -5011,11 +5012,14 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
'12-dummy.netdev', '12-dummy.netdev',
'13-dummy.netdev', '13-dummy.netdev',
'25-veth.netdev', '25-veth.netdev',
'25-veth-downstream.netdev', '25-veth-downstream-veth97.netdev',
'25-veth-downstream-veth98.netdev',
'dhcp6pd-downstream-dummy97.network', 'dhcp6pd-downstream-dummy97.network',
'dhcp6pd-downstream-dummy98.network', 'dhcp6pd-downstream-dummy98.network',
'dhcp6pd-downstream-dummy99.network', 'dhcp6pd-downstream-dummy99.network',
'dhcp6pd-downstream-test1.network', 'dhcp6pd-downstream-test1.network',
'dhcp6pd-downstream-veth97.network',
'dhcp6pd-downstream-veth97-peer.network',
'dhcp6pd-downstream-veth98.network', 'dhcp6pd-downstream-veth98.network',
'dhcp6pd-downstream-veth98-peer.network', 'dhcp6pd-downstream-veth98-peer.network',
'dhcp6pd-server.network', 'dhcp6pd-server.network',
@ -5035,7 +5039,8 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
def test_dhcp6pd(self): def test_dhcp6pd(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp6pd-server.network', 'dhcp6pd-upstream.network', copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp6pd-server.network', 'dhcp6pd-upstream.network',
'25-veth-downstream.netdev', 'dhcp6pd-downstream-veth98.network', 'dhcp6pd-downstream-veth98-peer.network', '25-veth-downstream-veth97.netdev', 'dhcp6pd-downstream-veth97.network', 'dhcp6pd-downstream-veth97-peer.network',
'25-veth-downstream-veth98.netdev', 'dhcp6pd-downstream-veth98.network', 'dhcp6pd-downstream-veth98-peer.network',
'11-dummy.netdev', 'dhcp6pd-downstream-test1.network', '11-dummy.netdev', 'dhcp6pd-downstream-test1.network',
'dhcp6pd-downstream-dummy97.network', 'dhcp6pd-downstream-dummy97.network',
'12-dummy.netdev', 'dhcp6pd-downstream-dummy98.network', '12-dummy.netdev', 'dhcp6pd-downstream-dummy98.network',
@ -5045,13 +5050,24 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
self.wait_online(['veth-peer:carrier']) self.wait_online(['veth-peer:carrier'])
start_isc_dhcpd('veth-peer', 'isc-dhcpd-dhcp6pd.conf') start_isc_dhcpd('veth-peer', 'isc-dhcpd-dhcp6pd.conf')
self.wait_online(['veth-peer:routable', 'veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded', self.wait_online(['veth-peer:routable', 'veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
'veth98:routable', 'veth98-peer:routable']) 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
print('### ip -6 address show dev veth-peer scope global') print('### ip -6 address show dev veth-peer scope global')
output = check_output('ip -6 address show dev veth-peer scope global') output = check_output('ip -6 address show dev veth-peer scope global')
print(output) print(output)
self.assertIn('inet6 3ffe:501:ffff:100::1/64 scope global', output) self.assertIn('inet6 3ffe:501:ffff:100::1/64 scope global', output)
'''
Link Subnet IDs
test1: 0x00
dummy97: 0x01 (The link will appear later)
dummy98: 0x02
dummy99: auto -> 0x03 (No address assignment)
veth97: 0x08
veth98: 0x09
veth99: 0x10
'''
print('### ip -6 address show dev veth99 scope global') print('### ip -6 address show dev veth99 scope global')
output = check_output('ip -6 address show dev veth99 scope global') output = check_output('ip -6 address show dev veth99 scope global')
print(output) print(output)
@ -5077,9 +5093,35 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
output = check_output('ip -6 address show dev dummy98 scope global') output = check_output('ip -6 address show dev dummy98 scope global')
print(output) print(output)
# address in IA_PD (Token=static) # address in IA_PD (Token=static)
self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]03:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
# address in IA_PD (temporary) # address in IA_PD (temporary)
self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]03:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
print('### ip -6 address show dev dummy99 scope global')
output = check_output('ip -6 address show dev dummy99 scope global')
print(output)
# Assign=no
self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]03')
print('### ip -6 address show dev veth97 scope global')
output = check_output('ip -6 address show dev veth97 scope global')
print(output)
# address in IA_PD (Token=static)
self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
# address in IA_PD (Token=eui64)
self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
# address in IA_PD (temporary)
self.wait_address('veth97', 'inet6 3ffe:501:ffff:[2-9a-f]08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
print('### ip -6 address show dev veth97-peer scope global')
output = check_output('ip -6 address show dev veth97-peer scope global')
print(output)
# NDisc address (Token=static)
self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
# NDisc address (Token=eui64)
self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
# NDisc address (temporary)
self.wait_address('veth97-peer', 'inet6 3ffe:501:ffff:[2-9a-f]08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
print('### ip -6 address show dev veth98 scope global') print('### ip -6 address show dev veth98 scope global')
output = check_output('ip -6 address show dev veth98 scope global') output = check_output('ip -6 address show dev veth98 scope global')
@ -5101,10 +5143,6 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
# NDisc address (temporary) # NDisc address (temporary)
self.wait_address('veth98-peer', 'inet6 3ffe:501:ffff:[2-9a-f]09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') self.wait_address('veth98-peer', 'inet6 3ffe:501:ffff:[2-9a-f]09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
print('### ip -6 address show dev dummy99 scope global')
output = check_output('ip -6 address show dev dummy98 scope global')
print(output)
print('### ip -6 route show type unreachable') print('### ip -6 route show type unreachable')
output = check_output('ip -6 route show type unreachable') output = check_output('ip -6 route show type unreachable')
print(output) print(output)
@ -5123,12 +5161,22 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
print('### ip -6 route show dev dummy98') print('### ip -6 route show dev dummy98')
output = check_output('ip -6 route show dev dummy98') output = check_output('ip -6 route show dev dummy98')
print(output) print(output)
self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]03::/64 proto kernel metric [0-9]* expires') self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto kernel metric [0-9]* expires')
print('### ip -6 route show dev dummy99') print('### ip -6 route show dev dummy99')
output = check_output('ip -6 route show dev dummy99') output = check_output('ip -6 route show dev dummy99')
print(output) print(output)
self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]01::/64 proto dhcp metric [0-9]* expires') self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]03::/64 proto dhcp metric [0-9]* expires')
print('### ip -6 route show dev veth97')
output = check_output('ip -6 route show dev veth97')
print(output)
self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires')
print('### ip -6 route show dev veth97-peer')
output = check_output('ip -6 route show dev veth97-peer')
print(output)
self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires')
print('### ip -6 route show dev veth98') print('### ip -6 route show dev veth98')
output = check_output('ip -6 route show dev veth98') output = check_output('ip -6 route show dev veth98')
@ -5148,31 +5196,42 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
output = check_output('ip -6 address show dev dummy97 scope global') output = check_output('ip -6 address show dev dummy97 scope global')
print(output) print(output)
# address in IA_PD (Token=static) # address in IA_PD (Token=static)
self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]06:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
# address in IA_PD (temporary) # address in IA_PD (temporary)
self.wait_address('dummy97', 'inet6 3ffe:501:ffff:[2-9a-f]06:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') self.wait_address('dummy97', 'inet6 3ffe:501:ffff:[2-9a-f]01:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
print('### ip -6 route show dev dummy97') print('### ip -6 route show dev dummy97')
output = check_output('ip -6 route show dev dummy97') output = check_output('ip -6 route show dev dummy97')
print(output) print(output)
self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]06::/64 proto kernel metric [0-9]* expires') self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires')
# Test case for reconfigure # Test case for reconfigure
check_output(*networkctl_cmd, 'reconfigure', 'dummy98', env=env) check_output(*networkctl_cmd, 'reconfigure', 'dummy98', 'dummy99', env=env)
self.wait_online(['dummy98:routable']) self.wait_online(['dummy98:routable'])
print('### ip -6 address show dev dummy98 scope global') print('### ip -6 address show dev dummy98 scope global')
output = check_output('ip -6 address show dev dummy98 scope global') output = check_output('ip -6 address show dev dummy98 scope global')
print(output) print(output)
# address in IA_PD (Token=static) # address in IA_PD (Token=static)
self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]03:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
# address in IA_PD (temporary) # address in IA_PD (temporary)
self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]03:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
print('### ip -6 address show dev dummy99 scope global')
output = check_output('ip -6 address show dev dummy99 scope global')
print(output)
# Assign=no
self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]03')
print('### ip -6 route show dev dummy98') print('### ip -6 route show dev dummy98')
output = check_output('ip -6 route show dev dummy98') output = check_output('ip -6 route show dev dummy98')
print(output) print(output)
self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]03::/64 proto kernel metric [0-9]* expires') self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto kernel metric [0-9]* expires')
print('### ip -6 route show dev dummy99')
output = check_output('ip -6 route show dev dummy99')
print(output)
self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]03::/64 proto dhcp metric [0-9]* expires')
class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities): class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
links = [ links = [