1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-21 02:50:18 +03:00

network/route: remove existing route if some property conflict with requested ones

Fixes #28853.
This commit is contained in:
Yu Watanabe 2024-02-02 12:18:33 +09:00
parent e09b758876
commit 7027cdbd79
4 changed files with 65 additions and 0 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);