From 483566e5ba9e4214e04106ae8760a79a13d710c2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 14 Oct 2021 15:42:33 +0900 Subject: [PATCH 1/4] network: deprecate ForceDHCPv6PDOtherInformation= setting The setting is completely meaningless, as WithoutRA= and UseDelegatedPrefix= in [DHCPv6] section, and DHCPv6Client= in [IPv6AcceptRA] section control the behavior. --- man/systemd.network.xml | 16 ---------------- src/network/networkd-dhcp6.c | 16 +--------------- src/network/networkd-network-gperf.gperf | 4 ++-- src/network/networkd-network.h | 2 -- 4 files changed, 3 insertions(+), 35 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index b6bf993adc..d847f0a0a3 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2089,22 +2089,6 @@ Table=1234 - - ForceDHCPv6PDOtherInformation= - - Takes 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. - - - WithoutRA= diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 52ff5eb3aa..aba0699780 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -1312,7 +1312,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { } int dhcp6_request_information(Link *link, int ir) { - int r, inf_req, pd; + int r, inf_req; bool running; assert(link); @@ -1325,20 +1325,6 @@ int dhcp6_request_information(Link *link, int ir) { return r; 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 ccbf02b99d..3caf7c2bdd 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -248,7 +248,6 @@ DHCPv6.RequestOptions, config_parse_dhcp_request_options, DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_user_class) DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class) DHCPv6.SendVendorOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_vendor_options) -DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_prefix_hint, 0, 0 DHCPv6.WithoutRA, config_parse_dhcp6_client_start_mode, 0, offsetof(Network, dhcp6_without_ra) DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options) @@ -530,11 +529,12 @@ DHCP.RouteTable, config_parse_dhcp_or_ra_route_table DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port) DHCP.RapidCommit, config_parse_warn_compat, DISABLED_LEGACY, 0 -DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) +DHCP.ForceDHCPv6PDOtherInformation, config_parse_warn_compat, DISABLED_LEGACY, 0 DHCPv4.UseDomainName, config_parse_dhcp_use_domains, AF_INET, 0 DHCPv4.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical) DHCPv6.RouteMetric, config_parse_dhcp_or_ra_route_metric, AF_INET6, 0 DHCPv6.RapidCommit, config_parse_warn_compat, DISABLED_LEGACY, 0 +DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_warn_compat, DISABLED_LEGACY, 0 IPv6AcceptRA.DenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix) IPv6AcceptRA.BlackList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix) TrafficControlQueueingDiscipline.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index bd9758c899..f8d62fee6c 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -189,8 +189,6 @@ struct Network { OrderedHashmap *dhcp6_client_send_options; OrderedHashmap *dhcp6_client_send_vendor_options; Set *dhcp6_request_options; - /* Start DHCPv6 PD also when 'O' RA flag is set, see RFC 7084, WPD-4 */ - bool dhcp6_force_pd_other_information; /* DHCP Server Support */ bool dhcp_server; From fac19a21cf1de0805352390378ab9844daa16862 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 14 Oct 2021 16:35:29 +0900 Subject: [PATCH 2/4] network: do not restart DHCPv6 client when WithoutRA= is set Previously, even if WithoutRA= is specified, the DHCPv6 client may be restarted in undesired mode when a RA is received. --- src/network/networkd-dhcp6.c | 35 +++++++++++++++++++++++++---------- src/network/networkd-dhcp6.h | 2 +- src/network/networkd-ndisc.c | 4 ++-- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index aba0699780..8bd69813a8 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -1311,26 +1311,31 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { } } -int dhcp6_request_information(Link *link, int ir) { - int r, inf_req; - bool running; +int dhcp6_start_on_ra(Link *link, bool information_request) { + int r; assert(link); assert(link->dhcp6_client); assert(link->network); assert(in6_addr_is_link_local(&link->ipv6ll_address)); + if (link->network->dhcp6_without_ra != DHCP6_CLIENT_START_MODE_NO) + /* When WithoutRA= is specified, then the DHCPv6 client should be already runnging in + * the requested mode. Hence, ignore the requests by RA. */ + return 0; + r = sd_dhcp6_client_is_running(link->dhcp6_client); if (r < 0) return r; - running = r; - if (running) { + if (r > 0) { + int inf_req; + r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req); if (r < 0) return r; - if (inf_req == ir) + if (inf_req == information_request) return 0; r = sd_dhcp6_client_stop(link->dhcp6_client); @@ -1342,7 +1347,7 @@ int dhcp6_request_information(Link *link, int ir) { return r; } - r = sd_dhcp6_client_set_information_request(link->dhcp6_client, ir); + r = sd_dhcp6_client_set_information_request(link->dhcp6_client, information_request); if (r < 0) return r; @@ -1357,6 +1362,7 @@ int dhcp6_start(Link *link) { int r; assert(link); + assert(link->network); if (!link->dhcp6_client) return 0; @@ -1370,15 +1376,24 @@ int dhcp6_start(Link *link) { if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO) return 0; + if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0) + return 0; + if (!in6_addr_is_link_local(&link->ipv6ll_address)) { log_link_debug(link, "IPv6 link-local address is not set, delaying to start DHCPv6 client."); return 0; } - if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0) - return 0; + r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); + if (r < 0) + return r; - r = dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST); + r = sd_dhcp6_client_set_information_request(link->dhcp6_client, + link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST); + if (r < 0) + return r; + + r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0) return r; diff --git a/src/network/networkd-dhcp6.h b/src/network/networkd-dhcp6.h index a08d03b614..4a522aebcf 100644 --- a/src/network/networkd-dhcp6.h +++ b/src/network/networkd-dhcp6.h @@ -21,7 +21,7 @@ bool link_dhcp6_pd_is_enabled(Link *link); int dhcp6_pd_remove(Link *link, bool only_marked); int dhcp6_update_mac(Link *link); int dhcp6_start(Link *link); -int dhcp6_request_information(Link *link, int ir); +int dhcp6_start_on_ra(Link *link, bool information_request); int dhcp6_request_prefix_delegation(Link *link); int request_process_dhcp6_client(Request *req); diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index d7b79f7416..5f831b58a4 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -906,13 +906,13 @@ static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) { /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags. * Note, if both managed and other information bits are set, then ignore other * information bit. See RFC 4861. */ - r = dhcp6_request_information(link, !(flags & ND_RA_FLAG_MANAGED)); + r = dhcp6_start_on_ra(link, !(flags & ND_RA_FLAG_MANAGED)); break; } case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS: /* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in managed mode * even if the router flags have neither M nor O flags. */ - r = dhcp6_request_information(link, false); + r = dhcp6_start_on_ra(link, /* information_request = */ false); break; default: From 0e45721e3d558eec0a08367a739d660615604aab Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 14 Oct 2021 19:10:49 +0900 Subject: [PATCH 3/4] network: dhcp6: make UplinkInterface=:self imply WithoutRA=solicit --- src/network/networkd-dhcp6.c | 31 ++++++++++++++++++++---- src/network/networkd-network-gperf.gperf | 2 +- src/network/networkd-network.c | 1 + src/network/networkd-network.h | 2 +- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 8bd69813a8..3cc457a02d 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -58,6 +58,25 @@ static int dhcp6_pd_resolve_uplink(Link *link, Link **ret) { return -ENOENT; } +static DHCP6ClientStartMode link_get_dhcp6_client_start_mode(Link *link) { + Link *uplink; + + assert(link); + + if (!link->network) + return DHCP6_CLIENT_START_MODE_NO; + + /* When WithoutRA= is explicitly specified, then honor it. */ + 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 */ + return uplink == link ? DHCP6_CLIENT_START_MODE_SOLICIT : DHCP6_CLIENT_START_MODE_NO; +} + static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) { uint32_t lifetime_preferred_sec, lifetime_valid_sec; struct in6_addr pd_prefix; @@ -1319,7 +1338,7 @@ int dhcp6_start_on_ra(Link *link, bool information_request) { assert(link->network); assert(in6_addr_is_link_local(&link->ipv6ll_address)); - if (link->network->dhcp6_without_ra != DHCP6_CLIENT_START_MODE_NO) + if (link_get_dhcp6_client_start_mode(link) != DHCP6_CLIENT_START_MODE_NO) /* When WithoutRA= is specified, then the DHCPv6 client should be already runnging in * the requested mode. Hence, ignore the requests by RA. */ return 0; @@ -1359,6 +1378,7 @@ int dhcp6_start_on_ra(Link *link, bool information_request) { } int dhcp6_start(Link *link) { + DHCP6ClientStartMode start_mode; int r; assert(link); @@ -1373,9 +1393,6 @@ int dhcp6_start(Link *link) { if (!link_has_carrier(link)) return 0; - if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO) - return 0; - if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0) return 0; @@ -1388,8 +1405,12 @@ int dhcp6_start(Link *link) { if (r < 0) return r; + start_mode = link_get_dhcp6_client_start_mode(link); + if (start_mode == DHCP6_CLIENT_START_MODE_NO) + return 0; + r = sd_dhcp6_client_set_information_request(link->dhcp6_client, - link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST); + start_mode == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST); if (r < 0) return r; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 3caf7c2bdd..6631f5bc3e 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -249,7 +249,7 @@ DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_cl DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class) DHCPv6.SendVendorOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_vendor_options) DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_prefix_hint, 0, 0 -DHCPv6.WithoutRA, config_parse_dhcp6_client_start_mode, 0, offsetof(Network, dhcp6_without_ra) +DHCPv6.WithoutRA, config_parse_dhcp6_client_start_mode, 0, offsetof(Network, dhcp6_client_start_mode) DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options) DHCPv6.IAID, config_parse_iaid, AF_INET6, 0 DHCPv6.DUIDType, config_parse_duid_type, 0, offsetof(Network, dhcp6_duid) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index c3c792eb49..5469cb4560 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -405,6 +405,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .dhcp6_use_hostname = true, .dhcp6_use_ntp = true, .dhcp6_duid.type = _DUID_TYPE_INVALID, + .dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID, .dhcp6_pd = -1, .dhcp6_pd_announce = true, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index f8d62fee6c..d10119f58c 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -185,7 +185,7 @@ struct Network { char *dhcp6_mudurl; char **dhcp6_user_class; char **dhcp6_vendor_class; - DHCP6ClientStartMode dhcp6_without_ra; + DHCP6ClientStartMode dhcp6_client_start_mode; OrderedHashmap *dhcp6_client_send_options; OrderedHashmap *dhcp6_client_send_vendor_options; Set *dhcp6_request_options; From 149cda85bfd8e6d2fd5c0137ff76b074c9e6cf3f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 14 Oct 2021 19:27:08 +0900 Subject: [PATCH 4/4] man: adjust the explanations related to the DHCPv6 client starting mode --- man/systemd.network.xml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index d847f0a0a3..41a58b36eb 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2092,9 +2092,13 @@ Table=1234 WithoutRA= - Allows DHCPv6 client to start without router advertisements's managed or other address - configuration flag. Takes one of solicit or - information-request. Defaults to unset. + Allows DHCPv6 client to start without router advertisements's managed or other + address configuration flag. Takes one of no, solicit + or information-request. When this is not specified and + UplinkInterface=:self is specified, then solicit is + implied. Otherwise, defaults to no, and the DHCPv6 client will be + started when an RA is received. See also DHCPv6Client= setting in the + [IPv6AcceptRA] section. @@ -2112,9 +2116,10 @@ Table=1234 Specifies the name or the index of the uplink interface, or one of the special values :self and :auto. When :self, the - interface itself is considered the uplink interface. When :auto, the first - link which acquired prefixes to be delegated from the DHCPv6 server is selected. Defaults to - :auto. + interface itself is considered the uplink interface, and + WithoutRA=solicit is implied if the setting is not explicitly specified. + When :auto, the first link which acquired prefixes to be delegated from + the DHCPv6 server is selected. Defaults to :auto. @@ -2366,11 +2371,13 @@ Token=prefixstable:2002:da8:1:: DHCPv6Client= - Takes a boolean, or the special value always. When true or - always, the DHCPv6 client will be started when the RA has the managed or - other information flag. If set to always, the DHCPv6 client will also be - started in managed mode when neither managed nor other information flag is set in the RA. - Defaults to true. + Takes a boolean, or the special value always. When true, the + DHCPv6 client will be started when the RA has the managed or other information flag. If set + to always, the DHCPv6 client will be started in managed mode when an RA + is received, even if neither managed nor other information flag is set in the RA. This will + be ignored when WithoutRA= in the [DHCPv6] section is enabled, or + UplinkInterface=:self in the [DHCPv6PrefixDelegation] section is + specified. Defaults to true.