From: Yu Watanabe Date: Wed, 1 Dec 2021 10:43:40 +0000 (+0900) Subject: network: dhcp6-pd: exclude all explicitly specified subnet IDs when searching free IDs X-Git-Tag: v250-rc1~95^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1a4ca0e2f35d859f2d7f3bb8c94eefe2ad1c2ff4;p=thirdparty%2Fsystemd.git network: dhcp6-pd: exclude all explicitly specified subnet IDs when searching free IDs 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(). --- diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 3c3794ab87d..76f4e4109c3 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -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; } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 2141e206224..a122e088002 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -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) { diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 42b77ee0f5c..ae9d5adf1b5 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -52,6 +52,7 @@ struct Manager { Hashmap *netdevs; OrderedHashmap *networks; OrderedSet *address_pools; + Set *dhcp6_pd_subnet_ids; usec_t network_dirs_ts_usec; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index c97998848cd..443222f6106 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 942210470c2..2fdd4994c4c 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -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);