X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-radv.c;h=817c15764ac174491a6649816653945c96edc74e;hb=db9ecf050165fd1033c6f81485917e229c4be537;hp=f5f8ec65ed7d4980820dadd8c7a9e93b728d7557;hpb=bb2294e4545ef2685d52ef27e7bc8a5a265d530b;p=thirdparty%2Fsystemd.git diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index f5f8ec65ed7..817c15764ac 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2017 Intel Corporation. All rights reserved. ***/ @@ -7,35 +7,32 @@ #include #include "dns-domain.h" -#include "networkd-address.h" +#include "networkd-link.h" #include "networkd-manager.h" +#include "networkd-network.h" #include "networkd-radv.h" #include "parse-util.h" -#include "sd-radv.h" #include "string-util.h" #include "string-table.h" #include "strv.h" -void prefix_free(Prefix *prefix) { +Prefix *prefix_free(Prefix *prefix) { if (!prefix) - return; + return NULL; if (prefix->network) { - LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix); - assert(prefix->network->n_static_prefixes > 0); - prefix->network->n_static_prefixes--; - - if (prefix->section) - hashmap_remove(prefix->network->prefixes_by_section, - prefix->section); + assert(prefix->section); + hashmap_remove(prefix->network->prefixes_by_section, prefix->section); } network_config_section_free(prefix->section); sd_radv_prefix_unref(prefix->radv_prefix); - free(prefix); + return mfree(prefix); } +DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free); + static int prefix_new(Prefix **ret) { _cleanup_(prefix_freep) Prefix *prefix = NULL; @@ -51,29 +48,24 @@ static int prefix_new(Prefix **ret) { return 0; } -static int prefix_new_static(Network *network, const char *filename, - unsigned section_line, Prefix **ret) { +static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) { _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; _cleanup_(prefix_freep) Prefix *prefix = NULL; int r; assert(network); assert(ret); - assert(!!filename == (section_line > 0)); - - if (filename) { - r = network_config_section_new(filename, section_line, &n); - if (r < 0) - return r; + assert(filename); + assert(section_line > 0); - if (section_line) { - prefix = hashmap_get(network->prefixes_by_section, n); - if (prefix) { - *ret = TAKE_PTR(prefix); + r = network_config_section_new(filename, section_line, &n); + if (r < 0) + return r; - return 0; - } - } + prefix = hashmap_get(network->prefixes_by_section, n); + if (prefix) { + *ret = TAKE_PTR(prefix); + return 0; } r = prefix_new(&prefix); @@ -81,26 +73,38 @@ static int prefix_new_static(Network *network, const char *filename, return r; prefix->network = network; - LIST_APPEND(prefixes, network->static_prefixes, prefix); - network->n_static_prefixes++; - - if (filename) { - prefix->section = TAKE_PTR(n); + prefix->section = TAKE_PTR(n); - r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops); - if (r < 0) - return r; + r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops); + if (r < 0) + return r; - r = hashmap_put(network->prefixes_by_section, prefix->section, prefix); - if (r < 0) - return r; - } + r = hashmap_put(network->prefixes_by_section, prefix->section, prefix); + if (r < 0) + return r; *ret = TAKE_PTR(prefix); return 0; } +RoutePrefix *route_prefix_free(RoutePrefix *prefix) { + if (!prefix) + return NULL; + + if (prefix->network) { + assert(prefix->section); + hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section); + } + + network_config_section_free(prefix->section); + sd_radv_route_prefix_unref(prefix->radv_route_prefix); + + return mfree(prefix); +} + +DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free); + static int route_prefix_new(RoutePrefix **ret) { _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL; @@ -116,49 +120,24 @@ static int route_prefix_new(RoutePrefix **ret) { return 0; } -void route_prefix_free(RoutePrefix *prefix) { - if (!prefix) - return; - - if (prefix->network) { - LIST_REMOVE(route_prefixes, prefix->network->static_route_prefixes, prefix); - assert(prefix->network->n_static_route_prefixes > 0); - prefix->network->n_static_route_prefixes--; - - if (prefix->section) - hashmap_remove(prefix->network->route_prefixes_by_section, - prefix->section); - } - - network_config_section_free(prefix->section); - sd_radv_route_prefix_unref(prefix->radv_route_prefix); - - free(prefix); -} - -static int route_prefix_new_static(Network *network, const char *filename, - unsigned section_line, RoutePrefix **ret) { +static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) { _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL; int r; assert(network); assert(ret); - assert(!!filename == (section_line > 0)); - - if (filename) { - r = network_config_section_new(filename, section_line, &n); - if (r < 0) - return r; + assert(filename); + assert(section_line > 0); - if (section_line) { - prefix = hashmap_get(network->route_prefixes_by_section, n); - if (prefix) { - *ret = TAKE_PTR(prefix); + r = network_config_section_new(filename, section_line, &n); + if (r < 0) + return r; - return 0; - } - } + prefix = hashmap_get(network->route_prefixes_by_section, n); + if (prefix) { + *ret = TAKE_PTR(prefix); + return 0; } r = route_prefix_new(&prefix); @@ -166,36 +145,81 @@ static int route_prefix_new_static(Network *network, const char *filename, return r; prefix->network = network; - LIST_APPEND(route_prefixes, network->static_route_prefixes, prefix); - network->n_static_route_prefixes++; - - if (filename) { - prefix->section = TAKE_PTR(n); + prefix->section = TAKE_PTR(n); - r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops); - if (r < 0) - return r; + r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops); + if (r < 0) + return r; - r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix); - if (r < 0) - return r; - } + r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix); + if (r < 0) + return r; *ret = TAKE_PTR(prefix); return 0; } -int config_parse_prefix(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +void network_drop_invalid_prefixes(Network *network) { + Prefix *prefix; + + assert(network); + + HASHMAP_FOREACH(prefix, network->prefixes_by_section) + if (section_is_invalid(prefix->section)) + prefix_free(prefix); +} + +void network_drop_invalid_route_prefixes(Network *network) { + RoutePrefix *prefix; + + assert(network); + + HASHMAP_FOREACH(prefix, network->route_prefixes_by_section) + if (section_is_invalid(prefix->section)) + route_prefix_free(prefix); +} + +void network_adjust_radv(Network *network) { + assert(network); + + /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */ + + if (network->dhcp6_pd < 0) + /* For backward compatibility. */ + network->dhcp6_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6); + + if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) { + if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) + log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. " + "Disabling IPv6PrefixDelegation=.", network->filename); + + network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE; + } + + if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) { + network->n_router_dns = 0; + network->router_dns = mfree(network->router_dns); + network->router_search_domains = ordered_set_free(network->router_search_domains); + } + + if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) { + network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free); + network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free); + } +} + +int config_parse_prefix( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { Network *network = userdata; _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; @@ -211,37 +235,40 @@ int config_parse_prefix(const char *unit, r = prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue); return 0; } - if (sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen) < 0) - return -EADDRNOTAVAIL; - - log_syntax(unit, LOG_INFO, filename, line, r, "Found prefix %s", rvalue); + r = sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set radv prefix, ignoring assignment: %s", rvalue); + return 0; + } p = NULL; return 0; } -int config_parse_prefix_flags(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_prefix_flags( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; - int r, val; + int r; assert(filename); assert(section); @@ -251,38 +278,40 @@ int config_parse_prefix_flags(const char *unit, r = prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); r = parse_boolean(rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); return 0; } - val = r; - if (streq(lvalue, "OnLink")) - r = sd_radv_prefix_set_onlink(p->radv_prefix, val); + r = sd_radv_prefix_set_onlink(p->radv_prefix, r); else if (streq(lvalue, "AddressAutoconfiguration")) - r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, val); - if (r < 0) - return r; + r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, r); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue); + return 0; + } p = NULL; return 0; } -int config_parse_prefix_lifetime(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_prefix_lifetime( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; usec_t usec; @@ -296,11 +325,11 @@ int config_parse_prefix_lifetime(const char *unit, r = prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); r = parse_sec(rvalue, &usec); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue); return 0; } @@ -311,8 +340,10 @@ int config_parse_prefix_lifetime(const char *unit, else if (streq(lvalue, "ValidLifetimeSec")) r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix, DIV_ROUND_UP(usec, USEC_PER_SEC)); - if (r < 0) - return r; + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue); + return 0; + } p = NULL; @@ -343,11 +374,11 @@ int config_parse_prefix_assign( r = prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); r = parse_boolean(rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); return 0; @@ -359,16 +390,17 @@ int config_parse_prefix_assign( return 0; } -int config_parse_route_prefix(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_route_prefix( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { Network *network = userdata; _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL; @@ -384,34 +416,37 @@ int config_parse_route_prefix(const char *unit, r = route_prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue); return 0; } - if (sd_radv_prefix_set_route_prefix(p->radv_route_prefix, &in6addr.in6, prefixlen) < 0) - return -EADDRNOTAVAIL; - - log_syntax(unit, LOG_INFO, filename, line, r, "Found route prefix %s", rvalue); + r = sd_radv_prefix_set_route_prefix(p->radv_route_prefix, &in6addr.in6, prefixlen); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set route prefix, ignoring assignment: %m"); + return 0; + } p = NULL; return 0; } -int config_parse_route_prefix_lifetime(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_route_prefix_lifetime( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL; usec_t usec; @@ -425,41 +460,43 @@ int config_parse_route_prefix_lifetime(const char *unit, r = route_prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); r = parse_sec(rvalue, &usec); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, + log_syntax(unit, LOG_WARNING, filename, line, r, "Route lifetime is invalid, ignoring assignment: %s", rvalue); return 0; } /* a value of 0xffffffff represents infinity */ r = sd_radv_route_prefix_set_lifetime(p->radv_route_prefix, DIV_ROUND_UP(usec, USEC_PER_SEC)); - if (r < 0) - return r; + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to set route lifetime, ignoring assignment: %m"); + return 0; + } p = NULL; return 0; } -static int radv_get_ip6dns(Network *network, struct in6_addr **dns, - size_t *n_dns) { +static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) { _cleanup_free_ struct in6_addr *addresses = NULL; - size_t i, n_addresses = 0, n_allocated = 0; + size_t n_addresses = 0, n_allocated = 0; assert(network); - assert(dns); - assert(n_dns); + assert(ret_addresses); + assert(ret_size); - for (i = 0; i < network->n_dns; i++) { + for (size_t i = 0; i < network->n_dns; i++) { union in_addr_union *addr; - if (network->dns[i].family != AF_INET6) + if (network->dns[i]->family != AF_INET6) continue; - addr = &network->dns[i].address; + addr = &network->dns[i]->address; if (in_addr_is_null(AF_INET6, addr) || in_addr_is_link_local(AF_INET6, addr) || @@ -472,11 +509,8 @@ static int radv_get_ip6dns(Network *network, struct in6_addr **dns, addresses[n_addresses++] = addr->in6; } - if (addresses) { - *dns = TAKE_PTR(addresses); - - *n_dns = n_addresses; - } + *ret_addresses = TAKE_PTR(addresses); + *ret_size = n_addresses; return n_addresses; } @@ -513,7 +547,7 @@ static int radv_set_dns(Link *link, Link *uplink) { lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC; - r = radv_get_ip6dns(link->network, &dns, &n_dns); + r = network_get_ipv6_dns(link->network, &dns, &n_dns); if (r > 0) goto set_dns; @@ -523,7 +557,7 @@ static int radv_set_dns(Link *link, Link *uplink) { return 0; } - r = radv_get_ip6dns(uplink->network, &dns, &n_dns); + r = network_get_ipv6_dns(uplink->network, &dns, &n_dns); if (r > 0) goto set_dns; } @@ -597,6 +631,15 @@ int radv_emit_dns(Link *link) { return 0; } +static bool link_radv_enabled(Link *link) { + assert(link); + + if (!link_ipv6ll_enabled(link)) + return false; + + return link->network->router_prefix_delegation; +} + int radv_configure(Link *link) { RoutePrefix *q; Prefix *p; @@ -605,15 +648,18 @@ int radv_configure(Link *link) { assert(link); assert(link->network); + if (!link_radv_enabled(link)) + return 0; + r = sd_radv_new(&link->radv); if (r < 0) return r; - r = sd_radv_attach_event(link->radv, NULL, 0); + r = sd_radv_attach_event(link->radv, link->manager->event, 0); if (r < 0) return r; - r = sd_radv_set_mac(link->radv, &link->mac); + r = sd_radv_set_mac(link->radv, &link->hw_addr.addr.ether); if (r < 0) return r; @@ -643,35 +689,95 @@ int radv_configure(Link *link) { return r; } - if (IN_SET(link->network->router_prefix_delegation, - RADV_PREFIX_DELEGATION_STATIC, - RADV_PREFIX_DELEGATION_BOTH)) { - - LIST_FOREACH(prefixes, p, link->network->static_prefixes) { - r = sd_radv_add_prefix(link->radv, p->radv_prefix, false); - if (r == -EEXIST) - continue; - if (r == -ENOEXEC) { - log_link_warning_errno(link, r, "[IPv6Prefix] section configured without Prefix= setting, ignoring section."); - continue; - } - if (r < 0) - return r; + HASHMAP_FOREACH(p, link->network->prefixes_by_section) { + r = sd_radv_add_prefix(link->radv, p->radv_prefix, false); + if (r == -EEXIST) + continue; + if (r == -ENOEXEC) { + log_link_warning_errno(link, r, "[IPv6Prefix] section configured without Prefix= setting, ignoring section."); + continue; } + if (r < 0) + return r; + } - LIST_FOREACH(route_prefixes, q, link->network->static_route_prefixes) { - r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false); - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } + HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) { + r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false); + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } + + return 0; +} + +int radv_update_mac(Link *link) { + bool restart; + int r; + + assert(link); + + if (!link->radv) + return 0; + + restart = sd_radv_is_running(link->radv); + r = sd_radv_stop(link->radv); + if (r < 0) + return r; + + r = sd_radv_set_mac(link->radv, &link->hw_addr.addr.ether); + if (r < 0) + return r; + + if (restart) { + r = sd_radv_start(link->radv); + if (r < 0) + return r; } return 0; } +int radv_add_prefix( + Link *link, + const struct in6_addr *prefix, + uint8_t prefix_len, + uint32_t lifetime_preferred, + uint32_t lifetime_valid) { + + _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL; + int r; + + assert(link); + + if (!link->radv) + return 0; + + r = sd_radv_prefix_new(&p); + if (r < 0) + return r; + + r = sd_radv_prefix_set_prefix(p, prefix, prefix_len); + if (r < 0) + return r; + + r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred); + if (r < 0) + return r; + + r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid); + if (r < 0) + return r; + + r = sd_radv_add_prefix(link->radv, p, true); + if (r < 0 && r != -EEXIST) + return r; + + return 0; +} + int config_parse_radv_dns( const char *unit, const char *filename, @@ -685,14 +791,19 @@ int config_parse_radv_dns( void *userdata) { Network *n = data; - const char *p = rvalue; int r; assert(filename); assert(lvalue); assert(rvalue); - for (;;) { + if (isempty(rvalue)) { + n->n_router_dns = 0; + n->router_dns = mfree(n->router_dns); + return 0; + } + + for (const char *p = rvalue;;) { _cleanup_free_ char *w = NULL; union in_addr_union a; @@ -700,25 +811,25 @@ int config_parse_radv_dns( if (r == -ENOMEM) return log_oom(); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract word, ignoring: %s", rvalue); return 0; } if (r == 0) - break; + return 0; if (streq(w, "_link_local")) a = IN_ADDR_NULL; else { r = in_addr_from_string(AF_INET6, w, &a); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse DNS server address, ignoring: %s", w); continue; } if (in_addr_is_null(AF_INET6, &a)) { - log_syntax(unit, LOG_ERR, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, 0, "DNS server address is null, ignoring: %s", w); continue; } @@ -732,8 +843,6 @@ int config_parse_radv_dns( m[n->n_router_dns++] = a.in6; n->router_dns = m; } - - return 0; } int config_parse_radv_search_domains( @@ -749,53 +858,55 @@ int config_parse_radv_search_domains( void *userdata) { Network *n = data; - const char *p = rvalue; int r; assert(filename); assert(lvalue); assert(rvalue); - for (;;) { + if (isempty(rvalue)) { + n->router_search_domains = ordered_set_free(n->router_search_domains); + return 0; + } + + for (const char *p = rvalue;;) { _cleanup_free_ char *w = NULL, *idna = NULL; r = extract_first_word(&p, &w, NULL, 0); if (r == -ENOMEM) return log_oom(); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract word, ignoring: %s", rvalue); return 0; } if (r == 0) - break; + return 0; r = dns_name_apply_idna(w, &idna); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to apply IDNA to domain name '%s', ignoring: %m", w); continue; } else if (r == 0) /* transfer ownership to simplify subsequent operations */ idna = TAKE_PTR(w); - r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops); + r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free); if (r < 0) - return r; + return log_oom(); r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna)); if (r < 0) - return r; + return log_oom(); } - - return 0; } static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = { - [RADV_PREFIX_DELEGATION_NONE] = "no", + [RADV_PREFIX_DELEGATION_NONE] = "no", [RADV_PREFIX_DELEGATION_STATIC] = "static", - [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6", - [RADV_PREFIX_DELEGATION_BOTH] = "yes", + [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6", + [RADV_PREFIX_DELEGATION_BOTH] = "yes", }; DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN( @@ -815,57 +926,42 @@ int config_parse_router_prefix_delegation( void *data, void *userdata) { - Network *network = userdata; - RADVPrefixDelegation d; + RADVPrefixDelegation val, *ra = data; + int r; assert(filename); - assert(section); assert(lvalue); assert(rvalue); assert(data); - d = radv_prefix_delegation_from_string(rvalue); - if (d < 0) { - log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid router prefix delegation '%s', ignoring assignment.", rvalue); + if (streq(lvalue, "IPv6SendRA")) { + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users + * need to explicitly enable DHCPv6PrefixDelegation=. */ + *ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE; return 0; } - network->router_prefix_delegation = d; - - return 0; -} - -int config_parse_router_preference(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - Network *network = userdata; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - if (streq(rvalue, "high")) - network->router_preference = SD_NDISC_PREFERENCE_HIGH; - else if (STR_IN_SET(rvalue, "medium", "normal", "default")) - network->router_preference = SD_NDISC_PREFERENCE_MEDIUM; - else if (streq(rvalue, "low")) - network->router_preference = SD_NDISC_PREFERENCE_LOW; - else - log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue); + /* For backward compatibility */ + val = radv_prefix_delegation_from_string(rvalue); + if (val < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + *ra = val; return 0; } -int config_parse_router_prefix_subnet_id(const char *unit, +int config_parse_router_preference( + const char *unit, const char *filename, unsigned line, const char *section, @@ -875,29 +971,24 @@ int config_parse_router_prefix_subnet_id(const char *unit, const char *rvalue, void *data, void *userdata) { + Network *network = userdata; - uint64_t t; - int r; assert(filename); + assert(section); assert(lvalue); assert(rvalue); assert(data); - if (isempty(rvalue) || streq(rvalue, "auto")) { - network->router_prefix_subnet_id = -1; - return 0; - } - - r = safe_atoux64(rvalue, &t); - if (r < 0 || t > INT64_MAX) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Subnet id '%s' is invalid, ignoring assignment.", - rvalue); - return 0; - } - - network->router_prefix_subnet_id = (int64_t)t; + if (streq(rvalue, "high")) + network->router_preference = SD_NDISC_PREFERENCE_HIGH; + else if (STR_IN_SET(rvalue, "medium", "normal", "default")) + network->router_preference = SD_NDISC_PREFERENCE_MEDIUM; + else if (streq(rvalue, "low")) + network->router_preference = SD_NDISC_PREFERENCE_LOW; + else + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid router preference, ignoring assignment: %s", rvalue); return 0; }