]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: make prefixstable mode of IPv6Token= can be applied to any received prefixes
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 30 Jul 2020 03:12:23 +0000 (12:12 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 8 Sep 2020 05:32:33 +0000 (14:32 +0900)
Closes #4625.

man/systemd.network.xml
src/network/networkd-ndisc.c

index e75d612c0535c9b0db13cab2da943e691177500d..c39b3643196a71ee2a0f51e0c49e951e5e7da68d 100644 (file)
         <varlistentry>
           <term><varname>IPv6Token=</varname></term>
           <listitem>
-            <para>Specifies an optional address generation mode and a required IPv6 address. If
-            the mode is present, the two parts must be separated with a colon
-            <literal><replaceable>mode</replaceable>:<replaceable>address</replaceable></literal>. The
-            address generation mode may be either <constant>prefixstable</constant> or
-            <constant>static</constant>. If not specified, <constant>static</constant> is assumed.
-            </para>
-            <para>When the mode is set to <constant>static</constant>, or unspecified, the lower bits of
-            the supplied address are combined with the upper bits of a prefix received in a Router Advertisement
-            message to form a complete address. Note that if multiple prefixes are received in an RA message, or in
-            multiple RA messages, addresses will be formed from each of them using the supplied address. This
-            mode implements SLAAC but uses a static interface identifier instead of an identifier generated
-            using the EUI-64 algorithm. Because the interface identifier is static, if Duplicate Address Detection
-            detects that the computed address is a duplicate (in use by another node on the link), then this
-            mode will fail to provide an address for that prefix.
-            </para>
-            <para>When the mode is set to <literal>prefixstable</literal> the RFC 7217 algorithm for generating
-            interface identifiers will be used, but only when a prefix received in an RA message matches the supplied address.
-            See <ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink>. Prefix matching will be attempted
-            against each <constant>prefixstable</constant> IPv6Token variable provided in the configuration; if a received
-            prefix does not match any of the provided addresses, then the EUI-64 algorithm will be used to form
-            an interface identifier for that prefix. This mode is also SLAAC, but with a potentially stable interface
-            identifier which does not directly map to the interface's hardware address.
-
-            Note that the <constant>prefixstable</constant> algorithm includes both the interface's name and
-            MAC address in the hash used to compute the interface identifier, so if either of those are changed the resulting
-            interface identifier (and address) will change, even if the prefix received in the RA message has not changed.
-
-            Note that if multiple <constant>prefixstable</constant> IPv6Token variables are supplied with addresses that
-            match a prefix received in an RA message, only the first one will be used to generate addresses.
-            </para>
+            <para>Specifies an optional address generation mode for the Stateless Address
+            Autoconfiguration (SLAAC). Supported modes are <literal>prefixstable</literal> and
+            <literal>static</literal>.</para>
+
+            <para>When the mode is set to <literal>static</literal>, an IPv6 address must be
+            specified after a colon (<literal>:</literal>), and the lower bits of the supplied
+            address are combined with the upper bits of a prefix received in a Router Advertisement
+            (RA) message to form a complete address. Note that if multiple prefixes are received in an
+            RA message, or in multiple RA messages, addresses will be formed from each of them using
+            the supplied address. This mode implements SLAAC but uses a static interface identifier
+            instead of an identifier generated by using the EUI-64 algorithm. Because the interface
+            identifier is static, if Duplicate Address Detection detects that the computed address is a
+            duplicate (in use by another node on the link), then this mode will fail to provide an
+            address for that prefix. If an IPv6 address without mode is specified, then
+            <literal>static</literal> mode is assumed.</para>
+
+            <para>When the mode is set to <literal>prefixstable</literal> the
+            <ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink> algorithm for generating
+            interface identifiers will be used. This mode can optionally take an IPv6 address separated
+            with a colon (<literal>:</literal>). If an IPv6 address is specified, then an interface
+            identifier is generated only when a prefix received in an RA message matches the supplied
+            address.</para>
+
+            <para>If no address generation mode is specified (which is the default), or a received
+            prefix does not match any of the addresses provided in <literal>prefixstable</literal>
+            mode, then the EUI-64 algorithm will be used to form an interface identifier for that
+            prefix. This mode is also SLAAC, but with a potentially stable interface identifier which
+            does not directly map to the interface's hardware address.</para>
+
+            <para>Note that the <literal>prefixstable</literal> algorithm uses both the interface
+            name and MAC address as input to the hash to compute the interface identifier, so if either
+            of those are changed the resulting interface identifier (and address) will change, even if
+            the prefix received in the RA message has not changed.</para>
+
+            <para>This setting can be specified multiple times. If an empty string is assigned, then
+            the all previous assignments are cleared.</para>
+
+            <para>Examples:
+            <programlisting>IPv6Token=::1a:2b:3c:4d
+IPv6Token=static:::1a:2b:3c:4d
+IPv6Token=prefixstable
+IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
           </listitem>
         </varlistentry>
         <varlistentry>
index 349f0548afd7d645d41e674721dbf445850f1b59..45c1aaa0514723a322fb3d19b9236534e480278c 100644 (file)
@@ -384,14 +384,14 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address,
                 _cleanup_free_ struct in6_addr *new_address = NULL;
 
                 if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
-                    && IN6_ARE_ADDR_EQUAL(&j->prefix, address)) {
+                    && (IN6_IS_ADDR_UNSPECIFIED(&j->prefix) || IN6_ARE_ADDR_EQUAL(&j->prefix, address))) {
                         /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop
                            does not actually attempt Duplicate Address Detection; the counter will be incremented
                            only when the address generation algorithm produces an invalid address, and the loop
                            may exit with an address which ends up being unusable due to duplication on the link.
                         */
                         for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
-                                r = make_stableprivate_address(link, &j->prefix, prefixlen, j->dad_counter, &new_address);
+                                r = make_stableprivate_address(link, address, prefixlen, j->dad_counter, &new_address);
                                 if (r < 0)
                                         return r;
                                 if (r > 0)
@@ -1176,30 +1176,43 @@ int config_parse_address_generation_type(
         if (r < 0)
                 return log_oom();
 
-        if ((p = startswith(rvalue, "static:")))
-                token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_STATIC;
-        else if ((p = startswith(rvalue, "prefixstable:")))
+        if ((p = startswith(rvalue, "prefixstable"))) {
                 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE;
-        else {
+                if (*p == ':')
+                        p++;
+                else if (*p == '\0')
+                        p = NULL;
+                else {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                                   "Invalid IPv6 token mode in %s=, ignoring assignment: %s",
+                                   lvalue, rvalue);
+                        return 0;
+                }
+        } else {
                 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_STATIC;
-                p = rvalue;
-        }
-
-        r = in_addr_from_string(AF_INET6, p, &buffer);
-        if (r < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, r,
-                           "Failed to parse IPv6 %s, ignoring: %s", lvalue, rvalue);
-                return 0;
+                p = startswith(rvalue, "static:");
+                if (!p)
+                        p = rvalue;
         }
 
-        if (in_addr_is_null(AF_INET6, &buffer)) {
-                log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "IPv6 %s cannot be the ANY address, ignoring: %s", lvalue, rvalue);
-                return 0;
+        if (p) {
+                r = in_addr_from_string(AF_INET6, p, &buffer);
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r,
+                                   "Failed to parse IP address in %s=, ignoring assignment: %s",
+                                   lvalue, rvalue);
+                        return 0;
+                }
+                if (token->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC &&
+                    in_addr_is_null(AF_INET6, &buffer)) {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                                   "IPv6 address in %s= cannot be the ANY address, ignoring assignment: %s",
+                                   lvalue, rvalue);
+                        return 0;
+                }
+                token->prefix = buffer.in6;
         }
 
-        token->prefix = buffer.in6;
-
         r = ordered_set_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops);
         if (r < 0)
                 return log_oom();