}
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;
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;
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)
&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;
}
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);
if (r < 0)
return r;
- return 0;
+ return manager_build_dhcp6_pd_subnet_ids(m);
}
bool manager_should_reload(Manager *m) {
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);
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;
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);