platform: fix handling rt_scope of IPv4 route

Kernel does not allow to add an IPv4 route with rt_scope RT_SCOPE_NOWHERE
(255). It would fail with EINVAL.

While adding a route, we coerce/normalize the scope in
nm_platform_ip_route_normalize(). However, that should only be
done, if the scope is not explicitly set already. Otherwise,
leave it unchanged.

nm_platform_ip_route_normalize() is related to the compare functions.
Several compare modes do a fuzzy comparison, and they should compare
equal as if they would be normalized. Hence, we must do the same
normalization there.

One pecularity in NetworkManager is that we track scope as it's
inverse. The reason is to have a default value of zero meaning
RT_SCOPE_NOWHERE. Hence "scope_inv".
This commit is contained in:
Thomas Haller 2017-08-17 15:17:40 +02:00
parent 69a50a5053
commit 974ff62996

View file

@ -3482,6 +3482,26 @@ nm_platform_ip_address_flush (NMPlatform *self,
/*****************************************************************************/
static guint8
_ip_route_scope_inv_get_normalized (const NMPlatformIP4Route *route)
{
/* in kernel, you cannot set scope to RT_SCOPE_NOWHERE (255).
* That means, in NM, we treat RT_SCOPE_NOWHERE as unset, and detect
* it based on the presence of the gateway. In other words, when adding
* a route with scope RT_SCOPE_NOWHERE (in NetworkManager) to kernel,
* the resulting scope will be either "link" or "universe" (depending
* on the gateway).
*
* Note that internally, we track @scope_inv is the inverse of scope,
* so that the default equals zero (~(RT_SCOPE_NOWHERE)).
**/
if (route->scope_inv == 0) {
return nm_platform_route_scope_inv (!route->gateway
? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
}
return route->scope_inv;
}
/**
* nm_platform_ip_route_normalize:
* @addr_family: AF_INET or AF_INET6
@ -3503,8 +3523,7 @@ nm_platform_ip_route_normalize (int addr_family,
r4 = (NMPlatformIP4Route *) route;
r4->network = nm_utils_ip4_address_clear_host_address (r4->network, r4->plen);
r4->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r4->rt_source);
r4->scope_inv = nm_platform_route_scope_inv (!r4->gateway
? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
r4->scope_inv = _ip_route_scope_inv_get_normalized (r4);
break;
case AF_INET6:
r6 = (NMPlatformIP6Route *) route;
@ -4814,7 +4833,7 @@ nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpT
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
h = NM_HASH_COMBINE (h, obj->ifindex);
h = NM_HASH_COMBINE (h, nmp_utils_ip_config_source_round_trip_rtprot (obj->rt_source));
h = NM_HASH_COMBINE (h, obj->scope_inv);
h = NM_HASH_COMBINE (h, _ip_route_scope_inv_get_normalized (obj));
h = NM_HASH_COMBINE (h, obj->gateway);
h = NM_HASH_COMBINE (h, obj->mss);
h = NM_HASH_COMBINE (h, obj->pref_src);
@ -4840,12 +4859,14 @@ nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpT
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
h = NM_HASH_COMBINE (h, obj->gateway);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
h = NM_HASH_COMBINE (h, nmp_utils_ip_config_source_round_trip_rtprot (obj->rt_source));
else
h = NM_HASH_COMBINE (h, _ip_route_scope_inv_get_normalized (obj));
} else {
h = NM_HASH_COMBINE (h, obj->rt_source);
h = NM_HASH_COMBINE (h, obj->scope_inv);
}
h = NM_HASH_COMBINE (h, obj->mss);
h = NM_HASH_COMBINE (h, obj->scope_inv);
h = NM_HASH_COMBINE (h, obj->pref_src);
h = NM_HASH_COMBINE (h, obj->rt_cloned);
h = NM_HASH_COMBINE (h, obj->tos);
@ -4884,7 +4905,8 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
NM_CMP_FIELD (a, b, ifindex);
NM_CMP_DIRECT (nmp_utils_ip_config_source_round_trip_rtprot (a->rt_source),
nmp_utils_ip_config_source_round_trip_rtprot (b->rt_source));
NM_CMP_FIELD (a, b, scope_inv);
NM_CMP_DIRECT (_ip_route_scope_inv_get_normalized (a),
_ip_route_scope_inv_get_normalized (b));
NM_CMP_FIELD (a, b, gateway);
NM_CMP_FIELD (a, b, mss);
NM_CMP_FIELD (a, b, pref_src);
@ -4913,10 +4935,13 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT (nmp_utils_ip_config_source_round_trip_rtprot (a->rt_source),
nmp_utils_ip_config_source_round_trip_rtprot (b->rt_source));
} else
NM_CMP_DIRECT (_ip_route_scope_inv_get_normalized (a),
_ip_route_scope_inv_get_normalized (b));
} else {
NM_CMP_FIELD (a, b, rt_source);
NM_CMP_FIELD (a, b, scope_inv);
}
NM_CMP_FIELD (a, b, mss);
NM_CMP_FIELD (a, b, scope_inv);
NM_CMP_FIELD (a, b, pref_src);
NM_CMP_FIELD_UNSAFE (a, b, rt_cloned);
NM_CMP_FIELD (a, b, tos);