diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 31af7cfa98..2c564d26b4 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1372,6 +1372,22 @@ + + ForceDHCPv6PDOtherInformation= + + A boolean that enforces DHCPv6 stateful mode when the 'Other information' bit is set in + Router Advertisement messages. By default setting only the 'O' bit in Router Advertisements + makes DHCPv6 request network information in a stateless manner using a two-message Information + Request and Information Reply message exchange. + RFC 7084, requirement WPD-4, updates + this behavior for a Customer Edge router so that stateful DHCPv6 Prefix Delegation is also + requested when only the 'O' bit is set in Router Advertisements. This option enables such a CE + behavior as it is impossible to automatically distinguish the intention of the 'O' bit otherwise. + By default this option is set to 'false', enable it if no prefixes are delegated when the device + should be acting as a CE router. + + + diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 0aa7a190c4..f9b97d17dd 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -403,11 +403,12 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { } int dhcp6_request_address(Link *link, int ir) { - int r, inf_req; + int r, inf_req, pd; bool running; assert(link); assert(link->dhcp6_client); + assert(link->network); assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); r = sd_dhcp6_client_is_running(link->dhcp6_client); @@ -416,6 +417,21 @@ int dhcp6_request_address(Link *link, int ir) { else running = r; + r = sd_dhcp6_client_get_prefix_delegation(link->dhcp6_client, &pd); + if (r < 0) + return r; + + if (pd && ir && link->network->dhcp6_force_pd_other_information) { + log_link_debug(link, "Enabling managed mode to request DHCPv6 PD with 'Other Information' set"); + + r = sd_dhcp6_client_set_address_request(link->dhcp6_client, + false); + if (r < 0 ) + return r; + + ir = false; + } + if (running) { r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req); if (r < 0) diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 357231152e..a7c94d1dc4 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -138,6 +138,7 @@ DHCP.UseTimezone, config_parse_bool, DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid) DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port) DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit) +DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) IPv6AcceptRA.RouteTable, config_parse_uint32, 0, offsetof(Network, ipv6_accept_ra_route_table) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 6bfd8d5dd5..1be7d46735 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -171,6 +171,9 @@ struct Network { struct in6_addr *router_dns; unsigned n_router_dns; char **router_search_domains; + bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O' + RA flag is set, see RFC 7084, + WPD-4 */ /* Bridge Support */ int use_bpdu;