From: Yu Watanabe Date: Fri, 17 Sep 2021 11:54:47 +0000 (+0900) Subject: network: radv: reorder functions X-Git-Tag: v250-rc1~552^2~22 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0943b3b7a413dc8b05cc41627754c77257f1f8ac;p=thirdparty%2Fsystemd.git network: radv: reorder functions In other files, we usually (but not always) place functions in the following order: - network_adjust_xxx(), which applies default or updates settings specified in .network files, - link_xxx_enabled(), which checks if the functionality is enabled, - xxx_new() and xxx_free(), allocator and deallocator for sections, - functions which apply/update/remove configs - validators of section, - conf parsers. This does not change each function, but just changes the order. --- diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index c734c4c3b48..6a873d76691 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -19,6 +19,44 @@ #include "string-table.h" #include "strv.h" +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); + } +} + +static bool link_radv_enabled(Link *link) { + assert(link); + + if (!link_ipv6ll_enabled(link)) + return false; + + return link->network->router_prefix_delegation; +} + Prefix *prefix_free(Prefix *prefix) { if (!prefix) return NULL; @@ -155,64 +193,6 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig return 0; } -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); - } -} - -static bool link_radv_enabled(Link *link) { - assert(link); - - if (!link_ipv6ll_enabled(link)) - return false; - - return link->network->router_prefix_delegation; -} - int link_request_radv_addresses(Link *link) { Prefix *p; int r; @@ -252,704 +232,724 @@ int link_request_radv_addresses(Link *link) { 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) { +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 n_addresses = 0; - Network *network = userdata; - _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; - uint8_t prefixlen = 64; - union in_addr_union in6addr; - int r; + assert(network); + assert(ret_addresses); + assert(ret_size); - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); + for (size_t i = 0; i < network->n_dns; i++) { + union in_addr_union *addr; - r = prefix_new_static(network, filename, section_line, &p); - if (r < 0) - return log_oom(); + if (network->dns[i]->family != AF_INET6) + continue; - r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue); - return 0; - } + addr = &network->dns[i]->address; - 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; + if (in_addr_is_null(AF_INET6, addr) || + in_addr_is_link_local(AF_INET6, addr) || + in_addr_is_localhost(AF_INET6, addr)) + continue; + + if (!GREEDY_REALLOC(addresses, n_addresses + 1)) + return -ENOMEM; + + addresses[n_addresses++] = addr->in6; } - p = NULL; + *ret_addresses = TAKE_PTR(addresses); + *ret_size = n_addresses; - return 0; + return n_addresses; } -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; +static int radv_set_dns(Link *link, Link *uplink) { + _cleanup_free_ struct in6_addr *dns = NULL; + usec_t lifetime_usec; + size_t n_dns; int r; - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = prefix_new_static(network, filename, section_line, &p); - if (r < 0) - return log_oom(); - - r = parse_boolean(rvalue); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + if (!link->network->router_emit_dns) return 0; - } - if (streq(lvalue, "OnLink")) - 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, r); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue); - return 0; - } + if (link->network->router_dns) { + struct in6_addr *p; - p = NULL; + dns = new(struct in6_addr, link->network->n_router_dns); + if (!dns) + return -ENOMEM; - return 0; -} + p = dns; + for (size_t i = 0; i < link->network->n_router_dns; i++) + if (in6_addr_is_null(&link->network->router_dns[i])) { + if (in6_addr_is_set(&link->ipv6ll_address)) + *(p++) = link->ipv6ll_address; + } else + *(p++) = link->network->router_dns[i]; -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) { + n_dns = p - dns; + lifetime_usec = link->network->router_dns_lifetime_usec; - Network *network = userdata; - _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; - usec_t usec; - int r; + goto set_dns; + } - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); + lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC; - r = prefix_new_static(network, filename, section_line, &p); - if (r < 0) - return log_oom(); + r = network_get_ipv6_dns(link->network, &dns, &n_dns); + if (r > 0) + goto set_dns; - r = parse_sec(rvalue, &usec); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue); - return 0; + if (uplink) { + assert(uplink->network); + + r = network_get_ipv6_dns(uplink->network, &dns, &n_dns); + if (r > 0) + goto set_dns; } - /* a value of 0xffffffff represents infinity */ - if (streq(lvalue, "PreferredLifetimeSec")) - r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix, - DIV_ROUND_UP(usec, USEC_PER_SEC)); - 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) { - 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_assign( - 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; - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); +set_dns: + return sd_radv_set_rdnss(link->radv, + DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC), + dns, n_dns); +} - r = prefix_new_static(network, filename, section_line, &p); - if (r < 0) - return log_oom(); +static int radv_set_domains(Link *link, Link *uplink) { + OrderedSet *search_domains; + usec_t lifetime_usec; + _cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */ - r = parse_boolean(rvalue); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse %s=, ignoring assignment: %s", - lvalue, rvalue); + if (!link->network->router_emit_domains) return 0; - } - - p->assign = r; - p = NULL; - return 0; -} + search_domains = link->network->router_search_domains; + lifetime_usec = link->network->router_dns_lifetime_usec; -int config_parse_prefix_metric( - 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) { + if (search_domains) + goto set_domains; - Network *network = userdata; - _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; - int r; + lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC; - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); + search_domains = link->network->search_domains; + if (search_domains) + goto set_domains; - r = prefix_new_static(network, filename, section_line, &p); - if (r < 0) - return log_oom(); + if (uplink) { + assert(uplink->network); - r = safe_atou32(rvalue, &p->route_metric); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse %s=, ignoring assignment: %s", - lvalue, rvalue); - return 0; + search_domains = uplink->network->search_domains; + if (search_domains) + goto set_domains; } - TAKE_PTR(p); - 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) { +set_domains: + s = ordered_set_get_strv(search_domains); + if (!s) + return log_oom(); - Network *network = userdata; - _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL; - uint8_t prefixlen = 64; - union in_addr_union in6addr; - int r; + return sd_radv_set_dnssl(link->radv, + DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC), + s); - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); +} - r = route_prefix_new_static(network, filename, section_line, &p); - if (r < 0) - return log_oom(); +static int radv_find_uplink(Link *link, Link **ret) { + assert(link); - r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue); - return 0; - } + if (link->network->router_uplink_name) + return link_get_by_name(link->manager, link->network->router_uplink_name, ret); - 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"); + if (link->network->router_uplink_index > 0) + return link_get_by_index(link->manager, link->network->router_uplink_index, ret); + + if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) { + /* It is not necessary to propagate error in automatic selection. */ + if (manager_find_uplink(link->manager, AF_INET6, link, ret) < 0) + *ret = NULL; return 0; } - p = NULL; - + *ret = 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) { - - Network *network = userdata; - _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL; - usec_t usec; +static int radv_configure(Link *link) { + uint16_t router_lifetime; + Link *uplink = NULL; + RoutePrefix *q; + Prefix *p; int r; - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); + assert(link); + assert(link->network); - r = route_prefix_new_static(network, filename, section_line, &p); + if (link->radv) + return -EBUSY; + + r = sd_radv_new(&link->radv); if (r < 0) - return log_oom(); + return r; - r = parse_sec(rvalue, &usec); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Route lifetime is invalid, ignoring assignment: %s", rvalue); - return 0; - } + r = sd_radv_attach_event(link->radv, link->manager->event, 0); + if (r < 0) + return r; - /* 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) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to set route lifetime, ignoring assignment: %m"); - return 0; - } + r = sd_radv_set_mac(link->radv, &link->hw_addr.ether); + if (r < 0) + return r; - p = NULL; + r = sd_radv_set_ifindex(link->radv, link->ifindex); + if (r < 0) + return r; - return 0; -} + r = sd_radv_set_managed_information(link->radv, link->network->router_managed); + if (r < 0) + return r; -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 n_addresses = 0; + r = sd_radv_set_other_information(link->radv, link->network->router_other_information); + if (r < 0) + return r; - assert(network); - assert(ret_addresses); - assert(ret_size); + /* a value of UINT16_MAX represents infinity, 0x0 means this host is not a router */ + if (link->network->router_lifetime_usec == USEC_INFINITY) + router_lifetime = UINT16_MAX; + else if (link->network->router_lifetime_usec > (UINT16_MAX - 1) * USEC_PER_SEC) + router_lifetime = UINT16_MAX - 1; + else + router_lifetime = DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC); - for (size_t i = 0; i < network->n_dns; i++) { - union in_addr_union *addr; + r = sd_radv_set_router_lifetime(link->radv, router_lifetime); + if (r < 0) + return r; - if (network->dns[i]->family != AF_INET6) - continue; + if (router_lifetime > 0) { + r = sd_radv_set_preference(link->radv, link->network->router_preference); + if (r < 0) + return r; + } - addr = &network->dns[i]->address; + 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; + } - if (in_addr_is_null(AF_INET6, addr) || - in_addr_is_link_local(AF_INET6, addr) || - in_addr_is_localhost(AF_INET6, addr)) + 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; + } - if (!GREEDY_REALLOC(addresses, n_addresses + 1)) - return -ENOMEM; + (void) radv_find_uplink(link, &uplink); - addresses[n_addresses++] = addr->in6; - } + r = radv_set_dns(link, uplink); + if (r < 0) + return log_link_debug_errno(link, r, "Could not set RA DNS: %m"); - *ret_addresses = TAKE_PTR(addresses); - *ret_size = n_addresses; + r = radv_set_domains(link, uplink); + if (r < 0) + return log_link_debug_errno(link, r, "Could not set RA Domains: %m"); - return n_addresses; + return 0; } -static int radv_set_dns(Link *link, Link *uplink) { - _cleanup_free_ struct in6_addr *dns = NULL; - usec_t lifetime_usec; - size_t n_dns; +int radv_update_mac(Link *link) { + bool restart; int r; - if (!link->network->router_emit_dns) - return 0; + assert(link); - if (link->network->router_dns) { - struct in6_addr *p; + if (!link->radv) + return 0; - dns = new(struct in6_addr, link->network->n_router_dns); - if (!dns) - return -ENOMEM; + restart = sd_radv_is_running(link->radv); - p = dns; - for (size_t i = 0; i < link->network->n_router_dns; i++) - if (in6_addr_is_null(&link->network->router_dns[i])) { - if (in6_addr_is_set(&link->ipv6ll_address)) - *(p++) = link->ipv6ll_address; - } else - *(p++) = link->network->router_dns[i]; + r = sd_radv_stop(link->radv); + if (r < 0) + return r; - n_dns = p - dns; - lifetime_usec = link->network->router_dns_lifetime_usec; + r = sd_radv_set_mac(link->radv, &link->hw_addr.ether); + if (r < 0) + return r; - goto set_dns; + if (restart) { + r = sd_radv_start(link->radv); + if (r < 0) + return r; } - lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC; + return 0; +} - r = network_get_ipv6_dns(link->network, &dns, &n_dns); - if (r > 0) - goto set_dns; +static int radv_is_ready_to_configure(Link *link) { + bool needs_uplink = false; + int r; - if (uplink) { - assert(uplink->network); + assert(link); + assert(link->network); - r = network_get_ipv6_dns(uplink->network, &dns, &n_dns); - if (r > 0) - goto set_dns; - } + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + return false; - return 0; + if (in6_addr_is_null(&link->ipv6ll_address)) + return false; -set_dns: - return sd_radv_set_rdnss(link->radv, - DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC), - dns, n_dns); -} + if (link->network->router_emit_dns && !link->network->router_dns) { + _cleanup_free_ struct in6_addr *dns = NULL; + size_t n_dns; -static int radv_set_domains(Link *link, Link *uplink) { - OrderedSet *search_domains; - usec_t lifetime_usec; - _cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */ + r = network_get_ipv6_dns(link->network, &dns, &n_dns); + if (r < 0) + return r; - if (!link->network->router_emit_domains) - return 0; + needs_uplink = r == 0; + } - search_domains = link->network->router_search_domains; - lifetime_usec = link->network->router_dns_lifetime_usec; + if (link->network->router_emit_domains && + !link->network->router_search_domains && + !link->network->search_domains) + needs_uplink = true; + + if (needs_uplink) { + Link *uplink = NULL; - if (search_domains) - goto set_domains; + if (radv_find_uplink(link, &uplink) < 0) + return false; - lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC; + if (uplink && !uplink->network) + return false; + } - search_domains = link->network->search_domains; - if (search_domains) - goto set_domains; + return true; +} - if (uplink) { - assert(uplink->network); +int request_process_radv(Request *req) { + Link *link; + int r; - search_domains = uplink->network->search_domains; - if (search_domains) - goto set_domains; - } + assert(req); + assert(req->link); + assert(req->type == REQUEST_TYPE_RADV); - return 0; + link = req->link; -set_domains: - s = ordered_set_get_strv(search_domains); - if (!s) - return log_oom(); + r = radv_is_ready_to_configure(link); + if (r <= 0) + return r; - return sd_radv_set_dnssl(link->radv, - DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC), - s); + r = radv_configure(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Advertisement engine: %m"); + if (link_has_carrier(link)) { + r = sd_radv_start(link->radv); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start IPv6 Router Advertisement engine: %m"); + } + + log_link_debug(link, "IPv6 Router Advertisement engine is configured%s.", + link_has_carrier(link) ? " and started." : ""); + return 1; } -static int radv_find_uplink(Link *link, Link **ret) { - assert(link); +int link_request_radv(Link *link) { + int r; - if (link->network->router_uplink_name) - return link_get_by_name(link->manager, link->network->router_uplink_name, ret); + assert(link); - if (link->network->router_uplink_index > 0) - return link_get_by_index(link->manager, link->network->router_uplink_index, ret); + if (!link_radv_enabled(link)) + return 0; - if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) { - /* It is not necessary to propagate error in automatic selection. */ - if (manager_find_uplink(link->manager, AF_INET6, link, ret) < 0) - *ret = NULL; + if (link->radv) return 0; - } - *ret = NULL; + r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m"); + + log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine."); return 0; } -static int radv_configure(Link *link) { - uint16_t router_lifetime; - Link *uplink = NULL; - RoutePrefix *q; - Prefix *p; +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); - assert(link->network); - if (link->radv) - return -EBUSY; + if (!link->radv) + return 0; - r = sd_radv_new(&link->radv); + r = sd_radv_prefix_new(&p); if (r < 0) return r; - r = sd_radv_attach_event(link->radv, link->manager->event, 0); + r = sd_radv_prefix_set_prefix(p, prefix, prefix_len); if (r < 0) return r; - r = sd_radv_set_mac(link->radv, &link->hw_addr.ether); + r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred); if (r < 0) return r; - r = sd_radv_set_ifindex(link->radv, link->ifindex); + r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid); if (r < 0) return r; - r = sd_radv_set_managed_information(link->radv, link->network->router_managed); - if (r < 0) + r = sd_radv_add_prefix(link->radv, p, true); + if (r < 0 && r != -EEXIST) return r; - r = sd_radv_set_other_information(link->radv, link->network->router_other_information); - if (r < 0) - return r; + return 0; +} - /* a value of UINT16_MAX represents infinity, 0x0 means this host is not a router */ - if (link->network->router_lifetime_usec == USEC_INFINITY) - router_lifetime = UINT16_MAX; - else if (link->network->router_lifetime_usec > (UINT16_MAX - 1) * USEC_PER_SEC) - router_lifetime = UINT16_MAX - 1; - else - router_lifetime = DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC); +void network_drop_invalid_prefixes(Network *network) { + Prefix *prefix; - r = sd_radv_set_router_lifetime(link->radv, router_lifetime); + 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); +} + +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; + uint8_t prefixlen = 64; + union in_addr_union in6addr; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); - if (router_lifetime > 0) { - r = sd_radv_set_preference(link->radv, link->network->router_preference); - if (r < 0) - return r; + r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue); + return 0; } - 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; + 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; } - 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; - } + p = NULL; - (void) radv_find_uplink(link, &uplink); + return 0; +} - r = radv_set_dns(link, uplink); - if (r < 0) - return log_link_debug_errno(link, r, "Could not set RA DNS: %m"); +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) { - r = radv_set_domains(link, uplink); + Network *network = userdata; + _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = prefix_new_static(network, filename, section_line, &p); if (r < 0) - return log_link_debug_errno(link, r, "Could not set RA Domains: %m"); + return log_oom(); + + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + if (streq(lvalue, "OnLink")) + 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, 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 radv_update_mac(Link *link) { - bool restart; +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; int r; - assert(link); - - if (!link->radv) - return 0; - - restart = sd_radv_is_running(link->radv); + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); - r = sd_radv_stop(link->radv); + r = prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); - r = sd_radv_set_mac(link->radv, &link->hw_addr.ether); - if (r < 0) - return r; + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue); + return 0; + } - if (restart) { - r = sd_radv_start(link->radv); - if (r < 0) - return r; + /* a value of 0xffffffff represents infinity */ + if (streq(lvalue, "PreferredLifetimeSec")) + r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix, + DIV_ROUND_UP(usec, USEC_PER_SEC)); + 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) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue); + return 0; } + p = NULL; + return 0; } -static int radv_is_ready_to_configure(Link *link) { - bool needs_uplink = false; - int r; - - assert(link); - assert(link->network); - - if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) - return false; +int config_parse_prefix_assign( + 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) { - if (in6_addr_is_null(&link->ipv6ll_address)) - return false; + Network *network = userdata; + _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; + int r; - if (link->network->router_emit_dns && !link->network->router_dns) { - _cleanup_free_ struct in6_addr *dns = NULL; - size_t n_dns; + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); - r = network_get_ipv6_dns(link->network, &dns, &n_dns); - if (r < 0) - return r; + r = prefix_new_static(network, filename, section_line, &p); + if (r < 0) + return log_oom(); - needs_uplink = r == 0; + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", + lvalue, rvalue); + return 0; } - if (link->network->router_emit_domains && - !link->network->router_search_domains && - !link->network->search_domains) - needs_uplink = true; - - if (needs_uplink) { - Link *uplink = NULL; - - if (radv_find_uplink(link, &uplink) < 0) - return false; - - if (uplink && !uplink->network) - return false; - } + p->assign = r; + p = NULL; - return true; + return 0; } -int request_process_radv(Request *req) { - Link *link; - int r; - - assert(req); - assert(req->link); - assert(req->type == REQUEST_TYPE_RADV); +int config_parse_prefix_metric( + 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) { - link = req->link; + Network *network = userdata; + _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; + int r; - r = radv_is_ready_to_configure(link); - if (r <= 0) - return r; + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); - r = radv_configure(link); + r = prefix_new_static(network, filename, section_line, &p); if (r < 0) - return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Advertisement engine: %m"); + return log_oom(); - if (link_has_carrier(link)) { - r = sd_radv_start(link->radv); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to start IPv6 Router Advertisement engine: %m"); + r = safe_atou32(rvalue, &p->route_metric); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", + lvalue, rvalue); + return 0; } - log_link_debug(link, "IPv6 Router Advertisement engine is configured%s.", - link_has_carrier(link) ? " and started." : ""); - return 1; + TAKE_PTR(p); + + return 0; } -int link_request_radv(Link *link) { +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; + uint8_t prefixlen = 64; + union in_addr_union in6addr; int r; - assert(link); + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); - if (!link_radv_enabled(link)) + r = route_prefix_new_static(network, filename, section_line, &p); + if (r < 0) + return log_oom(); + + r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue); return 0; + } - if (link->radv) + 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; + } - r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m"); + p = NULL; - log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine."); 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) { +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) { - _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL; + Network *network = userdata; + _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL; + usec_t usec; int r; - assert(link); - - if (!link->radv) - return 0; - - r = sd_radv_prefix_new(&p); - if (r < 0) - return r; + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); - r = sd_radv_prefix_set_prefix(p, prefix, prefix_len); + r = route_prefix_new_static(network, filename, section_line, &p); if (r < 0) - return r; + return log_oom(); - r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred); - if (r < 0) - return r; + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Route lifetime is invalid, ignoring assignment: %s", rvalue); + return 0; + } - r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid); - if (r < 0) - return r; + /* 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) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to set route lifetime, ignoring assignment: %m"); + return 0; + } - r = sd_radv_add_prefix(link->radv, p, true); - if (r < 0 && r != -EEXIST) - return r; + p = NULL; return 0; }