diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-12-02 08:16:23 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-02 08:16:23 +0900 |
commit | bf1e65a4fdb4b13dce6afdbc3ce8d9bbb718322e (patch) | |
tree | a2b4c2e9cb509f917027acc44ffff31e4f3e9071 /src | |
parent | 9db6a416dd2f8a1e338a7275fc8b0583d8ed2450 (diff) | |
parent | 6016f1cfbb32568452cae070e6271b8cc3319c16 (diff) | |
download | systemd-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.c | 102 | ||||
-rw-r--r-- | src/network/networkd-dhcp6.h | 1 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 3 | ||||
-rw-r--r-- | src/network/networkd-manager.h | 1 | ||||
-rw-r--r-- | src/network/networkd-network.c | 28 | ||||
-rw-r--r-- | src/network/networkd-network.h | 2 | ||||
-rw-r--r-- | src/network/networkd-radv.c | 10 |
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; } |