]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/ndisc: do not override conflicting static routes
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 23 Jun 2024 05:36:08 +0000 (14:36 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 24 Jun 2024 17:46:08 +0000 (02:46 +0900)
We have already ignored conflicting address configurations requested by
NDisc protocol. See ndisc_request_address().
Let's follow the same rule for routes. That is, if there are conflicting
static routes configured or requested, do not override them by NDisc.

Also, swap the order of checking existing route and existing request.

Fixes a regression caused by 972f1d17ab461a51142a142609dd3ec50bae8440.
Prompted by #33346.

src/network/networkd-ndisc.c

index 7cafe1f6a3e5d3ccecf80a5cb6318bd325f6f099..0c43965ea60df7531176d068a26f7f65302fa5ff 100644 (file)
@@ -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;