summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-10-27 12:15:18 +0900
committerGitHub <noreply@github.com>2021-10-27 12:15:18 +0900
commitb81070ff13c1f9647e771c09c9e8c37e4e206807 (patch)
treebdd7aee67da2fe1b6ced6860c77ad9e5e45281c7
parent8f1daefce6e952f2fad9510e5101b5fc675d363f (diff)
parent149cda85bfd8e6d2fd5c0137ff76b074c9e6cf3f (diff)
downloadsystemd-b81070ff13c1f9647e771c09c9e8c37e4e206807.tar.gz
Merge pull request #21129 from yuwata/network-dhcp6-pd-vs-ndisc
network: several follow-ups for DHCPv6-PD
-rw-r--r--man/systemd.network.xml45
-rw-r--r--src/network/networkd-dhcp6.c68
-rw-r--r--src/network/networkd-dhcp6.h2
-rw-r--r--src/network/networkd-ndisc.c4
-rw-r--r--src/network/networkd-network-gperf.gperf6
-rw-r--r--src/network/networkd-network.c1
-rw-r--r--src/network/networkd-network.h4
7 files changed, 71 insertions, 59 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index b6bf993adc..41a58b36eb 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2090,27 +2090,15 @@ Table=1234</programlisting></para>
<!-- How to communicate with the server -->
<varlistentry>
- <term><varname>ForceDHCPv6PDOtherInformation=</varname></term>
- <listitem>
- <para>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.
- <ulink url="https://tools.ietf.org/html/rfc7084">RFC 7084</ulink>, 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.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term><varname>WithoutRA=</varname></term>
<listitem>
- <para>Allows DHCPv6 client to start without router advertisements's managed or other address
- configuration flag. Takes one of <literal>solicit</literal> or
- <literal>information-request</literal>. Defaults to unset.</para>
+ <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>
</listitem>
</varlistentry>
</variablelist>
@@ -2128,9 +2116,10 @@ Table=1234</programlisting></para>
<listitem>
<para>Specifies the name or the index of the uplink interface, or one of the special values
<literal>:self</literal> and <literal>:auto</literal>. When <literal>:self</literal>, the
- interface itself is considered the uplink interface. When <literal>:auto</literal>, the first
- link which acquired prefixes to be delegated from the DHCPv6 server is selected. Defaults to
- <literal>:auto</literal>.</para>
+ interface itself is considered the uplink interface, and
+ <varname>WithoutRA=solicit</varname> is implied if the setting is not explicitly specified.
+ When <literal>:auto</literal>, the first link which acquired prefixes to be delegated from
+ the DHCPv6 server is selected. Defaults to <literal>:auto</literal>.</para>
</listitem>
</varlistentry>
@@ -2382,11 +2371,13 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
<varlistentry>
<term><varname>DHCPv6Client=</varname></term>
<listitem>
- <para>Takes a boolean, or the special value <literal>always</literal>. When true or
- <literal>always</literal>, the DHCPv6 client will be started when the RA has the managed or
- other information flag. If set to <literal>always</literal>, 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.</para>
+ <para>Takes a boolean, or the special value <literal>always</literal>. When true, the
+ DHCPv6 client will be started when the RA has the managed or other information flag. If set
+ to <literal>always</literal>, 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 <varname>WithoutRA=</varname> in the [DHCPv6] section is enabled, or
+ <varname>UplinkInterface=:self</varname> in the [DHCPv6PrefixDelegation] section is
+ specified. Defaults to true.</para>
</listitem>
</varlistentry>
</variablelist>
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 52ff5eb3aa..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;
@@ -1311,40 +1330,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, pd;
- 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));
- r = sd_dhcp6_client_is_running(link->dhcp6_client);
- if (r < 0)
- return r;
- running = r;
+ 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;
- r = sd_dhcp6_client_get_prefix_delegation(link->dhcp6_client, &pd);
+ r = sd_dhcp6_client_is_running(link->dhcp6_client);
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");
+ if (r > 0) {
+ int inf_req;
- 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)
return r;
- if (inf_req == ir)
+ if (inf_req == information_request)
return 0;
r = sd_dhcp6_client_stop(link->dhcp6_client);
@@ -1356,7 +1366,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;
@@ -1368,9 +1378,11 @@ int dhcp6_request_information(Link *link, int ir) {
}
int dhcp6_start(Link *link) {
+ DHCP6ClientStartMode start_mode;
int r;
assert(link);
+ assert(link->network);
if (!link->dhcp6_client)
return 0;
@@ -1381,7 +1393,7 @@ int dhcp6_start(Link *link) {
if (!link_has_carrier(link))
return 0;
- if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO)
+ if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0)
return 0;
if (!in6_addr_is_link_local(&link->ipv6ll_address)) {
@@ -1389,10 +1401,20 @@ int dhcp6_start(Link *link) {
return 0;
}
- if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0)
+ r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
+ 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 = 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,
+ start_mode == 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:
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index ccbf02b99d..6631f5bc3e 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -248,9 +248,8 @@ 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.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)
@@ -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.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 bd9758c899..d10119f58c 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -185,12 +185,10 @@ 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;
- /* 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;