#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;
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;
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;
}