diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2021-10-19 09:22:32 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-19 09:22:32 +0200 |
commit | 221e9cfe4bbec16d355e4bc483c0e365ef6abcd5 (patch) | |
tree | 8eb900b234e0d413c1c7284dd430f7377b4a343d /src/network/networkd-dhcp6.c | |
parent | 33331d116db2eaf1189ea56ee4b36540179ac3dd (diff) | |
parent | d205851dbe8217f98100dcffd98462f8b427e72a (diff) | |
download | systemd-221e9cfe4bbec16d355e4bc483c0e365ef6abcd5.tar.gz |
Merge pull request #21036 from yuwata/network-dhcp6-pd-manage-prefix-with-hashmap
network: dhcp6-pd: manage prefix with hashmap
Diffstat (limited to 'src/network/networkd-dhcp6.c')
-rw-r--r-- | src/network/networkd-dhcp6.c | 124 |
1 files changed, 63 insertions, 61 deletions
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 35cb0ea9a5..fdf4ba5e1e 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -56,64 +56,62 @@ static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) { 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; @@ -122,14 +120,14 @@ static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_pr 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; } @@ -141,7 +139,7 @@ static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_pr 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; @@ -175,6 +173,8 @@ int dhcp6_pd_remove(Link *link, bool only_marked) { 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; @@ -183,17 +183,20 @@ int dhcp6_pd_remove(Link *link, bool only_marked) { } 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) @@ -440,7 +443,7 @@ static int dhcp6_pd_assign_prefix( if (r < 0) return r; - return 0; + return link_add_dhcp6_pd_prefix(link, prefix); } static bool link_has_preferred_subnet_id(Link *link) { @@ -487,9 +490,9 @@ static int dhcp6_get_preferred_delegated_prefix( /* 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; @@ -506,7 +509,7 @@ static int dhcp6_get_preferred_delegated_prefix( 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; @@ -847,7 +850,6 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { 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, @@ -876,8 +878,8 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { 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"); @@ -885,13 +887,13 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { 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, @@ -900,7 +902,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { return r; r = dhcp6_pd_prefix_distribute(dhcp6_link, - &prefix.in6, + &pd_prefix, pd_prefix_len, lifetime_preferred, lifetime_valid, |