diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 1eaa452786..e8f3f364f1 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1781,6 +1781,15 @@
+
+ AssignAcquiredDelegatedPrefixAddress=
+
+ Takes a boolean. Specifies whether to add an address from the delegated prefixes which are received
+ from the WAN interface by the IPv6PrefixDelegation=. When true (on LAN interfce), the EUI-64
+ algorithm will be used to form an interface identifier from the delegated prefixes. Defaults to true.
+
+
+
PrefixDelegationHint=
@@ -3301,7 +3310,10 @@ DHCP=ipv6
Name=enp2s0
[Network]
-IPv6PrefixDelegation=dhcpv6
+IPv6PrefixDelegation=dhcpv6
+
+[DHCPv6]
+AssignAcquiredDelegatedPrefixAddress=yes
This will enable IPv6 PD on the interface enp1s0 as an upstream interface where the
DHCPv6 client is running and enp2s0 as a downstream interface where the prefix is delegated to.
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index b3ebdc8cd7..d0972f3593 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -26,6 +26,10 @@ static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr);
static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link);
static int dhcp6_prefix_remove_all(Manager *m, Link *link);
static bool dhcp6_link_has_dhcpv6_prefix(Link *link);
+static int dhcp6_assign_delegated_prefix(Link *link, const struct in6_addr *prefix,
+ uint8_t prefix_len,
+ uint32_t lifetime_preferred,
+ uint32_t lifetime_valid);
static bool dhcp6_get_prefix_delegation(Link *link) {
if (!link->network)
@@ -191,6 +195,12 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix,
if (r < 0)
return r;
+ if (link->network->dhcp6_pd_assign_prefix) {
+ r = dhcp6_assign_delegated_prefix(link, prefix, prefix_len, lifetime_preferred, lifetime_valid);
+ if (r < 0)
+ return r;
+ }
+
return sd_radv_start(radv);
}
@@ -1018,3 +1028,43 @@ static bool dhcp6_link_has_dhcpv6_prefix(Link *link) {
return false;
}
+
+static int dhcp6_assign_delegated_prefix(Link *link,
+ const struct in6_addr *prefix,
+ uint8_t prefix_len,
+ uint32_t lifetime_preferred,
+ uint32_t lifetime_valid) {
+ _cleanup_(address_freep) Address *address = NULL;
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(prefix);
+
+ if (!link->network->dhcp6_pd_assign_prefix)
+ return 0;
+
+ r = address_new(&address);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate address: %m");
+
+ address->in_addr.in6 = *prefix;
+ r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to generate EUI64 address for DHCPv6 acquired delegated prefix: %m");
+
+ address->prefixlen = prefix_len;
+ address->family = AF_INET6;
+ address->cinfo.ifa_prefered = lifetime_preferred;
+ address->cinfo.ifa_valid = lifetime_valid;
+
+ link_set_state(link, LINK_STATE_CONFIGURING);
+
+ r = address_configure(address, link, address_handler, true);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not set addresses: %m");
+ if (r > 0)
+ link->address_messages++;
+
+ return 0;
+}
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 484705f488..8a549110fa 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1173,7 +1173,7 @@ static int link_request_set_neighbors(Link *link) {
return 0;
}
-static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(rtnl);
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index e8d67e0d64..c793a37df7 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -228,6 +228,7 @@ int link_request_set_routes(Link *link);
int link_request_set_nexthop(Link *link);
int link_reconfigure(Link *link, bool force);
+int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_link_ipv6_address_gen_mode);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 79799e7dde..d318b7d891 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -199,6 +199,7 @@ DHCPv6.RequestOptions, config_parse_dhcp_request_options,
DHCPv6.UserClass, config_parse_dhcp_user_class, AF_INET6, offsetof(Network, dhcp6_user_class)
DHCPv6.VendorClass, config_parse_dhcp_vendor_class, 0, offsetof(Network, dhcp6_vendor_class)
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
+DHCPv6.AssignAcquiredDelegatedPrefixAddress, config_parse_bool, 0, offsetof(Network, dhcp6_pd_assign_prefix)
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra)
DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 781bbaa881..ae466a2310 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -412,6 +412,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp6_use_ntp = true,
.dhcp6_use_dns = true,
+ .dhcp6_pd_assign_prefix = true,
+
.dhcp_server_emit_dns = true,
.dhcp_server_emit_ntp = true,
.dhcp_server_emit_sip = true,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 45b9df647d..441bba1273 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -192,6 +192,7 @@ struct Network {
bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
RA flag is set, see RFC 7084,
WPD-4 */
+ bool dhcp6_pd_assign_prefix;
/* Bridge Support */
int use_bpdu;
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 178bd9aaae..a1a6cdd233 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -119,6 +119,7 @@ SendOption=
RequestOptions=
UserClass=
VendorClass=
+AssignAcquiredDelegatedPrefixAddress=
[Route]
Destination=
Protocol=