networkd-dhcp6: Request prefix delegation for a new link

Request prefix delegation for a new downstream link that is enabled
after any number of upstream DHCPv6 links. Submit the request after
the link has been configured with a link-local address.

If the upstream DHCPv6 client has already been configured to request
prefixes, attempt to re-assign any possible prefixes between the
already existing links and the new one. If no prefixes are yet
acquired, nothing will happen right away and any prefixes will be
distributed after a reply from the DHCPv6 server.

If none of the already existing downstream links have requested
DHCPv6 prefixes to be assigned, enable prefix delegation for each
client and restart them one by one if they are already running. This
causes the DHCPv6 clients to re-acquire addresses and prefixes and
to re-distribute them to all links when receiving an updated
response from their respective DHCPv6 servers. If the DHCPv6 client
in question was not already running, it is set to request prefixes
but not restarted.

When an error occurs while setting or restarting the DHCPv6 client,
log the incident and move over to the next link.

Fixes #9758.
This commit is contained in:
Patrik Flykt 2018-10-02 12:29:09 -06:00
parent 03d4fc2ed2
commit 107523437c
3 changed files with 67 additions and 0 deletions

View File

@ -346,6 +346,70 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
return 0;
}
int dhcp6_request_prefix_delegation(Link *link) {
Link *l;
Iterator i;
assert_return(link, -EINVAL);
assert_return(link->manager, -EOPNOTSUPP);
if (dhcp6_get_prefix_delegation(link) <= 0)
return 0;
log_link_debug(link, "Requesting DHCPv6 prefixes to be delegated for new link");
HASHMAP_FOREACH(l, link->manager->links, i) {
int r, enabled;
if (l == link)
continue;
if (!l->dhcp6_client)
continue;
r = sd_dhcp6_client_get_prefix_delegation(l->dhcp6_client, &enabled);
if (r < 0) {
log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link");
continue;
}
if (enabled == 0) {
r = sd_dhcp6_client_set_prefix_delegation(l->dhcp6_client, 1);
if (r < 0) {
log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link");
continue;
}
}
r = sd_dhcp6_client_is_running(l->dhcp6_client);
if (r <= 0)
continue;
if (enabled != 0) {
log_link_debug(l, "Requesting re-assignment of delegated prefixes after adding new link");
(void) dhcp6_lease_pd_prefix_acquired(l->dhcp6_client, l);
continue;
}
r = sd_dhcp6_client_stop(l->dhcp6_client);
if (r < 0) {
log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link");
continue;
}
r = sd_dhcp6_client_start(l->dhcp6_client);
if (r < 0) {
log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link");
continue;
}
log_link_debug(l, "Restarted DHCPv6 client to acquire prefix delegations after adding new link");
}
return 0;
}
static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
void *userdata) {
_cleanup_(link_unrefp) Link *link = userdata;

View File

@ -1662,6 +1662,8 @@ static int link_acquire_ipv6_conf(Link *link) {
return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m");
}
(void) dhcp6_request_prefix_delegation(link);
return 0;
}

View File

@ -163,6 +163,7 @@ int ipv4ll_configure(Link *link);
int dhcp4_configure(Link *link);
int dhcp4_set_client_identifier(Link *link);
int dhcp4_set_promote_secondaries(Link *link);
int dhcp6_request_prefix_delegation(Link *link);
int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link, int ir);
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);