From fd436c8d67e75eebd0ef9499f699524e4cbe2a92 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 24 Jun 2024 16:20:27 +0900 Subject: [PATCH] network/ndisc: do not remove static routes when received RA with zero lifetime Similar to the previous commit, but for preventing from removing static routes on receiving RA with zero lifetime. Fixes a regresson caused by 479d3e1994a2e4ff7070dc2a0cb1615af7120b0c. Fixes #33346. --- src/network/networkd-ndisc.c | 44 ++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 0c43965ea6..50d284b26a 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -304,18 +304,44 @@ static int ndisc_remove_route(Route *route, Link *link) { if (r < 0) return r; - if (route->pref_set) { - ndisc_set_route_priority(link, route); - return route_remove_and_cancel(route, link->manager); - } - - uint8_t pref; + uint8_t pref, pref_original = route->pref; FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) { + Route *existing; + Request *req; + + /* If the preference is specified by the user config (that is, for semi-static routes), + * rather than RA, then only search conflicting routes that have the same preference. */ + if (route->pref_set && pref != pref_original) + continue; + route->pref = pref; ndisc_set_route_priority(link, route); - r = route_remove_and_cancel(route, link->manager); - if (r < 0) - return r; + + /* Unfortunately, we cannot directly pass 'route' to route_remove_and_cancel() here, as the + * same or similar route may be configured or requested statically. */ + + /* First, check if the route is already requested. If there is an existing route, and also an + * existing pending request, then the source may be updated by the request. So, we first need + * to check the source of the requested route. */ + if (route_get_request(link->manager, route, &req) >= 0) { + existing = ASSERT_PTR(req->userdata); + if (existing->source == NETWORK_CONFIG_SOURCE_STATIC) + continue; + + r = route_remove_and_cancel(existing, link->manager); + if (r < 0) + return r; + } + + /* Then, check if the route exists. */ + if (route_get(link->manager, route, &existing) >= 0) { + if (existing->source == NETWORK_CONFIG_SOURCE_STATIC) + continue; + + r = route_remove_and_cancel(existing, link->manager); + if (r < 0) + return r; + } } return 0; -- 2.25.1