1
0
mirror of https://github.com/systemd/systemd synced 2025-09-21 21:04:46 +02:00

Compare commits

..

No commits in common. "1d6cfd25a23b2da1364e5dc62c3cf28b37277d32" and "c09f335744c9359f1830e3f249cbb307b225adac" have entirely different histories.

7 changed files with 68 additions and 162 deletions

View File

@ -1,24 +1,17 @@
---
# vi: ts=2 sw=2 et:
extraction: extraction:
cpp: cpp:
prepare: prepare:
packages: packages:
- python3-pip
- python3-setuptools
- python3-wheel
- libpwquality-dev - libpwquality-dev
- libfdisk-dev - libfdisk-dev
- libp11-kit-dev - libp11-kit-dev
- libssl-dev - libssl-dev
before_index: after_prepare:
# /tmp has `noexec` set in the LGTM infra which breaks meson's - pip3 install meson
# compilation checks. Let's temporarily override TMPDIR to /var/tmp which - export PATH="$HOME/.local/bin/:$PATH"
# should work as expected
# See: https://discuss.lgtm.com/t/meson-fails-to-determine-sizes-of-basic-data-types/2639
- export TMPDIR=/var/tmp
index:
build_command:
- meson build
- ninja -C build
python: python:
python_setup: python_setup:
version: 3 version: 3

View File

@ -308,35 +308,18 @@
<varlistentry> <varlistentry>
<term><varname>IPv6Token=</varname></term> <term><varname>IPv6Token=</varname></term>
<listitem> <listitem>
<para>Specifies an optional address generation mode and a required IPv6 address. If <para>Specifies an optional address generation mechanism and an optional address prefix. If
the mode is present, the two parts must be separated with a colon the mechanism is present, the two parts must be separated with a colon
<literal><replaceable>mode</replaceable>:<replaceable>address</replaceable></literal>. The <literal><replaceable>type</replaceable>:<replaceable>prefix</replaceable></literal>. The
address generation mode may be either <constant>prefixstable</constant> or address generation mechanism may be either <constant>prefixstable</constant> or
<constant>static</constant>. If not specified, <constant>static</constant> is assumed. <constant>static</constant>. If not specified, <constant>static</constant> is assumed. When
</para> set to <literal>prefixstable</literal> a method for generating IPv6 Interface Identifiers to
<para>When the mode is set to <constant>static</constant>, or unspecified, the lower bits of be used with IPv6 Stateless Address Autocon figuration (SLAAC). See
the supplied address are combined with the upper bits of a prefix received in a Router Advertisement <ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink>. When IPv6 address is set,
message to form a complete address. Note that if multiple prefixes are received in an RA message, or in indicates the 64-bit interface part of SLAAC IPv6 addresses for this link.</para>
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 <para>Note that the token is only ever used for SLAAC, and not for DHCPv6 addresses, even in
MAC address in the hash used to compute the interface identifier, so if either of those are changed the resulting the case DHCP is requested by router advertisement. By default, the token is autogenerated.
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>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -187,7 +187,7 @@ static int address_compare_func(const Address *a1, const Address *a2) {
} }
} }
DEFINE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func); DEFINE_PRIVATE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func);
bool address_equal(Address *a1, Address *a2) { bool address_equal(Address *a1, Address *a2) {
if (a1 == a2) if (a1 == a2)

View File

@ -67,8 +67,6 @@ int configure_ipv4_duplicate_address_detection(Link *link, Address *address);
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free); DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
extern const struct hash_ops address_hash_ops;
CONFIG_PARSER_PROTOTYPE(config_parse_address); CONFIG_PARSER_PROTOTYPE(config_parse_address);
CONFIG_PARSER_PROTOTYPE(config_parse_broadcast); CONFIG_PARSER_PROTOTYPE(config_parse_broadcast);
CONFIG_PARSER_PROTOTYPE(config_parse_label); CONFIG_PARSER_PROTOTYPE(config_parse_label);

View File

@ -254,109 +254,62 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
return 0; return 0;
} }
static int ndisc_router_generate_addresses(Link *link, unsigned prefixlen, uint32_t lifetime_preferred, Address *address, Set **ret) { static int ndisc_router_generate_address(Link *link, unsigned prefixlen, uint32_t lifetime_preferred, Address *address) {
_cleanup_set_free_free_ Set *addresses = NULL; bool prefix = false;
struct in6_addr addr; struct in6_addr addr;
IPv6Token *j; IPv6Token *j;
Iterator i; Iterator i;
int r; int r;
assert(link);
assert(address); assert(address);
assert(ret); assert(link);
addresses = set_new(&address_hash_ops);
if (!addresses)
return log_oom();
addr = address->in_addr.in6; addr = address->in_addr.in6;
ORDERED_HASHMAP_FOREACH(j, link->network->ipv6_tokens, i) { ORDERED_HASHMAP_FOREACH(j, link->network->ipv6_tokens, i)
bool have_address = false;
_cleanup_(address_freep) Address *new_address = NULL;
r = address_new(&new_address);
if (r < 0)
return log_oom();
*new_address = *address;
if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
&& memcmp(&j->prefix, &addr, FAMILY_ADDRESS_SIZE(address->family)) == 0) { && memcmp(&j->prefix, &addr, FAMILY_ADDRESS_SIZE(address->family)) == 0) {
/* 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++) { 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->in_addr.in6); r = make_stableprivate_address(link, &j->prefix, prefixlen, j->dad_counter, &address->in_addr.in6);
if (r < 0) if (r < 0)
break; return r;
if (stableprivate_address_is_valid(&new_address->in_addr.in6)) { if (stableprivate_address_is_valid(&address->in_addr.in6)) {
have_address = true; prefix = true;
break; break;
} }
} }
} else if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC) { } else if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC) {
memcpy(((uint8_t *)&new_address->in_addr.in6) + 8, ((uint8_t *) &j->prefix) + 8, 8); memcpy(((uint8_t *)&address->in_addr.in6) + 8, ((uint8_t *) &j->prefix) + 8, 8);
have_address = true; prefix = true;
break;
} }
if (have_address) { /* fallback to eui64 if prefixstable or static do not match */
new_address->prefixlen = prefixlen; if (!prefix) {
new_address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
new_address->cinfo.ifa_prefered = lifetime_preferred;
r = set_put(addresses, new_address);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store address: %m");
TAKE_PTR(new_address);
}
}
/* fall back to EUI-64 if no tokens provided addresses */
if (set_isempty(addresses)) {
_cleanup_(address_freep) Address *new_address = NULL;
r = address_new(&new_address);
if (r < 0)
return log_oom();
*new_address = *address;
/* see RFC4291 section 2.5.1 */ /* see RFC4291 section 2.5.1 */
new_address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0]; address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
new_address->in_addr.in6.s6_addr[8] ^= 1 << 1; address->in_addr.in6.s6_addr[8] ^= 1 << 1;
new_address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1]; address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
new_address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2]; address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
new_address->in_addr.in6.s6_addr[11] = 0xff; address->in_addr.in6.s6_addr[11] = 0xff;
new_address->in_addr.in6.s6_addr[12] = 0xfe; address->in_addr.in6.s6_addr[12] = 0xfe;
new_address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3]; address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
new_address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4]; address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
new_address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5]; address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
new_address->prefixlen = prefixlen;
new_address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
new_address->cinfo.ifa_prefered = lifetime_preferred;
r = set_put(addresses, new_address);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store address: %m");
TAKE_PTR(new_address);
} }
*ret = TAKE_PTR(addresses); address->prefixlen = prefixlen;
address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
address->cinfo.ifa_prefered = lifetime_preferred;
return 0; return 0;
} }
static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) { static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining; uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
_cleanup_set_free_free_ Set *addresses = NULL;
_cleanup_(address_freep) Address *address = NULL; _cleanup_(address_freep) Address *address = NULL;
Address *existing_address;
unsigned prefixlen; unsigned prefixlen;
usec_t time_now; usec_t time_now;
Address *existing_address, *a;
Iterator i;
int r; int r;
assert(link); assert(link);
@ -391,39 +344,36 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix address: %m"); return log_link_error_errno(link, r, "Failed to get prefix address: %m");
r = ndisc_router_generate_addresses(link, prefixlen, lifetime_preferred, address, &addresses); r = ndisc_router_generate_address(link, prefixlen, lifetime_preferred, address);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to generate SLAAC addresses: %m"); return log_link_error_errno(link, r, "Falied to generate prefix stable address: %m");
SET_FOREACH(a, addresses, i) {
/* see RFC4862 section 5.5.3.e */ /* see RFC4862 section 5.5.3.e */
r = address_get(link, a->family, &a->in_addr, a->prefixlen, &existing_address); r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address);
if (r > 0) { if (r > 0) {
lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC; lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining) if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
a->cinfo.ifa_valid = lifetime_valid; address->cinfo.ifa_valid = lifetime_valid;
else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN) else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
a->cinfo.ifa_valid = lifetime_remaining; address->cinfo.ifa_valid = lifetime_remaining;
else else
a->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN; address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
} else if (lifetime_valid > 0) } else if (lifetime_valid > 0)
a->cinfo.ifa_valid = lifetime_valid; address->cinfo.ifa_valid = lifetime_valid;
else else
return 0; /* see RFC4862 section 5.5.3.d */ return 0; /* see RFC4862 section 5.5.3.d */
if (a->cinfo.ifa_valid == 0) if (address->cinfo.ifa_valid == 0)
continue; return 0;
r = address_configure(a, link, ndisc_netlink_address_message_handler, true); r = address_configure(address, link, ndisc_netlink_address_message_handler, true);
if (r < 0) { if (r < 0) {
log_link_warning_errno(link, r, "Could not set SLAAC address: %m"); log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
link_enter_failed(link); link_enter_failed(link);
return r; return r;
} }
if (r > 0) if (r > 0)
link->ndisc_messages++; link->ndisc_messages++;
}
return 0; return 0;
} }

View File

@ -1,7 +0,0 @@
[Match]
Name=veth99
[Network]
IPv6AcceptRA=true
IPv6Token=::1a:2b:3c:4d
IPv6Token=::fa:de:ca:fe

View File

@ -2685,7 +2685,6 @@ class NetworkdRATests(unittest.TestCase, Utilities):
'ipv6-prefix-veth.network', 'ipv6-prefix-veth.network',
'ipv6-prefix-veth-token-static.network', 'ipv6-prefix-veth-token-static.network',
'ipv6-prefix-veth-token-static-explicit.network', 'ipv6-prefix-veth-token-static-explicit.network',
'ipv6-prefix-veth-token-static-multiple.network',
'ipv6-prefix-veth-token-prefixstable.network'] 'ipv6-prefix-veth-token-prefixstable.network']
def setUp(self): def setUp(self):
@ -2729,16 +2728,6 @@ class NetworkdRATests(unittest.TestCase, Utilities):
print(output) print(output)
self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d') self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d')
def test_ipv6_token_static_multiple(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
start_networkd()
self.wait_online(['veth99:routable', 'veth-peer:degraded'])
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d')
self.assertRegex(output, '2002:da8:1:0:fa:de:ca:fe')
def test_ipv6_token_prefixstable(self): def test_ipv6_token_prefixstable(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network') copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
start_networkd() start_networkd()