summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-12-01 19:43:40 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-12-01 20:35:03 +0900
commit1a4ca0e2f35d859f2d7f3bb8c94eefe2ad1c2ff4 (patch)
tree3bdbf81e7b85b7fb5d0dfe3d8604bc34a882abfb /src
parenta74229c58ed4e472875829589502119e4badc483 (diff)
downloadsystemd-1a4ca0e2f35d859f2d7f3bb8c94eefe2ad1c2ff4.tar.gz
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().
Diffstat (limited to 'src')
-rw-r--r--src/network/networkd-dhcp6.c29
-rw-r--r--src/network/networkd-manager.c3
-rw-r--r--src/network/networkd-manager.h1
-rw-r--r--src/network/networkd-network.c28
-rw-r--r--src/network/networkd-network.h2
5 files changed, 43 insertions, 20 deletions
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 3c3794ab87..76f4e4109c 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 2141e20622..a122e08800 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 42b77ee0f5..ae9d5adf1b 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 c97998848c..443222f610 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 942210470c..2fdd4994c4 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);