]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #21036 from yuwata/network-dhcp6-pd-manage-prefix-with-hashmap
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 19 Oct 2021 07:22:32 +0000 (09:22 +0200)
committerGitHub <noreply@github.com>
Tue, 19 Oct 2021 07:22:32 +0000 (09:22 +0200)
network: dhcp6-pd: manage prefix with hashmap

src/network/networkd-dhcp6.c
src/network/networkd-manager.c
src/network/networkd-manager.h

index 35cb0ea9a539de001ed029bcb54a18c0d44d7f5a..fdf4ba5e1e8a57cd6906fb5992c7bc5cf8299b90 100644 (file)
@@ -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,
index b4494d51827f1dc5af8045bad11c9b472f1aeda5..c5ccfb4b580da74a5fca5bca87e7d020d5db5d1a 100644 (file)
@@ -485,6 +485,7 @@ Manager* manager_free(Manager *m) {
         m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
         m->links_by_name = hashmap_free(m->links_by_name);
         m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
+        m->links_by_dhcp6_pd_prefix = hashmap_free(m->links_by_dhcp6_pd_prefix);
         m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
 
         m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
index 5f3f81ad9dcbc8ef325be0ac26d976fb8c14910e..42b77ee0f5c5c1a478410de1a8005ef9660aee1a 100644 (file)
@@ -48,6 +48,7 @@ struct Manager {
         Hashmap *links_by_index;
         Hashmap *links_by_name;
         Hashmap *links_by_hw_addr;
+        Hashmap *links_by_dhcp6_pd_prefix;
         Hashmap *netdevs;
         OrderedHashmap *networks;
         OrderedSet *address_pools;