X Tutup
Skip to content

Commit 6830c3a

Browse files
authored
Merge pull request systemd#20778 from yuwata/network-ipv6-token
network: rework IPv6 address generation mode
2 parents 1717588 + fe2a8b3 commit 6830c3a

22 files changed

+1261
-1020
lines changed

man/systemd.network.xml

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -488,53 +488,6 @@ Gateway=0.0.0.0
488488
Table=1234</programlisting></para>
489489
</listitem>
490490
</varlistentry>
491-
<varlistentry>
492-
<term><varname>IPv6Token=</varname></term>
493-
<listitem>
494-
<para>Specifies an optional address generation mode for the Stateless Address
495-
Autoconfiguration (SLAAC). Supported modes are <literal>prefixstable</literal> and
496-
<literal>static</literal>.</para>
497-
498-
<para>When the mode is set to <literal>static</literal>, an IPv6 address must be
499-
specified after a colon (<literal>:</literal>), and the lower bits of the supplied
500-
address are combined with the upper bits of a prefix received in a Router Advertisement
501-
(RA) message to form a complete address. Note that if multiple prefixes are received in an
502-
RA message, or in multiple RA messages, addresses will be formed from each of them using
503-
the supplied address. This mode implements SLAAC but uses a static interface identifier
504-
instead of an identifier generated by using the EUI-64 algorithm. Because the interface
505-
identifier is static, if Duplicate Address Detection detects that the computed address is a
506-
duplicate (in use by another node on the link), then this mode will fail to provide an
507-
address for that prefix. If an IPv6 address without mode is specified, then
508-
<literal>static</literal> mode is assumed.</para>
509-
510-
<para>When the mode is set to <literal>prefixstable</literal> the
511-
<ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink> algorithm for generating
512-
interface identifiers will be used. This mode can optionally take an IPv6 address separated
513-
with a colon (<literal>:</literal>). If an IPv6 address is specified, then an interface
514-
identifier is generated only when a prefix received in an RA message matches the supplied
515-
address.</para>
516-
517-
<para>If no address generation mode is specified (which is the default), or a received
518-
prefix does not match any of the addresses provided in <literal>prefixstable</literal>
519-
mode, then the EUI-64 algorithm will be used to form an interface identifier for that
520-
prefix. This mode is also SLAAC, but with a potentially stable interface identifier which
521-
does not directly map to the interface's hardware address.</para>
522-
523-
<para>Note that the <literal>prefixstable</literal> algorithm uses both the interface
524-
name and MAC address as input to the hash to compute the interface identifier, so if either
525-
of those are changed the resulting interface identifier (and address) will change, even if
526-
the prefix received in the RA message has not changed.</para>
527-
528-
<para>This setting can be specified multiple times. If an empty string is assigned, then
529-
the all previous assignments are cleared.</para>
530-
531-
<para>Examples:
532-
<programlisting>IPv6Token=::1a:2b:3c:4d
533-
IPv6Token=static:::1a:2b:3c:4d
534-
IPv6Token=prefixstable
535-
IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
536-
</listitem>
537-
</varlistentry>
538491
<varlistentry>
539492
<term><varname>LLMNR=</varname></term>
540493
<listitem>
@@ -2205,11 +2158,9 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
22052158
<term><varname>Token=</varname></term>
22062159
<listitem>
22072160
<para>Specifies an optional address generation mode for assigning an address in each
2208-
delegated prefix. Takes an IPv6 address. When set, the lower bits of the supplied address is
2209-
combined with the upper bits of each delegatad prefix received from the WAN interface by the
2210-
DHCPv6 Prefix Delegation to form a complete address. When <varname>Assign=</varname> is
2211-
disabled, this setting is ignored. When unset, the EUI-64 algorithm will be used to form
2212-
addresses. Defaults to unset.</para>
2161+
delegated prefix. This accepts the same syntax as <varname>Token=</varname> in the
2162+
[IPv6AcceptRA] section. If <varname>Assign=</varname> is set to false, then this setting will
2163+
be ignored. Defaults to unset, which means the EUI-64 algorithm will be used.</para>
22132164
</listitem>
22142165
</varlistentry>
22152166

@@ -2236,6 +2187,57 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
22362187
with the <varname>IPv6AcceptRA=</varname> setting described above:</para>
22372188

22382189
<variablelist class='network-directives'>
2190+
<varlistentry>
2191+
<term><varname>Token=</varname></term>
2192+
<listitem>
2193+
<para>Specifies an optional address generation mode for the Stateless Address
2194+
Autoconfiguration (SLAAC). Supported modes are <literal>eui64</literal>,
2195+
<literal>static</literal>, and <literal>prefixstable</literal>.</para>
2196+
2197+
<para>When the mode is set to <literal>eui64</literal>, then the EUI-64 algorithm will be
2198+
used to generate an address for that prefix.</para>
2199+
2200+
<para>When the mode is set to <literal>static</literal>, an IPv6 address must be
2201+
specified after a colon (<literal>:</literal>), and the lower bits of the supplied
2202+
address are combined with the upper bits of a prefix received in a Router Advertisement
2203+
(RA) message to form a complete address. Note that if multiple prefixes are received in an
2204+
RA message, or in multiple RA messages, addresses will be formed from each of them using
2205+
the supplied address. This mode implements SLAAC but uses a static interface identifier
2206+
instead of an identifier generated by using the EUI-64 algorithm. Because the interface
2207+
identifier is static, if Duplicate Address Detection detects that the computed address is a
2208+
duplicate (in use by another node on the link), then this mode will fail to provide an
2209+
address for that prefix. If an IPv6 address without mode is specified, then
2210+
<literal>static</literal> mode is assumed.</para>
2211+
2212+
<para>When the mode is set to <literal>prefixstable</literal> the
2213+
<ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink> algorithm for generating
2214+
interface identifiers will be used. This mode can optionally take an IPv6 address separated
2215+
with a colon (<literal>:</literal>). If an IPv6 address is specified, then an interface
2216+
identifier is generated only when a prefix received in an RA message matches the supplied
2217+
address.</para>
2218+
2219+
<para>If no address generation mode is specified (which is the default), or a received
2220+
prefix does not match any of the addresses provided in <literal>prefixstable</literal>
2221+
mode, then the EUI-64 algorithm will be used to form an interface identifier for that
2222+
prefix.</para>
2223+
2224+
<para>Note that the <literal>prefixstable</literal> algorithm uses both the interface
2225+
name and MAC address as input to the hash to compute the interface identifier, so if either
2226+
of those are changed the resulting interface identifier (and address) will be changed, even
2227+
if the prefix received in the RA message has not been changed.</para>
2228+
2229+
<para>This setting can be specified multiple times. If an empty string is assigned, then
2230+
the all previous assignments are cleared.</para>
2231+
2232+
<para>Examples:
2233+
<programlisting>Token=eui64
2234+
Token=::1a:2b:3c:4d
2235+
Token=static:::1a:2b:3c:4d
2236+
Token=prefixstable
2237+
Token=prefixstable:2002:da8:1::</programlisting></para>
2238+
</listitem>
2239+
</varlistentry>
2240+
22392241
<varlistentry>
22402242
<term><varname>UseDNS=</varname></term>
22412243
<listitem>
@@ -2727,6 +2729,16 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
27272729
</para></listitem>
27282730
</varlistentry>
27292731

2732+
<varlistentry>
2733+
<term><varname>Token=</varname></term>
2734+
<listitem>
2735+
<para>Specifies an optional address generation mode for assigning an address in each
2736+
prefix. This accepts the same syntax as <varname>Token=</varname> in the [IPv6AcceptRA]
2737+
section. If <varname>Assign=</varname> is set to false, then this setting will be ignored.
2738+
Defaults to unset, which means the EUI-64 algorithm will be used.</para>
2739+
</listitem>
2740+
</varlistentry>
2741+
27302742
<varlistentry>
27312743
<term><varname>RouteMetric=</varname></term>
27322744
<listitem>

src/basic/in-addr-util.c

Lines changed: 92 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -621,64 +621,119 @@ int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mas
621621
return 0;
622622
}
623623

624-
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
624+
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen) {
625+
struct in_addr mask;
626+
625627
assert(addr);
626628

627-
if (family == AF_INET) {
628-
struct in_addr mask;
629+
if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
630+
return -EINVAL;
629631

630-
if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
631-
return -EINVAL;
632+
addr->s_addr &= mask.s_addr;
633+
return 0;
634+
}
632635

633-
addr->in.s_addr &= mask.s_addr;
634-
return 0;
635-
}
636+
int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen) {
637+
unsigned i;
636638

637-
if (family == AF_INET6) {
638-
unsigned i;
639+
for (i = 0; i < 16; i++) {
640+
uint8_t mask;
639641

640-
for (i = 0; i < 16; i++) {
641-
uint8_t mask;
642+
if (prefixlen >= 8) {
643+
mask = 0xFF;
644+
prefixlen -= 8;
645+
} else if (prefixlen > 0) {
646+
mask = 0xFF << (8 - prefixlen);
647+
prefixlen = 0;
648+
} else {
649+
assert(prefixlen == 0);
650+
mask = 0;
651+
}
642652

643-
if (prefixlen >= 8) {
644-
mask = 0xFF;
645-
prefixlen -= 8;
646-
} else {
647-
mask = 0xFF << (8 - prefixlen);
648-
prefixlen = 0;
649-
}
653+
addr->s6_addr[i] &= mask;
654+
}
650655

651-
addr->in6.s6_addr[i] &= mask;
652-
}
656+
return 0;
657+
}
653658

654-
return 0;
659+
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
660+
assert(addr);
661+
662+
switch (family) {
663+
case AF_INET:
664+
return in4_addr_mask(&addr->in, prefixlen);
665+
case AF_INET6:
666+
return in6_addr_mask(&addr->in6, prefixlen);
667+
default:
668+
return -EAFNOSUPPORT;
655669
}
670+
}
656671

657-
return -EAFNOSUPPORT;
672+
int in4_addr_prefix_covers(
673+
const struct in_addr *prefix,
674+
unsigned char prefixlen,
675+
const struct in_addr *address) {
676+
677+
struct in_addr masked_prefix, masked_address;
678+
int r;
679+
680+
assert(prefix);
681+
assert(address);
682+
683+
masked_prefix = *prefix;
684+
r = in4_addr_mask(&masked_prefix, prefixlen);
685+
if (r < 0)
686+
return r;
687+
688+
masked_address = *address;
689+
r = in4_addr_mask(&masked_address, prefixlen);
690+
if (r < 0)
691+
return r;
692+
693+
return in4_addr_equal(&masked_prefix, &masked_address);
658694
}
659695

660-
int in_addr_prefix_covers(int family,
661-
const union in_addr_union *prefix,
662-
unsigned char prefixlen,
663-
const union in_addr_union *address) {
696+
int in6_addr_prefix_covers(
697+
const struct in6_addr *prefix,
698+
unsigned char prefixlen,
699+
const struct in6_addr *address) {
664700

665-
union in_addr_union masked_prefix, masked_address;
701+
struct in6_addr masked_prefix, masked_address;
666702
int r;
667703

668704
assert(prefix);
669705
assert(address);
670706

671707
masked_prefix = *prefix;
672-
r = in_addr_mask(family, &masked_prefix, prefixlen);
708+
r = in6_addr_mask(&masked_prefix, prefixlen);
673709
if (r < 0)
674710
return r;
675711

676712
masked_address = *address;
677-
r = in_addr_mask(family, &masked_address, prefixlen);
713+
r = in6_addr_mask(&masked_address, prefixlen);
678714
if (r < 0)
679715
return r;
680716

681-
return in_addr_equal(family, &masked_prefix, &masked_address);
717+
return in6_addr_equal(&masked_prefix, &masked_address);
718+
}
719+
720+
int in_addr_prefix_covers(
721+
int family,
722+
const union in_addr_union *prefix,
723+
unsigned char prefixlen,
724+
const union in_addr_union *address) {
725+
726+
assert(prefix);
727+
assert(address);
728+
729+
switch (family) {
730+
case AF_INET:
731+
return in4_addr_prefix_covers(&prefix->in, prefixlen, &address->in);
732+
case AF_INET6:
733+
return in6_addr_prefix_covers(&prefix->in6, prefixlen, &address->in6);
734+
default:
735+
return -EAFNOSUPPORT;
736+
}
682737
}
683738

684739
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
@@ -846,3 +901,9 @@ int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
846901
}
847902

848903
DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);
904+
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
905+
in6_addr_hash_ops_free,
906+
struct in6_addr,
907+
in6_addr_hash_func,
908+
in6_addr_compare_func,
909+
free);

src/basic/in-addr-util.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
8989
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
9090
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
9191
int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
92+
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen);
93+
int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen);
9294
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
95+
int in4_addr_prefix_covers(const struct in_addr *prefix, unsigned char prefixlen, const struct in_addr *address);
96+
int in6_addr_prefix_covers(const struct in6_addr *prefix, unsigned char prefixlen, const struct in6_addr *address);
9397
int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
9498
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
9599
int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
@@ -119,6 +123,7 @@ int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b);
119123

120124
extern const struct hash_ops in_addr_data_hash_ops;
121125
extern const struct hash_ops in6_addr_hash_ops;
126+
extern const struct hash_ops in6_addr_hash_ops_free;
122127

123128
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"
124129
#define IPV4_ADDRESS_FMT_VAL(address) \

src/network/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ sources = files('''
5151
netdev/macsec.h
5252
netdev/xfrm.c
5353
netdev/xfrm.h
54+
networkd-address-generation.c
55+
networkd-address-generation.h
5456
networkd-address-label.c
5557
networkd-address-label.h
5658
networkd-address-pool.c

0 commit comments

Comments
 (0)
X Tutup