summaryrefslogtreecommitdiffstats
path: root/src/network/networkd-dhcp6.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-09-06 09:09:38 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-09-24 14:46:32 +0200
commit3b6a3bdebfb555754fdc6ee507e3f6964de7b61c (patch)
treeb904859c12346774a65f0704d8f42f197045b23e /src/network/networkd-dhcp6.c
parentRevert "mkosi: turn off qemu headless mode" (diff)
downloadsystemd-3b6a3bdebfb555754fdc6ee507e3f6964de7b61c.tar.xz
systemd-3b6a3bdebfb555754fdc6ee507e3f6964de7b61c.zip
network: use NetworkConfigSource/State to manage addresses and routes
This also fixes #20146.
Diffstat (limited to 'src/network/networkd-dhcp6.c')
-rw-r--r--src/network/networkd-dhcp6.c824
1 files changed, 323 insertions, 501 deletions
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 0a7471f0e8..23a0f5fb53 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -20,6 +20,7 @@
#include "networkd-manager.h"
#include "networkd-queue.h"
#include "networkd-radv.h"
+#include "networkd-route.h"
#include "siphash24.h"
#include "string-table.h"
#include "string-util.h"
@@ -54,89 +55,103 @@ static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
return sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len, &lifetime_preferred, &lifetime_valid) >= 0;
}
-DHCP6DelegatedPrefix *dhcp6_pd_free(DHCP6DelegatedPrefix *p) {
- if (!p)
- return NULL;
+static int dhcp6_pd_get_link_by_prefix(Manager *manager, const struct in6_addr *prefix, Link **ret) {
+ union in_addr_union u;
+ Link *link;
- if (p->link && p->link->manager) {
- hashmap_remove(p->link->manager->dhcp6_prefixes, &p->prefix);
- set_remove(p->link->manager->dhcp6_pd_prefixes, p);
- }
+ assert(manager);
+ assert(prefix);
- link_unref(p->link);
- return mfree(p);
-}
+ u.in6 = *prefix;
-static void dhcp6_pd_hash_func(const DHCP6DelegatedPrefix *p, struct siphash *state) {
- assert(p);
+ HASHMAP_FOREACH(link, manager->links_by_index) {
+ if (!link_dhcp6_pd_is_enabled(link))
+ continue;
- siphash24_compress(&p->pd_prefix, sizeof(p->pd_prefix), state);
- siphash24_compress(&p->link, sizeof(p->link), state);
-}
+ if (link->network->dhcp6_pd_assign) {
+ Address *address;
-static int dhcp6_pd_compare_func(const DHCP6DelegatedPrefix *a, const DHCP6DelegatedPrefix *b) {
- int r;
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
+ continue;
+ assert(address->family == AF_INET6);
- r = memcmp(&a->pd_prefix, &b->pd_prefix, sizeof(a->pd_prefix));
- if (r != 0)
- return r;
+ if (in_addr_prefix_covers(AF_INET6, &u, 64, &address->in_addr) > 0) {
+ if (ret)
+ *ret = link;
+ return 0;
+ }
+ }
+ } else {
+ Route *route;
+
+ SET_FOREACH(route, link->routes) {
+ if (route->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
+ continue;
+ assert(route->family == AF_INET6);
+
+ if (in6_addr_equal(&route->dst.in6, prefix)) {
+ if (ret)
+ *ret = link;
+ return 0;
+ }
+ }
+ }
+ }
- return CMP(a->link, b->link);
+ return -ENOENT;
}
-DEFINE_HASH_OPS(dhcp6_pd_hash_ops, DHCP6DelegatedPrefix, dhcp6_pd_hash_func, dhcp6_pd_compare_func);
-
-static Link *dhcp6_pd_get_link_by_prefix(Link *link, const struct in6_addr *prefix) {
- DHCP6DelegatedPrefix *pd;
+static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_prefix, uint8_t pd_prefix_len, struct in6_addr *ret) {
+ union in_addr_union u;
assert(link);
- assert(link->manager);
- assert(prefix);
-
- pd = hashmap_get(link->manager->dhcp6_prefixes, prefix);
- if (!pd)
- return NULL;
-
- return pd->link;
-}
+ assert(pd_prefix);
-static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_prefix, struct in6_addr *ret_prefix) {
- DHCP6DelegatedPrefix *pd, in;
+ if (!link_dhcp6_pd_is_enabled(link))
+ return -ENOENT;
- assert(link);
- assert(link->manager);
- assert(pd_prefix);
- assert(ret_prefix);
+ u.in6 = *pd_prefix;
- in = (DHCP6DelegatedPrefix) {
- .pd_prefix = *pd_prefix,
- .link = link,
- };
+ if (link->network->dhcp6_pd_assign) {
+ Address *address;
- pd = set_get(link->manager->dhcp6_pd_prefixes, &in);
- if (!pd)
- return -ENOENT;
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
+ continue;
+ assert(address->family == AF_INET6);
- *ret_prefix = pd->prefix;
- return 0;
-}
+ if (in_addr_prefix_covers(AF_INET6, &u, pd_prefix_len, &address->in_addr) <= 0)
+ continue;
-static int dhcp6_pd_remove_old(Link *link, bool force);
+ if (ret) {
+ union in_addr_union prefix = address->in_addr;
-static int dhcp6_pd_address_callback(Address *address) {
- Address *a;
+ in_addr_mask(AF_INET6, &prefix, 64);
+ *ret = prefix.in6;
+ }
+ return 0;
+ }
+ } else {
+ Route *route;
- assert(address);
- assert(address->link);
+ SET_FOREACH(route, link->routes) {
+ if (route->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
+ continue;
+ assert(route->family == AF_INET6);
- /* Make this called only once */
- SET_FOREACH(a, address->link->dhcp6_pd_addresses)
- a->callback = NULL;
+ if (in_addr_prefix_covers(AF_INET6, &u, pd_prefix_len, &route->dst) > 0) {
+ if (ret)
+ *ret = route->dst.in6;
+ return 0;
+ }
+ }
+ }
- return dhcp6_pd_remove_old(address->link, true);
+ return -ENOENT;
}
-static int dhcp6_pd_remove_old(Link *link, bool force) {
+int dhcp6_pd_remove(Link *link, bool only_marked) {
Address *address;
Route *route;
int k, r = 0;
@@ -144,205 +159,160 @@ static int dhcp6_pd_remove_old(Link *link, bool force) {
assert(link);
assert(link->manager);
- if (!force && (link->dhcp6_pd_address_messages > 0 || link->dhcp6_pd_route_messages > 0))
- return 0;
-
- if (set_isempty(link->dhcp6_pd_addresses_old) && set_isempty(link->dhcp6_pd_routes_old))
+ if (!link_dhcp6_pd_is_enabled(link))
return 0;
- if (!force) {
- bool set_callback = !set_isempty(link->dhcp6_pd_addresses);
+ if (!only_marked)
+ link->dhcp6_pd_configured = false;
- SET_FOREACH(address, link->dhcp6_pd_addresses)
- if (address_is_ready(address)) {
- set_callback = false;
- break;
- }
-
- if (set_callback) {
- SET_FOREACH(address, link->dhcp6_pd_addresses)
- address->callback = dhcp6_pd_address_callback;
- return 0;
- }
- }
+ SET_FOREACH(route, link->routes) {
+ if (route->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
+ continue;
+ if (only_marked && !route_is_marked(route))
+ continue;
- log_link_debug(link, "Removing old DHCPv6 Prefix Delegation addresses and routes.");
+ if (link->radv)
+ (void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
- SET_FOREACH(route, link->dhcp6_pd_routes_old) {
- k = route_remove(route, NULL, link);
+ k = route_remove(route);
if (k < 0)
r = k;
- if (link->radv)
- (void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
- dhcp6_pd_free(hashmap_get(link->manager->dhcp6_prefixes, &route->dst.in6));
+ route_cancel_request(route);
}
- SET_FOREACH(address, link->dhcp6_pd_addresses_old) {
- k = address_remove(address, link);
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
+ continue;
+ if (only_marked && !address_is_marked(address))
+ continue;
+
+ if (link->radv) {
+ union in_addr_union prefix = address->in_addr;
+
+ in_addr_mask(AF_INET6, &prefix, 64);
+ (void) sd_radv_remove_prefix(link->radv, &prefix.in6, 64);
+ }
+
+ k = address_remove(address);
if (k < 0)
r = k;
+
+ address_cancel_request(address);
}
return r;
}
-int dhcp6_pd_remove(Link *link) {
- Address *address;
- Route *route;
- int k, r = 0;
-
- assert(link);
- assert(link->manager);
+static int dhcp6_pd_check_ready(Link *link);
- if (!link_dhcp6_pd_is_enabled(link))
- return 0;
+static int dhcp6_pd_address_ready_callback(Address *address) {
+ Address *a;
- link->dhcp6_pd_address_configured = false;
- link->dhcp6_pd_route_configured = false;
+ assert(address);
+ assert(address->link);
- k = dhcp6_pd_remove_old(link, true);
- if (k < 0)
- r = k;
+ SET_FOREACH(a, address->link->addresses)
+ if (a->source == NETWORK_CONFIG_SOURCE_DHCP6PD)
+ a->callback = NULL;
- if (set_isempty(link->dhcp6_pd_addresses) && set_isempty(link->dhcp6_pd_routes))
- return r;
+ return dhcp6_pd_check_ready(address->link);
+}
- log_link_debug(link, "Removing DHCPv6 Prefix Delegation addresses and routes.");
+static int dhcp6_pd_check_ready(Link *link) {
+ bool has_ready = false;
+ Address *address;
+ int r;
- SET_FOREACH(route, link->dhcp6_pd_routes) {
- k = route_remove(route, NULL, link);
- if (k < 0)
- r = k;
+ assert(link);
- if (link->radv)
- (void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
- dhcp6_pd_free(hashmap_get(link->manager->dhcp6_prefixes, &route->dst.in6));
+ if (link->dhcp6_pd_messages > 0) {
+ log_link_debug(link, "%s(): DHCPv6PD addresses and routes are not set.", __func__);
+ return 0;
}
- SET_FOREACH(address, link->dhcp6_pd_addresses) {
- k = address_remove(address, link);
- if (k < 0)
- r = k;
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP6PD)
+ continue;
+ if (address_is_ready(address)) {
+ has_ready = true;
+ break;
+ }
}
- return r;
-}
+ if (!has_ready) {
+ SET_FOREACH(address, link->addresses)
+ if (address->source == NETWORK_CONFIG_SOURCE_DHCP6PD)
+ address->callback = dhcp6_pd_address_ready_callback;
-static int dhcp6_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- int r;
+ log_link_debug(link, "%s(): no DHCPv6PD address is ready.", __func__);
+ return 0;
+ }
- assert(link);
- assert(link->dhcp6_pd_route_messages > 0);
+ link->dhcp6_pd_configured = true;
- link->dhcp6_pd_route_messages--;
+ log_link_debug(link, "DHCPv6 PD addresses and routes set.");
- r = route_configure_handler_internal(rtnl, m, link, "Failed to add DHCPv6 Prefix Delegation route");
- if (r <= 0)
+ r = dhcp6_pd_remove(link, /* only_marked = */ true);
+ if (r < 0)
return r;
- if (link->dhcp6_pd_route_messages == 0) {
- log_link_debug(link, "DHCPv6 prefix delegation routes set");
- if (link->dhcp6_pd_prefixes_assigned)
- link->dhcp6_pd_route_configured = true;
-
- r = dhcp6_pd_remove_old(link, false);
- if (r < 0) {
- link_enter_failed(link);
- return 1;
- }
-
- link_check_ready(link);
- }
-
+ link_check_ready(link);
return 1;
}
-static int dhcp6_pd_after_route_configure(Request *req, void *object) {
- Route *route = object;
- Link *link;
+static int dhcp6_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
- assert(req);
- assert(req->link);
- assert(req->type == REQUEST_TYPE_ROUTE);
- assert(route);
+ assert(link);
+ assert(link->dhcp6_pd_messages > 0);
- link = req->link;
+ link->dhcp6_pd_messages--;
- r = set_ensure_put(&link->dhcp6_pd_routes, &route_hash_ops, route);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store DHCPv6 prefix route: %m");
+ r = route_configure_handler_internal(rtnl, m, link, "Failed to add DHCPv6 Prefix Delegation route");
+ if (r <= 0)
+ return r;
- set_remove(link->dhcp6_pd_routes_old, route);
+ r = dhcp6_pd_check_ready(link);
+ if (r < 0)
+ link_enter_failed(link);
- return 0;
+ return 1;
}
-static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix, const struct in6_addr *pd_prefix) {
- _cleanup_(dhcp6_pd_freep) DHCP6DelegatedPrefix *pd = NULL;
+static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix) {
_cleanup_(route_freep) Route *route = NULL;
- Link *assigned_link;
- Request *req;
+ Route *existing;
int r;
assert(link);
- assert(link->manager);
+ assert(link->network);
assert(prefix);
- assert(pd_prefix);
+
+ if (link->network->dhcp6_pd_assign)
+ return 0;
r = route_new(&route);
if (r < 0)
return r;
+ route->source = NETWORK_CONFIG_SOURCE_DHCP6PD;
route->family = AF_INET6;
route->dst.in6 = *prefix;
route->dst_prefixlen = 64;
route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp6_pd_route_metric;
- r = link_has_route(link, route);
- if (r < 0)
- return r;
- if (r == 0)
- link->dhcp6_pd_route_configured = false;
+ if (route_get(NULL, link, route, &existing) < 0)
+ link->dhcp6_pd_configured = false;
+ else
+ route_unmark(existing);
- r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp6_pd_route_messages,
- dhcp6_pd_route_handler, &req);
+ r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp6_pd_messages,
+ dhcp6_pd_route_handler, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv6 prefix route: %m");
- if (r == 0)
- return 0;
-
- req->after_configure = dhcp6_pd_after_route_configure;
-
- assigned_link = dhcp6_pd_get_link_by_prefix(link, prefix);
- if (assigned_link) {
- assert(assigned_link == link);
- return 0;
- }
-
- pd = new(DHCP6DelegatedPrefix, 1);
- if (!pd)
- return log_oom();
-
- *pd = (DHCP6DelegatedPrefix) {
- .prefix = *prefix,
- .pd_prefix = *pd_prefix,
- .link = link_ref(link),
- };
-
- r = hashmap_ensure_put(&link->manager->dhcp6_prefixes, &in6_addr_hash_ops, &pd->prefix, pd);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store DHCPv6 prefix route at manager: %m");
- r = set_ensure_put(&link->manager->dhcp6_pd_prefixes, &dhcp6_pd_hash_ops, pd);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store DHCPv6 prefix route at manager: %m");
-
- TAKE_PTR(pd);
return 0;
}
@@ -350,25 +320,17 @@ static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin
int r;
assert(link);
- assert(link->dhcp6_pd_address_messages > 0);
+ assert(link->dhcp6_pd_messages > 0);
- link->dhcp6_pd_address_messages--;
+ link->dhcp6_pd_messages--;
r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv6 delegated prefix address");
if (r <= 0)
return r;
- if (link->dhcp6_pd_address_messages == 0) {
- log_link_debug(link, "DHCPv6 delegated prefix addresses set");
- if (link->dhcp6_pd_prefixes_assigned)
- link->dhcp6_pd_address_configured = true;
-
- r = dhcp6_pd_remove_old(link, false);
- if (r < 0) {
- link_enter_failed(link);
- return 1;
- }
- }
+ r = dhcp6_pd_check_ready(link);
+ if (r < 0)
+ link_enter_failed(link);
return 1;
}
@@ -393,27 +355,6 @@ static void log_dhcp6_pd_address(Link *link, const Address *address) {
FORMAT_LIFETIME(address->cinfo.ifa_prefered));
}
-static int dhcp6_pd_after_address_configure(Request *req, void *object) {
- Address *address = object;
- Link *link;
- int r;
-
- assert(req);
- assert(req->link);
- assert(req->type == REQUEST_TYPE_ADDRESS);
- assert(address);
-
- link = req->link;
-
- r = set_ensure_put(&link->dhcp6_pd_addresses, &address_hash_ops, address);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store DHCPv6 delegated prefix address: %m");
-
- set_remove(link->dhcp6_pd_addresses_old, address);
-
- return 0;
-}
-
static int dhcp6_pd_request_address(
Link *link,
const struct in6_addr *prefix,
@@ -421,7 +362,7 @@ static int dhcp6_pd_request_address(
uint32_t lifetime_valid) {
_cleanup_(address_freep) Address *address = NULL;
- Request *req;
+ Address *existing;
int r;
assert(link);
@@ -445,6 +386,7 @@ static int dhcp6_pd_request_address(
return log_link_warning_errno(link, r, "Failed to generate EUI64 address for acquired DHCPv6 delegated prefix: %m");
}
+ address->source = NETWORK_CONFIG_SOURCE_DHCP6PD;
address->prefixlen = 64;
address->family = AF_INET6;
address->cinfo.ifa_prefered = lifetime_preferred;
@@ -454,17 +396,15 @@ static int dhcp6_pd_request_address(
log_dhcp6_pd_address(link, address);
- if (address_get(link, address, NULL) < 0)
- link->dhcp6_pd_address_configured = false;
+ if (address_get(link, address, &existing) < 0)
+ link->dhcp6_pd_configured = false;
+ else
+ address_unmark(existing);
- r = link_request_address(link, TAKE_PTR(address), true, &link->dhcp6_pd_address_messages,
- dhcp6_pd_address_handler, &req);
+ r = link_request_address(link, TAKE_PTR(address), true, &link->dhcp6_pd_messages,
+ dhcp6_pd_address_handler, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv6 delegated prefix address: %m");
- if (r == 0)
- return 0;
-
- req->after_configure = dhcp6_pd_after_address_configure;
return 0;
}
@@ -472,7 +412,6 @@ static int dhcp6_pd_request_address(
static int dhcp6_pd_assign_prefix(
Link *link,
const struct in6_addr *prefix,
- const struct in6_addr *pd_prefix,
uint32_t lifetime_preferred,
uint32_t lifetime_valid) {
@@ -488,7 +427,7 @@ static int dhcp6_pd_assign_prefix(
return r;
}
- r = dhcp6_pd_request_route(link, prefix, pd_prefix);
+ r = dhcp6_pd_request_route(link, prefix);
if (r < 0)
return r;
@@ -508,7 +447,7 @@ static bool link_has_preferred_subnet_id(Link *link) {
static int dhcp6_get_preferred_delegated_prefix(
Link *link,
- const struct in6_addr *masked_pd_prefix,
+ const struct in6_addr *pd_prefix,
uint8_t pd_prefix_len,
struct in6_addr *ret) {
@@ -520,11 +459,11 @@ static int dhcp6_get_preferred_delegated_prefix(
assert(link);
assert(link->manager);
- assert(masked_pd_prefix);
+ assert(pd_prefix);
assert(pd_prefix_len <= 64);
n_prefixes = UINT64_C(1) << (64 - pd_prefix_len);
- prefix.in6 = *masked_pd_prefix;
+ prefix.in6 = *pd_prefix;
if (link_has_preferred_subnet_id(link)) {
uint64_t subnet_id = link->network->dhcp6_pd_subnet_id;
@@ -543,10 +482,10 @@ static int dhcp6_get_preferred_delegated_prefix(
/* Verify that the prefix we did calculate fits in the pd prefix.
* This should not fail as we checked the prefix size beforehand */
- assert_se(in_addr_prefix_covers(AF_INET6, (const union in_addr_union*) masked_pd_prefix, pd_prefix_len, &prefix) > 0);
+ assert_se(in_addr_prefix_covers(AF_INET6, (const union in_addr_union*) pd_prefix, pd_prefix_len, &prefix) > 0);
- assigned_link = dhcp6_pd_get_link_by_prefix(link, &prefix.in6);
- if (assigned_link && assigned_link != link) {
+ if (dhcp6_pd_get_link_by_prefix(link->manager, &prefix.in6, &assigned_link) >= 0 &&
+ assigned_link != link) {
_cleanup_free_ char *assigned_buf = NULL;
(void) in6_addr_to_string(&prefix.in6, &assigned_buf);
@@ -562,8 +501,8 @@ static int dhcp6_get_preferred_delegated_prefix(
for (uint64_t n = 0; n < n_prefixes; n++) {
/* If we do not have an allocation preference just iterate
* through the address space and return the first free prefix. */
- assigned_link = dhcp6_pd_get_link_by_prefix(link, &prefix.in6);
- if (!assigned_link || assigned_link == link) {
+ if (dhcp6_pd_get_link_by_prefix(link->manager, &prefix.in6, &assigned_link) < 0 ||
+ assigned_link == link) {
*ret = prefix.in6;
return 0;
}
@@ -577,7 +516,7 @@ static int dhcp6_get_preferred_delegated_prefix(
}
static void dhcp6_pd_prefix_distribute(Link *dhcp6_link,
- const struct in6_addr *masked_pd_prefix,
+ const struct in6_addr *pd_prefix,
uint8_t pd_prefix_len,
uint32_t lifetime_preferred,
uint32_t lifetime_valid,
@@ -588,7 +527,7 @@ static void dhcp6_pd_prefix_distribute(Link *dhcp6_link,
assert(dhcp6_link);
assert(dhcp6_link->manager);
- assert(masked_pd_prefix);
+ assert(pd_prefix);
assert(pd_prefix_len <= 64);
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
@@ -607,18 +546,15 @@ static void dhcp6_pd_prefix_distribute(Link *dhcp6_link,
if (assign_preferred_subnet_id != link_has_preferred_subnet_id(link))
continue;
- r = dhcp6_pd_get_assigned_prefix(link, masked_pd_prefix, &assigned_prefix);
+ r = dhcp6_pd_get_assigned_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix);
if (r < 0) {
- r = dhcp6_get_preferred_delegated_prefix(link, masked_pd_prefix, pd_prefix_len, &assigned_prefix);
- if (r < 0) {
- link->dhcp6_pd_prefixes_assigned = false;
+ r = dhcp6_get_preferred_delegated_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix);
+ if (r < 0)
continue;
- }
}
(void) in6_addr_to_string(&assigned_prefix, &assigned_buf);
- r = dhcp6_pd_assign_prefix(link, &assigned_prefix, masked_pd_prefix,
- lifetime_preferred, lifetime_valid);
+ r = dhcp6_pd_assign_prefix(link, &assigned_prefix, lifetime_preferred, lifetime_valid);
if (r < 0) {
log_link_error_errno(link, r, "Unable to assign/update prefix %s/64: %m",
strna(assigned_buf));
@@ -629,29 +565,14 @@ static void dhcp6_pd_prefix_distribute(Link *dhcp6_link,
}
static int dhcp6_pd_prepare(Link *link) {
- Address *address;
- Route *route;
- int r;
-
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
if (!link_dhcp6_pd_is_enabled(link))
return 0;
- link->dhcp6_pd_prefixes_assigned = true;
-
- while ((address = set_steal_first(link->dhcp6_pd_addresses))) {
- r = set_ensure_put(&link->dhcp6_pd_addresses_old, &address_hash_ops, address);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store old DHCPv6 Prefix Delegation address: %m");
- }
-
- while ((route = set_steal_first(link->dhcp6_pd_routes))) {
- r = set_ensure_put(&link->dhcp6_pd_routes_old, &route_hash_ops, route);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store old DHCPv6 Prefix Delegation route: %m");
- }
+ link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP6PD, NULL);
+ link_mark_routes(link, NETWORK_CONFIG_SOURCE_DHCP6PD, NULL);
return 0;
}
@@ -665,23 +586,15 @@ static int dhcp6_pd_finalize(Link *link) {
if (!link_dhcp6_pd_is_enabled(link))
return 0;
- if (link->dhcp6_pd_address_messages == 0) {
- if (link->dhcp6_pd_prefixes_assigned)
- link->dhcp6_pd_address_configured = true;
- } else
- log_link_debug(link, "Setting DHCPv6 PD addresses");
-
- if (link->dhcp6_pd_route_messages == 0) {
- if (link->dhcp6_pd_prefixes_assigned)
- link->dhcp6_pd_route_configured = true;
- } else
- log_link_debug(link, "Setting DHCPv6 PD routes");
+ if (link->dhcp6_pd_messages == 0) {
+ link->dhcp6_pd_configured = false;
- r = dhcp6_pd_remove_old(link, false);
- if (r < 0)
- return r;
+ r = dhcp6_pd_remove(link, /* only_marked = */ true);
+ if (r < 0)
+ return r;
+ }
- if (!link->dhcp6_pd_address_configured || !link->dhcp6_pd_route_configured)
+ if (!link->dhcp6_pd_configured)
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
@@ -699,7 +612,7 @@ static void dhcp6_pd_prefix_lost(Link *dhcp6_link) {
if (link == dhcp6_link)
continue;
- r = dhcp6_pd_remove(link);
+ r = dhcp6_pd_remove(link, /* only_marked = */ false);
if (r < 0)
link_enter_failed(link);
}
@@ -707,154 +620,124 @@ static void dhcp6_pd_prefix_lost(Link *dhcp6_link) {
set_clear(dhcp6_link->dhcp6_pd_prefixes);
}
-static int dhcp6_remove_old(Link *link, bool force);
-
-static int dhcp6_address_callback(Address *address) {
- Address *a;
-
- assert(address);
- assert(address->link);
-
- /* Make this called only once */
- SET_FOREACH(a, address->link->dhcp6_addresses)
- a->callback = NULL;
-
- return dhcp6_remove_old(address->link, true);
-}
-
-static int dhcp6_remove_old(Link *link, bool force) {
+static int dhcp6_remove(Link *link, bool only_marked) {
Address *address;
Route *route;
int k, r = 0;
assert(link);
- if (!force && (link->dhcp6_address_messages > 0 || link->dhcp6_route_messages > 0))
- return 0;
+ if (!only_marked)
+ link->dhcp6_configured = false;
- if (set_isempty(link->dhcp6_addresses_old) && set_isempty(link->dhcp6_routes_old))
- return 0;
-
- if (!force) {
- bool set_callback = !set_isempty(link->dhcp6_addresses);
+ SET_FOREACH(route, link->routes) {
+ if (route->source != NETWORK_CONFIG_SOURCE_DHCP6)
+ continue;
+ if (only_marked && !route_is_marked(route))
+ continue;
- SET_FOREACH(address, link->dhcp6_addresses)
- if (address_is_ready(address)) {
- set_callback = false;
- break;
- }
+ k = route_remove(route);
+ if (k < 0)
+ r = k;
- if (set_callback) {
- SET_FOREACH(address, link->dhcp6_addresses)
- address->callback = dhcp6_address_callback;
- return 0;
- }
+ route_cancel_request(route);
}
- log_link_debug(link, "Removing old DHCPv6 addresses and routes.");
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP6)
+ continue;
+ if (only_marked && !address_is_marked(address))
+ continue;
- SET_FOREACH(route, link->dhcp6_routes_old) {
- k = route_remove(route, NULL, link);
+ k = address_remove(address);
if (k < 0)
r = k;
- }
- SET_FOREACH(address, link->dhcp6_addresses_old) {
- k = address_remove(address, link);
- if (k < 0)
- r = k;
+ address_cancel_request(address);
}
return r;
}
-static int dhcp6_remove(Link *link) {
- Address *address;
- Route *route;
- int k, r = 0;
+static int dhcp6_check_ready(Link *link);
- assert(link);
+static int dhcp6_address_ready_callback(Address *address) {
+ Address *a;
- link->dhcp6_address_configured = false;
- link->dhcp6_route_configured = false;
+ assert(address);
+ assert(address->link);
- k = dhcp6_remove_old(link, true);
- if (k < 0)
- r = k;
+ SET_FOREACH(a, address->link->addresses)
+ if (a->source == NETWORK_CONFIG_SOURCE_DHCP6)
+ a->callback = NULL;
- if (set_isempty(link->dhcp6_addresses) && set_isempty(link->dhcp6_routes))
- return r;
+ return dhcp6_check_ready(address->link);
+}
- log_link_debug(link, "Removing DHCPv6 addresses and routes.");
+static int dhcp6_check_ready(Link *link) {
+ bool has_ready = false;
+ Address *address;
+ int r;
- SET_FOREACH(route, link->dhcp6_routes) {
- k = route_remove(route, NULL, link);
- if (k < 0)
- r = k;
+ assert(link);
+
+ if (link->dhcp6_messages > 0) {
+ log_link_debug(link, "%s(): DHCPv6 addresses and routes are not set.", __func__);
+ return 0;
}
- SET_FOREACH(address, link->dhcp6_addresses) {
- k = address_remove(address, link);
- if (k < 0)
- r = k;
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP6)
+ continue;
+ if (address_is_ready(address)) {
+ has_ready = true;
+ break;
+ }
}
- return r;
+ if (!has_ready) {
+ SET_FOREACH(address, link->addresses)
+ if (address->source == NETWORK_CONFIG_SOURCE_DHCP6)
+ address->callback = dhcp6_address_ready_callback;
+
+ log_link_debug(link, "%s(): no DHCPv6 address is ready.", __func__);
+ return 0;
+ }
+
+ link->dhcp6_configured = true;
+ log_link_debug(link, "DHCPv6 addresses and routes set.");
+
+ r = dhcp6_remove(link, /* only_marked = */ true);
+ if (r < 0)
+ return r;
+
+ link_check_ready(link);
+ return 0;
}
static int dhcp6_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
- assert(link->dhcp6_route_messages > 0);
+ assert(link->dhcp6_messages > 0);
- link->dhcp6_route_messages--;
+ link->dhcp6_messages--;
r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCPv6 delegated subnet");
if (r <= 0)
return r;
- if (link->dhcp6_route_messages == 0) {
- log_link_debug(link, "Unreachable routes for DHCPv6 delegated subnets set");
- link->dhcp6_route_configured = true;
-
- r = dhcp6_remove_old(link, false);
- if (r < 0) {
- link_enter_failed(link);
- return 1;
- }
-
- link_check_ready(link);
- }
-
- return 1;
-}
-
-static int dhcp6_after_route_configure(Request *req, void *object) {
- Route *route = object;
- Link *link;
- int r;
-
- assert(req);
- assert(req->link);
- assert(req->type == REQUEST_TYPE_ROUTE);
- assert(route);
-
- link = req->link;
-
- r = set_ensure_put(&link->dhcp6_routes, &route_hash_ops, route);
+ r = dhcp6_check_ready(link);
if (r < 0)
- return log_link_error_errno(link, r, "Failed to store unreachable route for DHCPv6 delegated subnet: %m");
-
- set_remove(link->dhcp6_routes_old, route);
+ link_enter_failed(link);
- return 0;
+ return 1;
}
static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *addr, uint8_t prefixlen) {
_cleanup_(route_freep) Route *route = NULL;
_cleanup_free_ char *buf = NULL;
- Request *req;
+ Route *existing;
int r;
assert(link);
@@ -872,6 +755,7 @@ static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *ad
if (r < 0)
return log_oom();
+ route->source = NETWORK_CONFIG_SOURCE_DHCP6;
route->family = AF_INET6;
route->dst.in6 = *addr;
route->dst_prefixlen = prefixlen;
@@ -879,28 +763,23 @@ static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *ad
route->type = RTN_UNREACHABLE;
route->protocol = RTPROT_DHCP;
- r = link_has_route(link, route);
- if (r < 0)
- return r;
- if (r == 0)
- link->dhcp6_route_configured = false;
+ if (route_get(link->manager, NULL, route, &existing) < 0)
+ link->dhcp6_configured = false;
+ else
+ route_unmark(existing);
- r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp6_route_messages,
- dhcp6_route_handler, &req);
+ r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp6_messages,
+ dhcp6_route_handler, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request unreachable route for DHCPv6 delegated subnet %s: %m",
strna(buf));
- if (r == 0)
- return 0;
-
- req->after_configure = dhcp6_after_route_configure;
return 0;
}
static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_t prefixlen) {
- _cleanup_free_ struct in_addr_prefix *p = NULL;
_cleanup_free_ char *buf = NULL;
+ struct in_addr_prefix *p;
int r;
assert(link);
@@ -927,11 +806,9 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
prefixlen < 48 ? " with prefix length < 48, looks unusual.": "");
/* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */
- r = set_ensure_put(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p);
+ r = set_ensure_consume(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 PD prefix %s: %m", strna(buf));
- if (r > 0)
- TAKE_PTR(p);
return prefixlen <= 64;
}
@@ -1029,102 +906,61 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
int r;
assert(link);
- assert(link->dhcp6_address_messages > 0);
+ assert(link->dhcp6_messages > 0);
- link->dhcp6_address_messages--;
+ link->dhcp6_messages--;
r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv6 address");
if (r <= 0)
return r;
- if (link->dhcp6_address_messages == 0) {
- log_link_debug(link, "DHCPv6 addresses set");
- link->dhcp6_address_configured = true;
-
- r = dhcp6_remove_old(link, false);
- if (r < 0) {
- link_enter_failed(link);
- return 1;
- }
- }
+ r = dhcp6_check_ready(link);
+ if (r < 0)
+ link_enter_failed(link);
return 1;
}
-static void log_dhcp6_address(Link *link, const Address *address, char **ret) {
+static void log_dhcp6_address(Link *link, const Address *address) {
_cleanup_free_ char *buffer = NULL;
bool by_ndisc = false;
Address *existing;
- NDiscAddress *na;
- int log_level, r;
+ int log_level;
assert(link);
assert(address);
assert(address->family == AF_INET6);
- (void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buffer);
+ (void) in6_addr_to_string(&address->in_addr.in6, &buffer);
- r = address_get(link, address, &existing);
- if (r < 0) {
+ if (address_get(link, address, &existing) < 0) {
/* New address. */
log_level = LOG_INFO;
goto simple_log;
} else
log_level = LOG_DEBUG;
- if (set_contains(link->dhcp6_addresses, address))
- /* Already warned. */
- goto simple_log;
-
if (address->prefixlen == existing->prefixlen)
/* Currently, only conflict in prefix length is reported. */
goto simple_log;
- SET_FOREACH(na, link->ndisc_addresses)
- if (address_compare_func(na->address, existing)) {
- by_ndisc = true;
- break;
- }
+ if (existing->source == NETWORK_CONFIG_SOURCE_NDISC)
+ by_ndisc = true;
- log_link_warning(link, "DHCPv6 address %s (valid %s, preferred %s) conflicts the existing address %s %s.",
- strna(buffer),
+ log_link_warning(link, "DHCPv6 address %s/%u (valid %s, preferred %s) conflicts the address %s/%u%s.",
+ strna(buffer), address->prefixlen,
FORMAT_LIFETIME(address->cinfo.ifa_valid),
FORMAT_LIFETIME(address->cinfo.ifa_prefered),
- strna(buffer),
- by_ndisc ? "assigned by NDISC. Please try to use or update IPv6Token= setting "
+ strna(buffer), existing->prefixlen,
+ by_ndisc ? " assigned by NDisc. Please try to use or update IPv6Token= setting "
"to change the address generated by NDISC, or disable UseAutonomousPrefix=" : "");
- goto finalize;
+ return;
simple_log:
- log_link_full(link, log_level, "DHCPv6 address %s (valid %s, preferred %s)",
- strna(buffer),
+ log_link_full(link, log_level, "DHCPv6 address %s/%u (valid %s, preferred %s)",
+ strna(buffer), address->prefixlen,
FORMAT_LIFETIME(address->cinfo.ifa_valid),
FORMAT_LIFETIME(address->cinfo.ifa_prefered));
-
-finalize:
- if (ret)
- *ret = TAKE_PTR(buffer);
-}
-
-static int dhcp6_after_address_configure(Request *req, void *object) {
- Address *address = object;
- Link *link;
- int r;
-
- assert(req);
- assert(req->link);
- assert(req->type == REQUEST_TYPE_ADDRESS);
- assert(address);
-
- link = req->link;
-
- r = set_ensure_put(&link->dhcp6_addresses, &address_hash_ops, address);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store DHCPv6 address: %m");
-
- set_remove(link->dhcp6_addresses_old, address);
-
- return 0;
}
static int dhcp6_request_address(
@@ -1134,14 +970,14 @@ static int dhcp6_request_address(
uint32_t lifetime_valid) {
_cleanup_(address_freep) Address *addr = NULL;
- _cleanup_free_ char *buffer = NULL;
- Request *req;
+ Address *existing;
int r;
r = address_new(&addr);
if (r < 0)
return log_oom();
+ addr->source = NETWORK_CONFIG_SOURCE_DHCP6;
addr->family = AF_INET6;
addr->in_addr.in6 = *ip6_addr;
addr->flags = IFA_F_NOPREFIXROUTE;
@@ -1149,19 +985,21 @@ static int dhcp6_request_address(
addr->cinfo.ifa_prefered = lifetime_preferred;
addr->cinfo.ifa_valid = lifetime_valid;
- log_dhcp6_address(link, addr, &buffer);
+ log_dhcp6_address(link, addr);
- if (address_get(link, addr, NULL) < 0)
- link->dhcp6_address_configured = false;
+ if (address_get(link, addr, &existing) < 0)
+ link->dhcp6_configured = false;
+ else
+ address_unmark(existing);
- r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp6_address_messages,
- dhcp6_address_handler, &req);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to request DHCPv6 address %s: %m", strna(buffer));
- if (r == 0)
- return 0;
+ r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp6_messages,
+ dhcp6_address_handler, NULL);
+ if (r < 0) {
+ _cleanup_free_ char *buffer = NULL;
- req->after_configure = dhcp6_after_address_configure;
+ (void) in6_addr_to_string(ip6_addr, &buffer);
+ return log_link_error_errno(link, r, "Failed to request DHCPv6 address %s/128: %m", strna(buffer));
+ }
return 0;
}
@@ -1215,21 +1053,10 @@ static int dhcp6_address_acquired(Link *link) {
static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) {
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease_old = NULL;
sd_dhcp6_lease *lease;
- Address *a;
- Route *rt;
int r;
- while ((a = set_steal_first(link->dhcp6_addresses))) {
- r = set_ensure_put(&link->dhcp6_addresses_old, &address_hash_ops, a);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store old DHCPv6 address: %m");
- }
-
- while ((rt = set_steal_first(link->dhcp6_routes))) {
- r = set_ensure_put(&link->dhcp6_routes_old, &route_hash_ops, rt);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store old DHCPv6 route: %m");
- }
+ link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP6, NULL);
+ link_mark_routes(link, NETWORK_CONFIG_SOURCE_DHCP6, NULL);
r = sd_dhcp6_client_get_lease(client, &lease);
if (r < 0)
@@ -1250,21 +1077,16 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) {
/* When we had PD prefixes but not now, we need to remove them. */
dhcp6_pd_prefix_lost(link);
- if (link->dhcp6_address_messages == 0)
- link->dhcp6_address_configured = true;
- else
- log_link_debug(link, "Setting DHCPv6 addresses");
-
- if (link->dhcp6_route_messages == 0)
- link->dhcp6_route_configured = true;
- else
- log_link_debug(link, "Setting unreachable routes for DHCPv6 delegated subnets");
+ if (link->dhcp6_messages == 0) {
+ link->dhcp6_configured = true;
- r = dhcp6_remove_old(link, false);
- if (r < 0)
- return r;
+ r = dhcp6_remove(link, /* only_marked = */ true);
+ if (r < 0)
+ return r;
+ } else
+ log_link_debug(link, "Setting DHCPv6 addresses and routes");
- if (!link->dhcp6_address_configured || !link->dhcp6_route_configured)
+ if (!link->dhcp6_configured)
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
@@ -1288,7 +1110,7 @@ static int dhcp6_lease_lost(Link *link) {
link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);
- r = dhcp6_remove(link);
+ r = dhcp6_remove(link, /* only_marked = */ false);
if (r < 0)
return r;