From: Yu Watanabe Date: Fri, 2 Feb 2024 03:18:33 +0000 (+0900) Subject: network/route: remove existing route if some property conflict with requested ones X-Git-Tag: v256-rc1~856^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7027cdbd79c26d5a8890759a37d70165c8aeb214;p=thirdparty%2Fsystemd.git network/route: remove existing route if some property conflict with requested ones Fixes #28853. --- diff --git a/src/network/networkd-route-metric.c b/src/network/networkd-route-metric.c index 9c417a4fc4f..1bae8939346 100644 --- a/src/network/networkd-route-metric.c +++ b/src/network/networkd-route-metric.c @@ -63,6 +63,28 @@ int route_metric_compare_func(const RouteMetric *a, const RouteMetric *b) { return strcmp_ptr(a->tcp_congestion_control_algo, b->tcp_congestion_control_algo); } +bool route_metric_can_update(const RouteMetric *a, const RouteMetric *b, bool expiration_by_kernel) { + assert(a); + assert(b); + + /* If the kernel has expiration timer for the route, then only MTU can be updated. */ + + if (!expiration_by_kernel) + return route_metric_compare_func(a, b) == 0; + + if (a->n_metrics != b->n_metrics) + return false; + + for (size_t i = 1; i < a->n_metrics; i++) { + if (i != RTAX_MTU) + continue; + if (a->metrics[i] != b->metrics[i]) + return false; + } + + return streq_ptr(a->tcp_congestion_control_algo, b->tcp_congestion_control_algo); +} + int route_metric_set_full(RouteMetric *metric, uint16_t attr, uint32_t value, bool force) { assert(metric); diff --git a/src/network/networkd-route-metric.h b/src/network/networkd-route-metric.h index 1a3aaf2ae59..212f9079cba 100644 --- a/src/network/networkd-route-metric.h +++ b/src/network/networkd-route-metric.h @@ -26,6 +26,7 @@ int route_metric_copy(const RouteMetric *src, RouteMetric *dest); void route_metric_hash_func(const RouteMetric *metric, struct siphash *state); int route_metric_compare_func(const RouteMetric *a, const RouteMetric *b); +bool route_metric_can_update(const RouteMetric *a, const RouteMetric *b, bool expiration_by_kernel); int route_metric_set_full(RouteMetric *metric, uint16_t attr, uint32_t value, bool force); static inline int route_metric_set(RouteMetric *metric, uint16_t attr, uint32_t value) { diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index b0bc7320545..743b4f55200 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -1305,6 +1305,43 @@ static bool route_by_kernel(const Route *route) { return false; } +bool route_can_update(const Route *existing, const Route *requesting) { + assert(existing); + assert(requesting); + + if (route_compare_func(existing, requesting) != 0) + return false; + + switch (existing->family) { + case AF_INET: + if (existing->nexthop.weight != requesting->nexthop.weight) + return false; + return true; + + case AF_INET6: + if (existing->protocol != requesting->protocol) + return false; + if (existing->type != requesting->type) + return false; + if (existing->flags != requesting->flags) + return false; + if (!in6_addr_equal(&existing->prefsrc.in6, &requesting->prefsrc.in6)) + return false; + if (existing->pref != requesting->pref) + return false; + if (existing->expiration_managed_by_kernel && requesting->lifetime_usec != USEC_INFINITY) + return false; /* We cannot disable expiration timer in the kernel. */ + if (!route_metric_can_update(&existing->metric, &requesting->metric, existing->expiration_managed_by_kernel)) + return false; + if (existing->nexthop.weight != requesting->nexthop.weight) + return false; + return true; + + default: + assert_not_reached(); + } +} + static int link_unmark_route(Link *link, const Route *route, const RouteNextHop *nh) { _cleanup_(route_unrefp) Route *tmp = NULL; Route *existing; @@ -1324,6 +1361,9 @@ static int link_unmark_route(Link *link, const Route *route, const RouteNextHop if (route_get(link->manager, tmp, &existing) < 0) return 0; + if (!route_can_update(existing, tmp)) + return 0; + route_unmark(existing); return 1; } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index a5019db65cb..d292716b1d6 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -97,6 +97,8 @@ int route_remove_and_cancel(Route *route, Manager *manager); int route_get(Manager *manager, const Route *route, Route **ret); +bool route_can_update(const Route *existing, const Route *requesting); + int link_drop_routes(Link *link, bool foreign); static inline int link_drop_static_routes(Link *link) { return link_drop_routes(link, false);