diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index 0819ed54f1..7a5d0e0415 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -613,8 +613,49 @@ static int dhcp_pd_finalize(Link *link) { return 0; } -void dhcp_pd_prefix_lost(Link *uplink) { +static void dhcp_pd_mark_unreachable_route(Manager *manager, NetworkConfigSource source) { + assert(manager); + Route *route; + SET_FOREACH(route, manager->routes) { + if (route->source != source) + continue; + if (route->family != AF_INET6) + continue; + if (route->nexthop.ifindex != 0) /* IPv6 unreachable has 0 ifindex. */ + continue; + if (!route_type_is_reject(route->type)) + continue; + + route_mark(route); + } +} + +static int dhcp_pd_remove_unreachable_route(Manager *manager, NetworkConfigSource source, bool only_marked) { + int ret = 0; + + assert(manager); + + Route *route; + SET_FOREACH(route, manager->routes) { + if (route->source != source) + continue; + if (route->family != AF_INET6) + continue; + if (route->nexthop.ifindex != 0) /* IPv6 unreachable has 0 ifindex. */ + continue; + if (!route_type_is_reject(route->type)) + continue; + if (only_marked && !route_is_marked(route)) + continue; + + RET_GATHER(ret, route_remove_and_cancel(route, manager)); + } + + return ret; +} + +static void dhcp_pd_prefix_lost(Link *uplink, NetworkConfigSource source) { Link *link; int r; @@ -630,22 +671,7 @@ void dhcp_pd_prefix_lost(Link *uplink) { link_enter_failed(link); } - SET_FOREACH(route, uplink->manager->routes) { - if (!IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6)) - continue; - if (route->family != AF_INET6) - continue; - if (route->type != RTN_UNREACHABLE) - continue; - if (!set_contains(uplink->dhcp_pd_prefixes, - &(struct in_addr_prefix) { - .family = AF_INET6, - .prefixlen = route->dst_prefixlen, - .address = route->dst })) - continue; - - (void) route_remove_and_cancel(route, uplink->manager); - } + (void) dhcp_pd_remove_unreachable_route(uplink->manager, source, /* only_marked = */ false); set_clear(uplink->dhcp_pd_prefixes); } @@ -653,13 +679,20 @@ void dhcp_pd_prefix_lost(Link *uplink) { void dhcp4_pd_prefix_lost(Link *uplink) { Link *tunnel; - dhcp_pd_prefix_lost(uplink); + assert(uplink); + assert(uplink->manager); + + dhcp_pd_prefix_lost(uplink, NETWORK_CONFIG_SOURCE_DHCP4); if (uplink->dhcp4_6rd_tunnel_name && link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, &tunnel) >= 0) (void) link_remove(tunnel); } +void dhcp6_pd_prefix_lost(Link *uplink) { + dhcp_pd_prefix_lost(uplink, NETWORK_CONFIG_SOURCE_DHCP6); +} + static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) { int r; @@ -1005,9 +1038,11 @@ int dhcp4_pd_prefix_acquired(Link *uplink) { return r; /* Request unreachable route */ + dhcp_pd_mark_unreachable_route(uplink->manager, NETWORK_CONFIG_SOURCE_DHCP4); r = dhcp4_request_unreachable_route(uplink, &pd_prefix, pd_prefixlen, lifetime_usec, &server_address); if (r < 0) return r; + (void) dhcp_pd_remove_unreachable_route(uplink->manager, NETWORK_CONFIG_SOURCE_DHCP4, /* only_marked = */ true); /* Create or update 6rd SIT tunnel device. */ r = dhcp4_pd_create_6rd_tunnel(uplink, dhcp4_pd_6rd_tunnel_create_handler); @@ -1085,11 +1120,14 @@ int dhcp6_pd_prefix_acquired(Link *uplink) { assert(uplink); assert(uplink->dhcp6_lease); + assert(uplink->manager); r = sd_dhcp6_lease_get_server_address(uplink->dhcp6_lease, &server_address.in6); if (r < 0) return log_link_warning_errno(uplink, r, "Failed to get server address of DHCPv6 lease: %m"); + dhcp_pd_mark_unreachable_route(uplink->manager, NETWORK_CONFIG_SOURCE_DHCP6); + /* First, logs acquired prefixes and request unreachable routes. */ FOREACH_DHCP6_PD_PREFIX(uplink->dhcp6_lease) { usec_t lifetime_valid_usec; @@ -1120,6 +1158,8 @@ int dhcp6_pd_prefix_acquired(Link *uplink) { return r; } + (void) dhcp_pd_remove_unreachable_route(uplink->manager, NETWORK_CONFIG_SOURCE_DHCP6, /* only_marked = */ true); + /* Then, assign subnet prefixes. */ HASHMAP_FOREACH(link, uplink->manager->links_by_index) { if (!dhcp_pd_is_uplink(link, uplink, /* accept_auto = */ true)) diff --git a/src/network/networkd-dhcp-prefix-delegation.h b/src/network/networkd-dhcp-prefix-delegation.h index 099e1444a5..27e920e1cf 100644 --- a/src/network/networkd-dhcp-prefix-delegation.h +++ b/src/network/networkd-dhcp-prefix-delegation.h @@ -20,8 +20,8 @@ int dhcp_request_prefix_delegation(Link *link); int link_drop_dhcp_pd_config(Link *link, Network *network); int dhcp4_pd_prefix_acquired(Link *uplink); int dhcp6_pd_prefix_acquired(Link *uplink); -void dhcp_pd_prefix_lost(Link *uplink); void dhcp4_pd_prefix_lost(Link *uplink); +void dhcp6_pd_prefix_lost(Link *uplink); int dhcp_pd_reconfigure_address(Address *address, Link *link); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_pd_subnet_id); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index ca4e2a5926..dae1a7b7f4 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -247,7 +247,7 @@ static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) { SET_FOREACH(route, link->manager->routes) { if (route->source != NETWORK_CONFIG_SOURCE_DHCP4) continue; - if (route->nexthop.ifindex != 0 && route->nexthop.ifindex != link->ifindex) + if (route->nexthop.ifindex != link->ifindex) continue; if (only_marked && !route_is_marked(route)) continue; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 88e7c0a263..a6808fdb75 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -307,7 +307,6 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) { int r; link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP6); - manager_mark_routes(link->manager, NULL, NETWORK_CONFIG_SOURCE_DHCP6); r = sd_dhcp6_client_get_lease(client, &lease); if (r < 0) @@ -330,7 +329,7 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) { return r; } else if (sd_dhcp6_lease_has_pd_prefix(lease_old)) /* When we had PD prefixes but not now, we need to remove them. */ - dhcp_pd_prefix_lost(link); + dhcp6_pd_prefix_lost(link); if (link->dhcp6_messages == 0) { link->dhcp6_configured = true; @@ -377,7 +376,7 @@ static int dhcp6_lease_lost(Link *link) { log_link_info(link, "DHCPv6 lease lost"); if (sd_dhcp6_lease_has_pd_prefix(link->dhcp6_lease)) - dhcp_pd_prefix_lost(link); + dhcp6_pd_prefix_lost(link); link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);