return link->manager->networks;
}
+static int dhcp6_route_remove_cb(sd_netlink *nl, sd_netlink_message *m,
+ void *userdata) {
+ Link *l = userdata;
+ int r;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0)
+ log_link_debug_errno(l, r, "Received error on unreachable route removal for DHCPv6 delegated subnetl: %m");
+
+ l = link_unref(l);
+
+ return 0;
+}
+
+static int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) {
+ int r;
+ sd_dhcp6_lease *lease;
+ union in_addr_union pd_prefix;
+ uint8_t pd_prefix_len;
+ uint32_t lifetime_preferred, lifetime_valid;
+
+ r = sd_dhcp6_client_get_lease(client, &lease);
+ if (r < 0)
+ return r;
+
+ dhcp6_reset_pd_prefix_network(link);
+ sd_dhcp6_lease_reset_pd_prefix_iter(lease);
+
+ while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
+ &lifetime_preferred,
+ &lifetime_valid) >= 0) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_free_ Route *route;
+
+ if (pd_prefix_len > 64)
+ continue;
+
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
+
+ if (pd_prefix_len < 64) {
+ r = route_new(&route);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Cannot create unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ continue;
+ }
+
+ route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
+ 0, 0, 0, &route);
+ route_update(route, NULL, 0, NULL, NULL, 0, 0,
+ RTN_UNREACHABLE);
+
+ r = route_remove(route, link, dhcp6_route_remove_cb);
+ if (r < 0) {
+ (void) in_addr_to_string(AF_INET6,
+ &pd_prefix, &buf);
+
+ log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ route_free(route);
+ continue;
+ }
+ link = link_ref(link);
+
+ log_link_debug(link, "Removing unreachable route %s/%u",
+ strnull(buf), pd_prefix_len);
+ }
+ }
+
+ return 0;
+}
+
static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
struct in6_addr *pd_prefix,
uint8_t pd_prefix_len,
return r;
}
- if (n_used < n_prefixes) {
- Route *route;
- uint64_t n = n_used;
-
- r = route_new(&route);
- if (r < 0)
- return r;
-
- route->family = AF_INET6;
+ return 0;
+}
- while (n < n_prefixes) {
- route_update(route, &prefix, pd_prefix_len, NULL, NULL,
- 0, 0, RTN_UNREACHABLE);
+static int dhcp6_route_add_cb(sd_netlink *nl, sd_netlink_message *m,
+ void *userdata) {
+ Link *l = userdata;
+ int r;
- r = route_configure(route, dhcp6_link, NULL);
- if (r < 0) {
- route_free(route);
- return r;
- }
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST)
+ log_link_debug_errno(l, r, "Received error when adding unreachable route for DHCPv6 delegated subnet: %m");
- r = in_addr_prefix_next(AF_INET6, &prefix, pd_prefix_len);
- if (r < 0)
- return r;
- }
- }
+ l = link_unref(l);
- return n_used;
+ return 0;
}
+
static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
int r;
sd_dhcp6_lease *lease;
- struct in6_addr pd_prefix;
+ union in_addr_union pd_prefix;
uint8_t pd_prefix_len;
uint32_t lifetime_preferred, lifetime_valid;
_cleanup_free_ char *buf = NULL;
dhcp6_reset_pd_prefix_network(link);
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
- while (sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len,
+ while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
&lifetime_preferred,
&lifetime_valid) >= 0) {
if (pd_prefix_len > 64) {
- (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u",
strnull(buf), pd_prefix_len);
continue;
}
if (pd_prefix_len < 48) {
- (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u",
strnull(buf), pd_prefix_len);
}
- r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix,
+ if (pd_prefix_len < 64) {
+ Route *route = NULL;
+
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
+
+ r = route_new(&route);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Cannot create unreachable route for DHCPv6 delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ continue;
+ }
+
+ route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
+ 0, 0, 0, &route);
+ route_update(route, NULL, 0, NULL, NULL, 0, 0,
+ RTN_UNREACHABLE);
+
+ r = route_configure(route, link, dhcp6_route_add_cb);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Cannot configure unreachable route for delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ route_free(route);
+ continue;
+ }
+ link = link_ref(link);
+
+ route_free(route);
+
+ log_link_debug(link, "Configuring unreachable route for %s/%u",
+ strnull(buf), pd_prefix_len);
+
+ } else
+ log_link_debug(link, "Not adding a blocking route since distributed prefix is /64");
+
+ r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix.in6,
pd_prefix_len,
lifetime_preferred,
lifetime_valid);
if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
log_link_warning(link, "DHCPv6 lease lost");
+ (void) dhcp6_lease_pd_prefix_lost(client, link);
(void) manager_dhcp6_prefix_remove_all(link->manager, link);
link->dhcp6_configured = false;