return sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len, &lifetime_preferred, &lifetime_valid) >= 0;
}
-static int dhcp6_pd_get_link_by_prefix(Manager *manager, const struct in6_addr *prefix, Link **ret) {
- union in_addr_union u;
- Link *link;
+static void link_remove_dhcp6_pd_prefix(Link *link, const struct in6_addr *prefix) {
+ void *key;
- assert(manager);
+ assert(link);
+ assert(link->manager);
assert(prefix);
- u.in6 = *prefix;
+ if (hashmap_get(link->manager->links_by_dhcp6_pd_prefix, prefix) != link)
+ return;
- HASHMAP_FOREACH(link, manager->links_by_index) {
- if (!link_dhcp6_pd_is_enabled(link))
- continue;
+ hashmap_remove2(link->manager->links_by_dhcp6_pd_prefix, prefix, &key);
+ free(key);
+}
- if (link->network->dhcp6_pd_assign) {
- Address *address;
+static int link_add_dhcp6_pd_prefix(Link *link, const struct in6_addr *prefix) {
+ _cleanup_free_ struct in6_addr *copy = NULL;
+ int r;
- SET_FOREACH(address, link->addresses) {
- if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
- continue;
- assert(address->family == AF_INET6);
+ assert(link);
+ assert(prefix);
- if (in_addr_prefix_covers(AF_INET6, &u, 64, &address->in_addr) > 0) {
- if (ret)
- *ret = link;
- return 0;
- }
- }
- } else {
- Route *route;
-
- SET_FOREACH(route, link->routes) {
- if (route->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
- continue;
- assert(route->family == AF_INET6);
-
- if (in6_addr_equal(&route->dst.in6, prefix)) {
- if (ret)
- *ret = link;
- return 0;
- }
- }
- }
- }
+ copy = newdup(struct in6_addr, prefix, 1);
+ if (!copy)
+ return -ENOMEM;
- return -ENOENT;
+ r = hashmap_ensure_put(&link->manager->links_by_dhcp6_pd_prefix, &in6_addr_hash_ops_free, copy, link);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ TAKE_PTR(copy);
+
+ return 0;
}
-static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_prefix, uint8_t pd_prefix_len, struct in6_addr *ret) {
- union in_addr_union u;
+static int link_get_by_dhcp6_pd_prefix(Manager *manager, const struct in6_addr *prefix, Link **ret) {
+ Link *link;
+ assert(manager);
+ assert(prefix);
+
+ link = hashmap_get(manager->links_by_dhcp6_pd_prefix, prefix);
+ if (!link)
+ return -ENODEV;
+
+ if (ret)
+ *ret = link;
+ return 0;
+}
+
+static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_prefix, uint8_t pd_prefix_len, struct in6_addr *ret) {
assert(link);
assert(pd_prefix);
if (!link_dhcp6_pd_is_enabled(link))
return -ENOENT;
- u.in6 = *pd_prefix;
-
if (link->network->dhcp6_pd_assign) {
Address *address;
continue;
assert(address->family == AF_INET6);
- if (in_addr_prefix_covers(AF_INET6, &u, pd_prefix_len, &address->in_addr) <= 0)
+ if (in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &address->in_addr.in6) <= 0)
continue;
if (ret) {
- union in_addr_union prefix = address->in_addr;
+ struct in6_addr prefix = address->in_addr.in6;
- in_addr_mask(AF_INET6, &prefix, 64);
- *ret = prefix.in6;
+ in6_addr_mask(&prefix, 64);
+ *ret = prefix;
}
return 0;
}
continue;
assert(route->family == AF_INET6);
- if (in_addr_prefix_covers(AF_INET6, &u, pd_prefix_len, &route->dst) > 0) {
+ if (in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &route->dst.in6) > 0) {
if (ret)
*ret = route->dst.in6;
return 0;
if (link->radv)
(void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
+ link_remove_dhcp6_pd_prefix(link, &route->dst.in6);
+
k = route_remove(route);
if (k < 0)
r = k;
}
SET_FOREACH(address, link->addresses) {
+ struct in6_addr prefix;
+
if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
continue;
if (only_marked && !address_is_marked(address))
continue;
- if (link->radv) {
- union in_addr_union prefix = address->in_addr;
+ prefix = address->in_addr.in6;
+ in6_addr_mask(&prefix, 64);
- in_addr_mask(AF_INET6, &prefix, 64);
- (void) sd_radv_remove_prefix(link->radv, &prefix.in6, 64);
- }
+ if (link->radv)
+ (void) sd_radv_remove_prefix(link->radv, &prefix, 64);
+
+ link_remove_dhcp6_pd_prefix(link, &prefix);
k = address_remove(address);
if (k < 0)
}
static int dhcp6_pd_check_ready(Link *link) {
- bool has_ready = false;
- Address *address;
int r;
assert(link);
+ assert(link->network);
if (link->dhcp6_pd_messages > 0) {
log_link_debug(link, "%s(): DHCPv6PD addresses and routes are not set.", __func__);
return 0;
}
- SET_FOREACH(address, link->addresses) {
- if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
- continue;
- if (address_is_ready(address)) {
- has_ready = true;
- break;
+ if (link->network->dhcp6_pd_assign) {
+ bool has_ready = false;
+ Address *address;
+
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
+ continue;
+ if (address_is_ready(address)) {
+ has_ready = true;
+ break;
+ }
}
- }
- if (!has_ready) {
- SET_FOREACH(address, link->addresses)
- if (address->source == NETWORK_CONFIG_SOURCE_DHCP6PD)
- address->callback = dhcp6_pd_address_ready_callback;
+ if (!has_ready) {
+ SET_FOREACH(address, link->addresses)
+ if (address->source == NETWORK_CONFIG_SOURCE_DHCP6PD)
+ address->callback = dhcp6_pd_address_ready_callback;
- log_link_debug(link, "%s(): no DHCPv6PD address is ready.", __func__);
- return 0;
+ log_link_debug(link, "%s(): no DHCPv6PD address is ready.", __func__);
+ return 0;
+ }
}
link->dhcp6_pd_configured = true;
if (r < 0)
return r;
- return 0;
+ return link_add_dhcp6_pd_prefix(link, prefix);
}
static bool link_has_preferred_subnet_id(Link *link) {
/* Verify that the prefix we did calculate fits in the pd prefix.
* This should not fail as we checked the prefix size beforehand */
- assert_se(in_addr_prefix_covers(AF_INET6, (const union in_addr_union*) pd_prefix, pd_prefix_len, &prefix) > 0);
+ assert_se(in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &prefix.in6) > 0);
- if (dhcp6_pd_get_link_by_prefix(link->manager, &prefix.in6, &assigned_link) >= 0 &&
+ if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix.in6, &assigned_link) >= 0 &&
assigned_link != link) {
_cleanup_free_ char *assigned_buf = NULL;
for (uint64_t n = 0; n < n_prefixes; n++) {
/* If we do not have an allocation preference just iterate
* through the address space and return the first free prefix. */
- if (dhcp6_pd_get_link_by_prefix(link->manager, &prefix.in6, &assigned_link) < 0 ||
+ if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix.in6, &assigned_link) < 0 ||
assigned_link == link) {
*ret = prefix.in6;
return 0;
if (assign_preferred_subnet_id != link_has_preferred_subnet_id(link))
continue;
- r = dhcp6_pd_get_assigned_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix);
- if (r < 0) {
- r = dhcp6_get_preferred_delegated_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix);
- if (r < 0)
- continue;
- }
+ if (dhcp6_pd_get_assigned_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix) < 0 &&
+ dhcp6_get_preferred_delegated_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix) < 0)
+ continue;
(void) in6_addr_prefix_to_string(&assigned_prefix, 64, &buf);
- if (link == dhcp6_link) {
- r = dhcp6_pd_request_address(link, &assigned_prefix, lifetime_preferred, lifetime_valid);
- if (r < 0)
- return log_link_warning_errno(link, r, "Failed to assign addresses in prefix %s: %m", strna(buf));
-
- log_link_debug(link, "Assigned addresses in prefix %s: %m", strna(buf));
- } else {
- r = dhcp6_pd_assign_prefix(link, &assigned_prefix, lifetime_preferred, lifetime_valid);
- if (r < 0) {
- log_link_error_errno(link, r, "Failed to assign/update prefix %s: %m", strna(buf));
- link_enter_failed(link);
- } else
- log_link_debug(link, "Assigned prefix %s", strna(buf));
+ r = dhcp6_pd_assign_prefix(link, &assigned_prefix, lifetime_preferred, lifetime_valid);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to assign/update prefix %s: %m", strna(buf));
+ if (link == dhcp6_link)
+ return r;
+
+ link_enter_failed(link);
+ continue;
}
+
+ log_link_debug(link, "Assigned prefix %s", strna(buf));
}
return 0;
for (sd_dhcp6_lease_reset_pd_prefix_iter(dhcp6_link->dhcp6_lease);;) {
uint32_t lifetime_preferred, lifetime_valid;
struct in6_addr pd_prefix;
- union in_addr_union prefix;
uint8_t pd_prefix_len;
r = sd_dhcp6_lease_get_pd(dhcp6_link->dhcp6_lease, &pd_prefix, &pd_prefix_len,
assert(pd_prefix_len <= 64);
- prefix.in6 = pd_prefix;
- r = in_addr_mask(AF_INET6, &prefix, pd_prefix_len);
+ /* Mask prefix for safety. */
+ r = in6_addr_mask(&pd_prefix, pd_prefix_len);
if (r < 0)
return log_link_error_errno(dhcp6_link, r, "Failed to mask DHCPv6 PD prefix: %m");
uint64_t n_prefixes = UINT64_C(1) << (64 - pd_prefix_len);
_cleanup_free_ char *buf = NULL;
- (void) in6_addr_prefix_to_string(&prefix.in6, pd_prefix_len, &buf);
+ (void) in6_addr_prefix_to_string(&pd_prefix, pd_prefix_len, &buf);
log_link_debug(dhcp6_link, "Assigning up to %" PRIu64 " prefixes from %s",
n_prefixes, strna(buf));
}
r = dhcp6_pd_prefix_distribute(dhcp6_link,
- &prefix.in6,
+ &pd_prefix,
pd_prefix_len,
lifetime_preferred,
lifetime_valid,
return r;
r = dhcp6_pd_prefix_distribute(dhcp6_link,
- &prefix.in6,
+ &pd_prefix,
pd_prefix_len,
lifetime_preferred,
lifetime_valid,