]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: dhcp6-pd: exclude all explicitly specified subnet IDs when searching free IDs
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 1 Dec 2021 10:43:40 +0000 (19:43 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 1 Dec 2021 11:35:03 +0000 (20:35 +0900)
When the upstream link gained a lease, then several downstream links may
not appear yet. Previously, the explicitly specified subnet ID for a
downstream link which appears later may be already assigned to an
interface which does not request specific subnet ID.

To avoid such situation, this makes all specified IDs are excluded when
searching free IDs.

As a side effect, we can avoid the second call of
dhcp6_pd_distribute_prefix().

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

index 3c3794ab87d03dbb3db7736031b3142ae90f137e..76f4e4109c3e2be953920010e7b0c6332b74cd2e 100644 (file)
@@ -531,13 +531,20 @@ static int dhcp6_pd_get_preferred_prefix(
         }
 
         for (uint64_t n = 0; ; n++) {
+                /* If we do not have an allocation preference just iterate
+                 * through the address space and return the first free prefix. */
+
                 r = dhcp6_pd_calculate_prefix(pd_prefix, pd_prefix_len, n, &prefix);
                 if (r < 0)
                         return log_link_warning_errno(link, r,
                                                       "Couldn't find a suitable prefix. Ran out of address space.");
 
-                /* If we do not have an allocation preference just iterate
-                 * through the address space and return the first free prefix. */
+                /* Do not use explicitly requested subnet IDs. Note that the corresponding link may not
+                 * appear yet. So, we need to check the ID is not used in any .network files. */
+                if (set_contains(link->manager->dhcp6_pd_subnet_ids, &n))
+                        continue;
+
+                /* Check that the prefix is not assigned to another link. */
                 if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix, &assigned_link) < 0 ||
                     assigned_link == link) {
                         *ret = prefix;
@@ -602,8 +609,7 @@ static int dhcp6_pd_distribute_prefix(
                 const struct in6_addr *pd_prefix,
                 uint8_t pd_prefix_len,
                 usec_t lifetime_preferred_usec,
-                usec_t lifetime_valid_usec,
-                bool assign_preferred_subnet_id) {
+                usec_t lifetime_valid_usec) {
 
         Link *link;
         int r;
@@ -626,9 +632,6 @@ static int dhcp6_pd_distribute_prefix(
                 if (link == dhcp6_link && !link->network->dhcp6_pd_assign)
                         continue;
 
-                if (assign_preferred_subnet_id != link_has_preferred_subnet_id(link))
-                        continue;
-
                 r = dhcp6_pd_assign_prefix(link, pd_prefix, pd_prefix_len, lifetime_preferred_usec, lifetime_valid_usec);
                 if (r < 0) {
                         if (link == dhcp6_link)
@@ -978,17 +981,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
                                                &pd_prefix,
                                                pd_prefix_len,
                                                lifetime_preferred_usec,
-                                               lifetime_valid_usec,
-                                               true);
-                if (r < 0)
-                        return r;
-
-                r = dhcp6_pd_distribute_prefix(dhcp6_link,
-                                               &pd_prefix,
-                                               pd_prefix_len,
-                                               lifetime_preferred_usec,
-                                               lifetime_valid_usec,
-                                               false);
+                                               lifetime_valid_usec);
                 if (r < 0)
                         return r;
         }
index 2141e2062246528f58d70f5094a7e1460fce28db..a122e0880020b4096adb00e4af62eb1403a5fe8e 100644 (file)
@@ -502,6 +502,7 @@ Manager* manager_free(Manager *m) {
         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->dhcp6_pd_subnet_ids = set_free(m->dhcp6_pd_subnet_ids);
         m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
 
         m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
@@ -585,7 +586,7 @@ int manager_load_config(Manager *m) {
         if (r < 0)
                 return r;
 
-        return 0;
+        return manager_build_dhcp6_pd_subnet_ids(m);
 }
 
 bool manager_should_reload(Manager *m) {
index 42b77ee0f5c5c1a478410de1a8005ef9660aee1a..ae9d5adf1b5f64b6a18efaa2c61db6a802ba1340 100644 (file)
@@ -52,6 +52,7 @@ struct Manager {
         Hashmap *netdevs;
         OrderedHashmap *networks;
         OrderedSet *address_pools;
+        Set *dhcp6_pd_subnet_ids;
 
         usec_t network_dirs_ts_usec;
 
index c97998848cd1532b97347457b306939549b01c1a..443222f61062054d682aeedfbc51123a32008c46 100644 (file)
@@ -643,7 +643,7 @@ int network_reload(Manager *manager) {
         ordered_hashmap_free_with_destructor(manager->networks, network_unref);
         manager->networks = new_networks;
 
-        return 0;
+        return manager_build_dhcp6_pd_subnet_ids(manager);
 
 failure:
         ordered_hashmap_free_with_destructor(new_networks, network_unref);
@@ -651,6 +651,32 @@ failure:
         return r;
 }
 
+int manager_build_dhcp6_pd_subnet_ids(Manager *manager) {
+        Network *n;
+        int r;
+
+        assert(manager);
+
+        set_clear(manager->dhcp6_pd_subnet_ids);
+
+        ORDERED_HASHMAP_FOREACH(n, manager->networks) {
+                if (n->unmanaged)
+                        continue;
+
+                if (!n->dhcp6_pd)
+                        continue;
+
+                if (n->dhcp6_pd_subnet_id < 0)
+                        continue;
+
+                r = set_ensure_put(&manager->dhcp6_pd_subnet_ids, &uint64_hash_ops, &n->dhcp6_pd_subnet_id);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 static Network *network_free(Network *network) {
         if (!network)
                 return NULL;
index 942210470c20f829f9d913280fa1bbea953c1f03..2fdd4994c4c41023d2eaf301a6efc9cf7ec76d96 100644 (file)
@@ -365,6 +365,8 @@ int network_reload(Manager *manager);
 int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename);
 int network_verify(Network *network);
 
+int manager_build_dhcp6_pd_subnet_ids(Manager *manager);
+
 int network_get_by_name(Manager *manager, const char *name, Network **ret);
 void network_apply_anonymize_if_set(Network *network);