network: drop pending requests (#43741)

Fixes #39460.
This commit is contained in:
Yu Watanabe
2026-09-23 19:21:10 +09:00
committed by GitHub
8 changed files with 74 additions and 32 deletions
+3
View File
@@ -1335,6 +1335,9 @@ int address_remove_and_cancel(Address *address, Link *link) {
if (waiting || (address->link && address_exists(address)))
return address_remove(address, link);
/* Otherwise, the address should be already gone or not configured yet. */
ipv4acd_detach(link, address);
return 0;
}
@@ -271,6 +271,10 @@ int dhcp_pd_remove(Link *link, bool only_marked) {
}
}
if (!only_marked)
/* Also drop pending requests when the lease is lost or the client is stopped. */
RET_GATHER(ret, link_drop_requests(link, NETWORK_CONFIG_SOURCE_DHCP_PD));
return ret;
}
+4
View File
@@ -272,6 +272,10 @@ static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) {
RET_GATHER(ret, address_remove_and_cancel(address, link));
}
if (!only_marked)
/* Also drop pending requests when the lease is lost or the client is stopped. */
RET_GATHER(ret, link_drop_requests(link, NETWORK_CONFIG_SOURCE_DHCP4));
return ret;
}
+4
View File
@@ -83,6 +83,10 @@ static int dhcp6_remove(Link *link, bool only_marked) {
RET_GATHER(ret, address_remove_and_cancel(address, link));
}
if (!only_marked)
/* Also drop pending requests when the lease is lost or the client is stopped. */
RET_GATHER(ret, link_drop_requests(link, NETWORK_CONFIG_SOURCE_DHCP6));
return ret;
}
+1 -1
View File
@@ -152,7 +152,7 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
void *val, *key;
HASHMAP_FOREACH_KEY(val, key, link->ipv4acd_by_address)
if (val == acd) {
(void) address_get(link, key, &address);
(void) address_get_harder(link, key, &address);
break;
}
+54 -31
View File
@@ -1068,13 +1068,17 @@ static void link_drop_from_master(Link *link) {
link_unref(set_remove(master->slaves, link));
}
static int link_drop_requests(Link *link) {
int link_drop_requests(Link *link, NetworkConfigSource source) {
Request *req;
int ret = 0;
assert(link);
assert(link->manager);
/* If the interface is already removed, then per-source request removal is not necessary. */
if (source >= 0 && link->state == LINK_STATE_LINGER)
return 0;
ORDERED_SET_FOREACH(req, link->manager->request_queue) {
if (req->link != link)
continue;
@@ -1082,39 +1086,58 @@ static int link_drop_requests(Link *link) {
/* If the request is already called, but its reply is not received, then we need to
* drop the configuration (e.g. address) here. Note, if the configuration is known,
* it will be handled later by link_drop_unmanaged_addresses() or so. */
if (req->waiting_reply && link->state != LINK_STATE_LINGER)
switch (req->type) {
case REQUEST_TYPE_ADDRESS: {
Address *address = ASSERT_PTR(req->userdata);
bool remove = req->waiting_reply && link->state != LINK_STATE_LINGER;
if (address_get(link, address, NULL) < 0)
switch (req->type) {
case REQUEST_TYPE_ADDRESS: {
Address *address = ASSERT_PTR(req->userdata);
if (source >= 0 && address->source != source)
continue;
if (address_get(link, address, /* ret= */ NULL) < 0) {
if (remove)
RET_GATHER(ret, address_remove(address, link));
break;
else
ipv4acd_detach(link, address);
}
case REQUEST_TYPE_NEIGHBOR: {
Neighbor *neighbor = ASSERT_PTR(req->userdata);
break;
}
case REQUEST_TYPE_NEIGHBOR: {
Neighbor *neighbor = ASSERT_PTR(req->userdata);
if (neighbor_get(link, neighbor, NULL) < 0)
RET_GATHER(ret, neighbor_remove(neighbor, link));
break;
}
case REQUEST_TYPE_NEXTHOP: {
NextHop *nexthop = ASSERT_PTR(req->userdata);
if (source >= 0 && neighbor->source != source)
continue;
if (nexthop_get_by_id(link->manager, nexthop->id, NULL) < 0)
RET_GATHER(ret, nexthop_remove(nexthop, link->manager));
break;
}
case REQUEST_TYPE_ROUTE: {
Route *route = ASSERT_PTR(req->userdata);
if (remove && neighbor_get(link, neighbor, /* ret= */ NULL) < 0)
RET_GATHER(ret, neighbor_remove(neighbor, link));
break;
}
case REQUEST_TYPE_NEXTHOP: {
NextHop *nexthop = ASSERT_PTR(req->userdata);
if (route_get(link->manager, route, NULL) < 0)
RET_GATHER(ret, route_remove(route, link->manager));
break;
}
default:
;
}
if (source >= 0 && nexthop->source != source)
continue;
if (remove && nexthop_get_by_id(link->manager, nexthop->id, /* ret= */ NULL) < 0)
RET_GATHER(ret, nexthop_remove(nexthop, link->manager));
break;
}
case REQUEST_TYPE_ROUTE: {
Route *route = ASSERT_PTR(req->userdata);
if (source >= 0 && route->source != source)
continue;
if (remove && route_get(link->manager, route, /* ret= */ NULL) < 0)
RET_GATHER(ret, route_remove(route, link->manager));
break;
}
default:
/* If a source is specified, then ignore all other kinds of requests. */
if (source >= 0)
continue;
}
request_detach(req);
}
@@ -1135,7 +1158,7 @@ static Link *link_drop(Link *link) {
/* Drop all references from other links and manager. Note that async netlink calls may have
* references to the link, and they will be dropped when we receive replies. */
(void) link_drop_requests(link);
(void) link_drop_requests(link, _NETWORK_CONFIG_SOURCE_INVALID);
link_free_bound_to_list(link);
link_free_bound_by_list(link);
@@ -1427,7 +1450,7 @@ static void link_enter_unmanaged(Link *link) {
"Unmanaging interface.");
(void) link_stop_engines(link, /* may_keep_dynamic= */ false);
(void) link_drop_requests(link);
(void) link_drop_requests(link, _NETWORK_CONFIG_SOURCE_INVALID);
(void) link_drop_static_config(link);
/* The bound_to map depends on .network file, hence it needs to be freed. But, do not free the
@@ -1515,7 +1538,7 @@ int link_reconfigure_impl(Link *link, LinkReconfigurationFlag flags) {
isempty(joined) ? "" : ")");
/* Dropping configurations based on the old .network file. */
r = link_drop_requests(link);
r = link_drop_requests(link, _NETWORK_CONFIG_SOURCE_INVALID);
if (r < 0)
return r;
+1
View File
@@ -239,6 +239,7 @@ int link_ipv6ll_gained(Link *link);
int link_ipv6ll_lost(Link *link, const struct in6_addr *dropped_ipv6ll, bool has_replacement);
bool link_has_ipv6_connectivity(Link *link);
int link_drop_requests(Link *link, NetworkConfigSource source);
int link_stop_engines(Link *link, bool may_keep_dynamic);
DECLARE_STRING_TABLE_LOOKUP(link_state, LinkState);
+3
View File
@@ -3194,6 +3194,9 @@ int ndisc_stop(Link *link) {
void ndisc_flush(Link *link) {
assert(link);
/* First, drop pending requests. */
(void) link_drop_requests(link, NETWORK_CONFIG_SOURCE_NDISC);
/* Remove all addresses, routes, RDNSS, DNSSL, DNR, and Captive Portal entries, without exception. */
(void) ndisc_drop_outdated(link, /* router= */ NULL, /* timestamp_usec= */ USEC_INFINITY);
(void) ndisc_drop_redirect(link, /* router= */ NULL);