Fixes #28853.
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);
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) {
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;
if (route_get(link->manager, tmp, &existing) < 0)
return 0;
+ if (!route_can_update(existing, tmp))
+ return 0;
+
route_unmark(existing);
return 1;
}
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);