ndisc_set_route_priority(link, route);
existing = ASSERT_PTR(req->userdata);
- if (!route_can_update(existing, route)) {
+ if (!route_can_update(link->manager, existing, route)) {
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;
route->pref = pref_original;
ndisc_set_route_priority(link, route);
- if (!route_can_update(existing, route)) {
+ if (!route_can_update(link->manager, existing, route)) {
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;
return false;
}
-bool route_can_update(const Route *existing, const Route *requesting) {
+bool route_can_update(Manager *manager, const Route *existing, const Route *requesting) {
+ int r;
+
+ assert(manager);
assert(existing);
assert(requesting);
- if (route_compare_func(existing, requesting) != 0)
+ if (route_compare_func(existing, requesting) != 0) {
+ log_route_debug(existing, "Cannot update route, as the existing route is different", manager);
return false;
+ }
switch (existing->family) {
case AF_INET:
- if (existing->nexthop.weight != requesting->nexthop.weight)
+ if (existing->nexthop.weight != requesting->nexthop.weight) {
+ log_debug("Cannot update route: existing weight: %u, requesting weight: %u",
+ existing->nexthop.weight, requesting->nexthop.weight);
return false;
+ }
return true;
case AF_INET6:
- if (existing->protocol != requesting->protocol)
+ if (existing->protocol != requesting->protocol) {
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *ex = NULL, *req = NULL;
+
+ r = route_protocol_to_string_alloc(existing->protocol, &ex);
+ if (r < 0)
+ return false;
+
+ r = route_protocol_to_string_alloc(requesting->protocol, &req);
+ if (r < 0)
+ return false;
+
+ log_debug("Cannot update route: existing protocol: %s, requesting protocol: %s", ex, req);
+ }
+
return false;
- if (existing->type != requesting->type)
+ }
+ if (existing->type != requesting->type) {
+ log_debug("Cannot update route: existing type: %s, requesting type: %s",
+ route_type_to_string(existing->type),
+ route_type_to_string(requesting->type));
+
return false;
- if ((existing->flags & ~RTNH_COMPARE_MASK) != (requesting->flags & ~RTNH_COMPARE_MASK))
+ }
+ if ((existing->flags & ~RTNH_COMPARE_MASK) != (requesting->flags & ~RTNH_COMPARE_MASK)) {
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *ex = NULL, *req = NULL;
+
+ r = route_flags_to_string_alloc(existing->flags, &ex);
+ if (r < 0)
+ return false;
+
+ r = route_flags_to_string_alloc(requesting->flags, &req);
+ if (r < 0)
+ return false;
+
+ log_debug("Cannot update route: existing flags: %s, requesting flags: %s", ex, req);
+ }
+
return false;
- if (!in6_addr_equal(&existing->prefsrc.in6, &requesting->prefsrc.in6))
+ }
+ if (!in6_addr_equal(&existing->prefsrc.in6, &requesting->prefsrc.in6)) {
+ log_debug("Cannot update route: existing preferred source: %s, requesting preferred source: %s",
+ IN6_ADDR_TO_STRING(&existing->prefsrc.in6),
+ IN6_ADDR_TO_STRING(&requesting->prefsrc.in6));
return false;
- if (existing->pref != requesting->pref)
+ }
+ if (existing->pref != requesting->pref) {
+ log_debug("Cannot update route: existing preference: %u, requesting preference: %u",
+ existing->pref, requesting->pref);
return false;
- if (existing->expiration_managed_by_kernel && requesting->lifetime_usec == USEC_INFINITY)
+ }
+ if (existing->expiration_managed_by_kernel && requesting->lifetime_usec == USEC_INFINITY) {
+ log_route_debug(existing,
+ "Cannot update route: the expiration is managed by the kernel and requested lifetime is infinite",
+ manager);
return false; /* We cannot disable expiration timer in the kernel. */
- if (!route_metric_can_update(&existing->metric, &requesting->metric, existing->expiration_managed_by_kernel))
+ }
+ if (!route_metric_can_update(&existing->metric, &requesting->metric, existing->expiration_managed_by_kernel)) {
+ log_route_debug(existing,
+ "Cannot update route: expiration is managed by the kernel or metrics differ",
+ manager);
return false;
- if (existing->nexthop.weight != requesting->nexthop.weight)
+ }
+ if (existing->nexthop.weight != requesting->nexthop.weight) {
+ log_debug("Cannot update route: existing weight: %u, requesting weight: %u",
+ existing->nexthop.weight, requesting->nexthop.weight);
return false;
+ }
return true;
default:
if (route_get(link->manager, tmp, &existing) < 0)
return 0;
- if (!route_can_update(existing, tmp))
+ if (!route_can_update(link->manager, existing, tmp))
return 0;
route_unmark(existing);