summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-16 18:18:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-16 18:18:14 +0000
commit67c5de60daa85b91fa68be4157e248fa31e75316 (patch)
tree7d567f3360f705ac21600343ef7f7cea645a9222 /src/network
parentAdding upstream version 256.1. (diff)
downloadsystemd-upstream/256.2.tar.xz
systemd-upstream/256.2.zip
Adding upstream version 256.2.upstream/256.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/network')
-rw-r--r--src/network/networkd-ndisc.c69
1 files changed, 54 insertions, 15 deletions
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 7cafe1f..50d284b 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -222,20 +222,33 @@ static int ndisc_request_route(Route *route, Link *link) {
/* Note, here do not call route_remove_and_cancel() with 'route' directly, otherwise
* existing route(s) may be removed needlessly. */
- if (route_get(link->manager, route, &existing) >= 0) {
- /* Found an existing route that may conflict with this route. */
+ /* First, check if a conflicting 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 (!route_can_update(existing, route)) {
- log_link_debug(link, "Found an existing route that conflicts with new route based on a received RA, removing.");
+ if (existing->source == NETWORK_CONFIG_SOURCE_STATIC) {
+ log_link_debug(link, "Found a pending route request that conflicts with new request based on a received RA, ignoring request.");
+ return 0;
+ }
+
+ log_link_debug(link, "Found a pending route request that conflicts with new request based on a received RA, cancelling.");
r = route_remove_and_cancel(existing, link->manager);
if (r < 0)
return r;
}
}
- if (route_get_request(link->manager, route, &req) >= 0) {
- existing = ASSERT_PTR(req->userdata);
+ /* Then, check if a conflicting route exists. */
+ if (route_get(link->manager, route, &existing) >= 0) {
if (!route_can_update(existing, route)) {
- log_link_debug(link, "Found a pending route request that conflicts with new request based on a received RA, cancelling.");
+ if (existing->source == NETWORK_CONFIG_SOURCE_STATIC) {
+ log_link_debug(link, "Found an existing route that conflicts with new route based on a received RA, ignoring request.");
+ return 0;
+ }
+
+ log_link_debug(link, "Found an existing route that conflicts with new route based on a received RA, removing.");
r = route_remove_and_cancel(existing, link->manager);
if (r < 0)
return r;
@@ -291,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;