1
0
mirror of https://github.com/systemd/systemd synced 2026-04-09 16:44:51 +02:00

Compare commits

..

16 Commits

Author SHA1 Message Date
Yu Watanabe
bf1e65a4fd
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
2021-12-02 08:16:23 +09:00
Yu Watanabe
9db6a416dd
Merge pull request #21583 from bluca/bpf_assert
cgroup: don't emit BPF firewall warning when manager is in test mode
2021-12-02 07:47:17 +09:00
Luca Boccassi
6b88743c22
Merge pull request #21591 from yuwata/core-bpf-firewall-unsupported-reason
core/bpf-firewall: make bpf_firewall_supported() always set unsupport…
2021-12-01 21:20:30 +00:00
Luca Boccassi
541b127170 elf-util: do not ignore prctl() errors
We want to avoid loops, so fail and return if we can't disable
core dumping

CID#1467004
2021-12-01 16:00:26 +00:00
Yu Watanabe
a783421498 tree-wide: fix typo 2021-12-02 00:51:02 +09:00
Yu Watanabe
8751bb6f5e core/bpf-firewall: make bpf_firewall_supported() always set unsupported reason when BPF_FIREWALL_UNSUPPORTED is returned
Otherwise, log_unit_full_errno() in emit_bpf_firewall_warning() will
trigger an assertion.
2021-12-01 21:39:21 +09:00
Yu Watanabe
ad13559e8d core/cgroup: propagate errors on detecting supported features 2021-12-01 21:39:21 +09:00
Yu Watanabe
3de3fd3d16 core/restrict-netif: make restrict_network_interfaces_supported() return negative errno only when critical error
Other errors are handled as the functionality is not supported.

This also drops unnecessary SYNTHETIC_ERRNO().
2021-12-01 21:38:54 +09:00
Luca Boccassi
cb94244406 test: run commands with debug level logs in TEST-65-ANALYZE 2021-12-01 12:06:36 +00:00
Luca Boccassi
a42232a18c cgroup: don't emit BPF firewall warning when manager is in test mode
Support for BPF might not have been checked, since it's not necessary
in test mode (eg: running offline analysis of units). This causes an
assert:

Assertion '(_error) != 0' failed at src/core/bpf-firewall.c:914, function emit_bpf_firewall_warning(). Aborting.

Export SYSTEMD_LOG_LEVEl=debug in TEST-65-ANALYZE is enough to trigger
this assert while doing an offline analysis of a unit that has some
firewall/network restrictions set.

Skip the warning if the manager is in test mode.
2021-12-01 12:06:36 +00:00
Yu Watanabe
6016f1cfbb test-network: re-arrange DHCP6-PD subnet IDs to test searching free subnet ID 2021-12-01 20:35:03 +09:00
Yu Watanabe
6c8d6bdd40 test-network: add testcases for uplink interface detection for RADV with DHCPv6-PD 2021-12-01 20:35:03 +09:00
Yu Watanabe
1a4ca0e2f3 network: dhcp6-pd: exclude all explicitly specified subnet IDs when searching free IDs
When the upstream link gained a lease, then several downstream links may
not appear yet. Previously, the explicitly specified subnet ID for a
downstream link which appears later may be already assigned to an
interface which does not request specific subnet ID.

To avoid such situation, this makes all specified IDs are excluded when
searching free IDs.

As a side effect, we can avoid the second call of
dhcp6_pd_distribute_prefix().
2021-12-01 20:35:03 +09:00
Yu Watanabe
a74229c58e network: dhcp6-pd: introduce dhcp6_pd_is_uplink()
This also merges dhcp6_pd_resolve_uplink() with dhcp6_pd_find_uplink()
2021-12-01 20:35:03 +09:00
Yu Watanabe
926fc8ee63 network: dhcp6: make UplinkInterface=:self take effect only when DHCPv6PrefixDelegation= is enabled 2021-12-01 20:35:03 +09:00
Yu Watanabe
f6032ff3e0 network: radv: use the uplink interface used in DHCPv6-PD 2021-12-01 20:35:03 +09:00
23 changed files with 263 additions and 112 deletions

View File

@ -38,8 +38,8 @@ manager, please consider supporting the following interfaces.
3. Pre-mount `/dev/` as (container private) `tmpfs` for the container and bind
mount some suitable TTY to `/dev/console`. If this is a pty, make sure to not
close the controling pty master during systemd's lifetime. PID1 will close ttys,
to avoid being killed by SAK. It only opens ttys for the time it
close the controlling pty master during systemd's lifetime. PID1 will close
ttys, to avoid being killed by SAK. It only opens ttys for the time it
actually needs to print something. Also, make sure to create device
nodes for `/dev/null`, `/dev/zero`, `/dev/full`, `/dev/random`,
`/dev/urandom`, `/dev/tty`, `/dev/ptmx` in `/dev/`. It is not necessary to

View File

@ -2106,11 +2106,12 @@ Table=1234</programlisting></para>
<listitem>
<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>
or <literal>information-request</literal>. When this is not specified and
<varname>UplinkInterface=:self</varname> is specified, then <literal>solicit</literal> is
implied. Otherwise, defaults to <literal>no</literal>, and the DHCPv6 client will be
started when an RA is received. See also <varname>DHCPv6Client=</varname> setting in the
[IPv6AcceptRA] section.</para>
or <literal>information-request</literal>. If this is not specified,
<literal>solicit</literal> is used when <varname>DHCPv6PrefixDelegation=</varname> is
enabled and <varname>UplinkInterface=:self</varname> is specified in the
[DHCPv6PrefixDelegation] section. Otherwise, defaults to <literal>no</literal>, and the
DHCPv6 client will be started when an RA is received. See also
<varname>DHCPv6Client=</varname> setting in the [IPv6AcceptRA] section.</para>
</listitem>
</varlistentry>
</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
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
interface will be emitted. When <literal>:auto</literal>, 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>
interface will be emitted. When <literal>:auto</literal>, the value specified to the same
setting in the [DHCPv6PrefixDelegation] section will be used if
<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>

View File

@ -28,7 +28,7 @@ if efi_arch.length() == 0
if get_option('gnu-efi') == 'true'
error('gnu-efi support requested, but headers not found or efi arch is unknown')
endif
warning('gnu-efi headers not found or efi arch is unkown, disabling gnu-efi support')
warning('gnu-efi headers not found or efi arch is unknown, disabling gnu-efi support')
subdir_done()
endif

View File

@ -872,7 +872,10 @@ int bpf_firewall_supported(void) {
/* YAY! */
} else {
log_debug("Wut? Kernel accepted our invalid BPF_PROG_DETACH call? Something is weird, assuming BPF firewalling is broken and hence not supported.");
bpf_firewall_unsupported_reason =
log_debug_errno(SYNTHETIC_ERRNO(EBADE),
"Wut? Kernel accepted our invalid BPF_PROG_DETACH call? "
"Something is weird, assuming BPF firewalling is broken and hence not supported.");
return supported = BPF_FIREWALL_UNSUPPORTED;
}
@ -900,7 +903,10 @@ int bpf_firewall_supported(void) {
return supported = BPF_FIREWALL_SUPPORTED;
} else {
log_debug("Wut? Kernel accepted our invalid BPF_PROG_ATTACH+BPF_F_ALLOW_MULTI call? Something is weird, assuming BPF firewalling is broken and hence not supported.");
bpf_firewall_unsupported_reason =
log_debug_errno(SYNTHETIC_ERRNO(EBADE),
"Wut? Kernel accepted our invalid BPF_PROG_ATTACH+BPF_F_ALLOW_MULTI call? "
"Something is weird, assuming BPF firewalling is broken and hence not supported.");
return supported = BPF_FIREWALL_UNSUPPORTED;
}
}
@ -908,7 +914,10 @@ int bpf_firewall_supported(void) {
void emit_bpf_firewall_warning(Unit *u) {
static bool warned = false;
if (!warned) {
assert(u);
assert(u->manager);
if (!warned && !MANAGER_IS_TEST_RUN(u->manager)) {
bool quiet = bpf_firewall_unsupported_reason == -EPERM && detect_container() > 0;
log_unit_full_errno(u, quiet ? LOG_DEBUG : LOG_WARNING, bpf_firewall_unsupported_reason,

View File

@ -3228,26 +3228,36 @@ static int cg_bpf_mask_supported(CGroupMask *ret) {
/* BPF-based firewall */
r = bpf_firewall_supported();
if (r < 0)
return r;
if (r > 0)
mask |= CGROUP_MASK_BPF_FIREWALL;
/* BPF-based device access control */
r = bpf_devices_supported();
if (r < 0)
return r;
if (r > 0)
mask |= CGROUP_MASK_BPF_DEVICES;
/* BPF pinned prog */
r = bpf_foreign_supported();
if (r < 0)
return r;
if (r > 0)
mask |= CGROUP_MASK_BPF_FOREIGN;
/* BPF-based bind{4|6} hooks */
r = bpf_socket_bind_supported();
if (r < 0)
return r;
if (r > 0)
mask |= CGROUP_MASK_BPF_SOCKET_BIND;
/* BPF-based cgroup_skb/{egress|ingress} hooks */
r = restrict_network_interfaces_supported();
if (r < 0)
return r;
if (r > 0)
mask |= CGROUP_MASK_BPF_RESTRICT_NETWORK_INTERFACES;

View File

@ -66,41 +66,35 @@ static int prepare_restrict_ifaces_bpf(Unit* u, bool is_allow_list,
int restrict_network_interfaces_supported(void) {
_cleanup_(restrict_ifaces_bpf_freep) struct restrict_ifaces_bpf *obj = NULL;
int r;
static int supported = -1;
int r;
if (supported >= 0)
return supported;
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
if (r < 0) {
log_warning_errno(r, "Can't determine whether the unified hierarchy is used: %m");
supported = 0;
return supported;
}
if (r < 0)
return log_error_errno(r, "Can't determine whether the unified hierarchy is used: %m");
if (r == 0) {
log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Not running with unified cgroup hierarchy, BPF is not supported");
supported = 0;
return supported;
log_debug("Not running with unified cgroup hierarchy, BPF is not supported");
return supported = 0;
}
if (dlopen_bpf() < 0)
return false;
if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SKB, /*ifindex=*/0)) {
log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"BPF program type cgroup_skb is not supported");
supported = 0;
return supported;
log_debug("BPF program type cgroup_skb is not supported");
return supported = 0;
}
r = prepare_restrict_ifaces_bpf(NULL, true, NULL, &obj);
if (r < 0)
return log_debug_errno(r, "Failed to load BPF object: %m");
if (r < 0) {
log_debug_errno(r, "Failed to load BPF object: %m");
return supported = 0;
}
supported = bpf_can_link_program(obj->progs.sd_restrictif_i);
return supported;
return supported = bpf_can_link_program(obj->progs.sd_restrictif_i);
}
static int restrict_network_interfaces_install_impl(Unit *u) {

View File

@ -42,25 +42,28 @@ bool link_dhcp6_pd_is_enabled(Link *link) {
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)
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)
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) {
*ret = link;
return 0;
}
if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF)
return link == target;
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) {
Link *uplink;
assert(link);
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)
return link->network->dhcp6_client_start_mode;
if (dhcp6_pd_resolve_uplink(link, &uplink) < 0)
return DHCP6_CLIENT_START_MODE_NO;
/* When this interface itself is an uplink interface, then start dhcp6 client in managed mode. */
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 */
return uplink == link ? DHCP6_CLIENT_START_MODE_SOLICIT : DHCP6_CLIENT_START_MODE_NO;
/* Otherwise, start dhcp6 client when RA is received. */
return DHCP6_CLIENT_START_MODE_NO;
}
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++) {
/* 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);
if (r < 0)
return log_link_warning_errno(link, r,
"Couldn't find a suitable prefix. Ran out of address space.");
/* If we do not have an allocation preference just iterate
* through the address space and return the first free prefix. */
/* Do not use explicitly requested subnet IDs. Note that the corresponding link may not
* 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 ||
assigned_link == link) {
*ret = prefix;
@ -598,8 +609,7 @@ static int dhcp6_pd_distribute_prefix(
const struct in6_addr *pd_prefix,
uint8_t pd_prefix_len,
usec_t lifetime_preferred_usec,
usec_t lifetime_valid_usec,
bool assign_preferred_subnet_id) {
usec_t lifetime_valid_usec) {
Link *link;
int r;
@ -610,12 +620,10 @@ static int dhcp6_pd_distribute_prefix(
assert(pd_prefix_len <= 64);
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
Link *uplink;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue;
if (!link_dhcp6_pd_is_enabled(link))
if (!dhcp6_pd_is_uplink(link, dhcp6_link, /* accept_auto = */ true))
continue;
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)
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);
if (r < 0) {
if (link == dhcp6_link)
@ -985,17 +981,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
&pd_prefix,
pd_prefix_len,
lifetime_preferred_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);
lifetime_valid_usec);
if (r < 0)
return r;
}
@ -1452,28 +1438,38 @@ static bool dhcp6_pd_uplink_is_ready(Link *link) {
return dhcp6_lease_has_pd_prefix(link->dhcp6_lease);
}
static int dhcp6_pd_find_uplink(Link *link, Link **ret) {
Link *l;
int dhcp6_pd_find_uplink(Link *link, Link **ret) {
Link *uplink = NULL;
int r = 0;
assert(link);
assert(link->manager);
assert(link->network);
assert(link_dhcp6_pd_is_enabled(link));
assert(ret);
if (dhcp6_pd_resolve_uplink(link, &l) >= 0) {
if (!dhcp6_pd_uplink_is_ready(l))
if (link->network->dhcp6_pd_uplink_name)
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;
*ret = l;
*ret = uplink;
return 0;
}
HASHMAP_FOREACH(l, link->manager->links_by_index) {
if (!dhcp6_pd_uplink_is_ready(l))
HASHMAP_FOREACH(uplink, link->manager->links_by_index) {
if (!dhcp6_pd_uplink_is_ready(uplink))
continue;
/* Assume that there exists at most one link which acquired delegated prefixes. */
*ret = l;
*ret = uplink;
return 0;
}

View File

@ -18,6 +18,7 @@ typedef struct Request Request;
bool link_dhcp6_with_address_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_update_mac(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_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->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
@ -585,7 +586,7 @@ int manager_load_config(Manager *m) {
if (r < 0)
return r;
return 0;
return manager_build_dhcp6_pd_subnet_ids(m);
}
bool manager_should_reload(Manager *m) {

View File

@ -52,6 +52,7 @@ struct Manager {
Hashmap *netdevs;
OrderedHashmap *networks;
OrderedSet *address_pools;
Set *dhcp6_pd_subnet_ids;
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);
manager->networks = new_networks;
return 0;
return manager_build_dhcp6_pd_subnet_ids(manager);
failure:
ordered_hashmap_free_with_destructor(new_networks, network_unref);
@ -651,6 +651,32 @@ failure:
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) {
if (!network)
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_verify(Network *network);
int manager_build_dhcp6_pd_subnet_ids(Manager *manager);
int network_get_by_name(Manager *manager, const char *name, Network **ret);
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) {
int r;
assert(link);
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);
if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) {
if (link_dhcp6_pd_is_enabled(link))
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. */
if (manager_find_uplink(link->manager, AF_INET6, link, ret) < 0)
*ret = NULL;
return 0;
}

View File

@ -604,8 +604,11 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
}
if (r == 0) {
/* We want to avoid loops, given this can be called from systemd-coredump */
if (fork_disable_dump)
prctl(PR_SET_DUMPABLE, 0);
if (fork_disable_dump) {
r = RET_NERRNO(prctl(PR_SET_DUMPABLE, 0));
if (r < 0)
goto child_fail;
}
r = parse_core(fd, executable, ret ? &buf : NULL, ret_package_metadata ? &package_metadata : NULL);
if (r < 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]
UplinkInterface=veth99
SubnetId=6
SubnetId=1
Announce=no
Token=eui64
Token=::1a:2b:3c:4d

View File

@ -10,7 +10,7 @@ DHCPv6PrefixDelegation=yes
[DHCPv6PrefixDelegation]
UplinkInterface=veth99
SubnetId=3
SubnetId=2
Announce=no
Token=eui64
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
[IPv6SendRA]
UplinkInterface=:none
EmitDNS=no
EmitDomains=no

View File

@ -5002,6 +5002,7 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
'dummy98',
'dummy99',
'test1',
'veth97',
'veth98',
'veth99',
]
@ -5011,11 +5012,14 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
'12-dummy.netdev',
'13-dummy.netdev',
'25-veth.netdev',
'25-veth-downstream.netdev',
'25-veth-downstream-veth97.netdev',
'25-veth-downstream-veth98.netdev',
'dhcp6pd-downstream-dummy97.network',
'dhcp6pd-downstream-dummy98.network',
'dhcp6pd-downstream-dummy99.network',
'dhcp6pd-downstream-test1.network',
'dhcp6pd-downstream-veth97.network',
'dhcp6pd-downstream-veth97-peer.network',
'dhcp6pd-downstream-veth98.network',
'dhcp6pd-downstream-veth98-peer.network',
'dhcp6pd-server.network',
@ -5035,7 +5039,8 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
def test_dhcp6pd(self):
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',
'dhcp6pd-downstream-dummy97.network',
'12-dummy.netdev', 'dhcp6pd-downstream-dummy98.network',
@ -5045,13 +5050,24 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
self.wait_online(['veth-peer:carrier'])
start_isc_dhcpd('veth-peer', 'isc-dhcpd-dhcp6pd.conf')
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')
output = check_output('ip -6 address show dev veth-peer scope global')
print(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')
output = check_output('ip -6 address show dev veth99 scope global')
print(output)
@ -5077,9 +5093,35 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
output = check_output('ip -6 address show dev dummy98 scope global')
print(output)
# 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)
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')
output = check_output('ip -6 address show dev veth98 scope global')
@ -5101,10 +5143,6 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
# 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')
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')
output = check_output('ip -6 route show type unreachable')
print(output)
@ -5123,12 +5161,22 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
print('### ip -6 route show dev dummy98')
output = check_output('ip -6 route show dev dummy98')
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]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')
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')
print(output)
# 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)
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')
output = check_output('ip -6 route show dev dummy97')
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
check_output(*networkctl_cmd, 'reconfigure', 'dummy98', env=env)
check_output(*networkctl_cmd, 'reconfigure', 'dummy98', 'dummy99', env=env)
self.wait_online(['dummy98:routable'])
print('### ip -6 address show dev dummy98 scope global')
output = check_output('ip -6 address show dev dummy98 scope global')
print(output)
# 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)
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')
output = check_output('ip -6 route show dev dummy98')
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):
links = [

View File

@ -4,6 +4,7 @@
set -eux
systemd-analyze log-level debug
export SYSTEMD_LOG_LEVEL=debug
mkdir -p /tmp/img/usr/lib/systemd/system/
mkdir -p /tmp/img/opt/