summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-12-02 08:16:23 +0900
committerGitHub <noreply@github.com>2021-12-02 08:16:23 +0900
commitbf1e65a4fdb4b13dce6afdbc3ce8d9bbb718322e (patch)
treea2b4c2e9cb509f917027acc44ffff31e4f3e9071 /src
parent9db6a416dd2f8a1e338a7275fc8b0583d8ed2450 (diff)
parent6016f1cfbb32568452cae070e6271b8cc3319c16 (diff)
downloadsystemd-bf1e65a4fdb4b13dce6afdbc3ce8d9bbb718322e.tar.gz
Merge pull request #21585 from yuwata/network-radv-uplink-interface-auto-with-dhcp6-pd
network: cleanups for uplink interface handling for RADV and DHCP6-PD
Diffstat (limited to 'src')
-rw-r--r--src/network/networkd-dhcp6.c102
-rw-r--r--src/network/networkd-dhcp6.h1
-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
-rw-r--r--src/network/networkd-radv.c10
7 files changed, 90 insertions, 57 deletions
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 8d48aa9f88..76f4e4109c 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -42,25 +42,28 @@ bool link_dhcp6_pd_is_enabled(Link *link) {
return link->network->dhcp6_pd;
}
-static int dhcp6_pd_resolve_uplink(Link *link, Link **ret) {
+static bool dhcp6_pd_is_uplink(Link *link, Link *target, bool accept_auto) {
+ assert(link);
+ assert(target);
+
+ if (!link_dhcp6_pd_is_enabled(link))
+ return false;
+
if (link->network->dhcp6_pd_uplink_name)
- return link_get_by_name(link->manager, link->network->dhcp6_pd_uplink_name, ret);
+ return streq_ptr(target->ifname, link->network->dhcp6_pd_uplink_name) ||
+ strv_contains(target->alternative_names, link->network->dhcp6_pd_uplink_name);
if (link->network->dhcp6_pd_uplink_index > 0)
- return link_get_by_index(link->manager, link->network->dhcp6_pd_uplink_index, ret);
+ return target->ifindex == link->network->dhcp6_pd_uplink_index;
- if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF) {
- *ret = link;
- return 0;
- }
+ if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF)
+ return link == target;
assert(link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_AUTO);
- return -ENOENT;
+ return accept_auto;
}
static DHCP6ClientStartMode link_get_dhcp6_client_start_mode(Link *link) {
- Link *uplink;
-
assert(link);
if (!link->network)
@@ -70,11 +73,12 @@ static DHCP6ClientStartMode link_get_dhcp6_client_start_mode(Link *link) {
if (link->network->dhcp6_client_start_mode >= 0)
return link->network->dhcp6_client_start_mode;
- if (dhcp6_pd_resolve_uplink(link, &uplink) < 0)
- return DHCP6_CLIENT_START_MODE_NO;
+ /* When this interface itself is an uplink interface, then start dhcp6 client in managed mode. */
+ if (dhcp6_pd_is_uplink(link, link, /* accept_auto = */ false))
+ return DHCP6_CLIENT_START_MODE_SOLICIT;
- /* When this interface itself is an uplink interface, then start dhcp6 client in managed mode */
- return uplink == link ? DHCP6_CLIENT_START_MODE_SOLICIT : DHCP6_CLIENT_START_MODE_NO;
+ /* Otherwise, start dhcp6 client when RA is received. */
+ return DHCP6_CLIENT_START_MODE_NO;
}
static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
@@ -527,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;
@@ -598,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;
@@ -610,12 +620,10 @@ static int dhcp6_pd_distribute_prefix(
assert(pd_prefix_len <= 64);
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
- Link *uplink;
-
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue;
- if (!link_dhcp6_pd_is_enabled(link))
+ if (!dhcp6_pd_is_uplink(link, dhcp6_link, /* accept_auto = */ true))
continue;
if (link->network->dhcp6_pd_announce && !link->radv)
@@ -624,18 +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_resolve_uplink(link, &uplink);
- if (r != -ENOENT) {
- if (r < 0) /* The uplink interface does not exist yet. */
- continue;
-
- if (uplink != dhcp6_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)
@@ -985,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;
}
@@ -1452,28 +1438,38 @@ static bool dhcp6_pd_uplink_is_ready(Link *link) {
return dhcp6_lease_has_pd_prefix(link->dhcp6_lease);
}
-static int dhcp6_pd_find_uplink(Link *link, Link **ret) {
- Link *l;
+int dhcp6_pd_find_uplink(Link *link, Link **ret) {
+ Link *uplink = NULL;
+ int r = 0;
assert(link);
assert(link->manager);
- assert(link->network);
+ assert(link_dhcp6_pd_is_enabled(link));
assert(ret);
- if (dhcp6_pd_resolve_uplink(link, &l) >= 0) {
- if (!dhcp6_pd_uplink_is_ready(l))
+ if (link->network->dhcp6_pd_uplink_name)
+ r = link_get_by_name(link->manager, link->network->dhcp6_pd_uplink_name, &uplink);
+ else if (link->network->dhcp6_pd_uplink_index > 0)
+ r = link_get_by_index(link->manager, link->network->dhcp6_pd_uplink_index, &uplink);
+ else if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF)
+ uplink = link;
+ if (r < 0)
+ return r;
+
+ if (uplink) {
+ if (!dhcp6_pd_uplink_is_ready(uplink))
return -EBUSY;
- *ret = l;
+ *ret = uplink;
return 0;
}
- HASHMAP_FOREACH(l, link->manager->links_by_index) {
- if (!dhcp6_pd_uplink_is_ready(l))
+ HASHMAP_FOREACH(uplink, link->manager->links_by_index) {
+ if (!dhcp6_pd_uplink_is_ready(uplink))
continue;
/* Assume that there exists at most one link which acquired delegated prefixes. */
- *ret = l;
+ *ret = uplink;
return 0;
}
diff --git a/src/network/networkd-dhcp6.h b/src/network/networkd-dhcp6.h
index 4a522aebcf..9c5aff6af7 100644
--- a/src/network/networkd-dhcp6.h
+++ b/src/network/networkd-dhcp6.h
@@ -18,6 +18,7 @@ typedef struct Request Request;
bool link_dhcp6_with_address_enabled(Link *link);
bool link_dhcp6_pd_is_enabled(Link *link);
+int dhcp6_pd_find_uplink(Link *link, Link **ret);
int dhcp6_pd_remove(Link *link, bool only_marked);
int dhcp6_update_mac(Link *link);
int dhcp6_start(Link *link);
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);
diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c
index c98528aee9..a137270cfa 100644
--- a/src/network/networkd-radv.c
+++ b/src/network/networkd-radv.c
@@ -410,6 +410,8 @@ set_domains:
}
static int radv_find_uplink(Link *link, Link **ret) {
+ int r;
+
assert(link);
if (link->network->router_uplink_name)
@@ -419,8 +421,12 @@ static int radv_find_uplink(Link *link, Link **ret) {
return link_get_by_index(link->manager, link->network->router_uplink_index, ret);
if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) {
- /* It is not necessary to propagate error in automatic selection. */
- if (manager_find_uplink(link->manager, AF_INET6, link, ret) < 0)
+ if (link_dhcp6_pd_is_enabled(link))
+ r = dhcp6_pd_find_uplink(link, ret); /* When DHCPv6PD is enabled, use its uplink. */
+ else
+ r = manager_find_uplink(link->manager, AF_INET6, link, ret);
+ if (r < 0)
+ /* It is not necessary to propagate error in automatic selection. */
*ret = NULL;
return 0;
}