platform: handle route table RT_TABLE_UNSPEC specially
Kernel does not allow to add a route with table 0 (RT_TABLE_UNSPEC). It effectively is an alias for the main table. We must consider that when comparing routes sementically.
This commit is contained in:
@@ -2594,7 +2594,7 @@ _nl_msg_new_route (int nlmsg_type,
|
||||
const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj);
|
||||
gboolean is_v4 = klass->addr_family == AF_INET;
|
||||
const guint32 lock = ip_route_get_lock_flag (NMP_OBJECT_CAST_IP_ROUTE (obj));
|
||||
const guint32 table = nm_platform_route_table_coerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced);
|
||||
const guint32 table = nm_platform_route_table_uncoerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced, TRUE);
|
||||
struct rtmsg rtmsg = {
|
||||
.rtm_family = klass->addr_family,
|
||||
.rtm_tos = is_v4
|
||||
|
@@ -2904,7 +2904,7 @@ nm_platform_lookup_predicate_routes_main (const NMPObject *obj,
|
||||
{
|
||||
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||
return !obj->ip_route.table_coerced;
|
||||
return nm_platform_route_table_is_main (obj->ip_route.table_coerced);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -2913,7 +2913,7 @@ nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel (const NMPObject *ob
|
||||
{
|
||||
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||
return !obj->ip_route.table_coerced
|
||||
return nm_platform_route_table_is_main (obj->ip_route.table_coerced)
|
||||
&& obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
|
||||
}
|
||||
|
||||
@@ -3828,12 +3828,14 @@ nm_platform_ip_route_normalize (int addr_family,
|
||||
switch (addr_family) {
|
||||
case AF_INET:
|
||||
r4 = (NMPlatformIP4Route *) route;
|
||||
r4->table_coerced = nm_platform_route_table_coerce (nm_platform_route_table_uncoerce (r4->table_coerced, TRUE));
|
||||
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 = _ip_route_scope_inv_get_normalized (r4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
r6 = (NMPlatformIP6Route *) route;
|
||||
r6->table_coerced = nm_platform_route_table_coerce (nm_platform_route_table_uncoerce (r6->table_coerced, TRUE));
|
||||
nm_utils_ip6_address_clear_host_address (&r6->network, &r6->network, r6->plen);
|
||||
r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r6->rt_source),
|
||||
r6->metric = nm_utils_ip6_route_metric_normalize (r6->metric);
|
||||
@@ -4942,7 +4944,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
|
||||
"%s" /* initrwnd */
|
||||
"%s" /* mtu */
|
||||
"",
|
||||
route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_coerce (route->table_coerced)) : "",
|
||||
route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_uncoerce (route->table_coerced, FALSE)) : "",
|
||||
s_network,
|
||||
route->plen,
|
||||
s_gateway,
|
||||
@@ -5015,7 +5017,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi
|
||||
"%s" /* initrwnd */
|
||||
"%s" /* mtu */
|
||||
"",
|
||||
route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_coerce (route->table_coerced)) : "",
|
||||
route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_uncoerce (route->table_coerced, FALSE)) : "",
|
||||
s_network,
|
||||
route->plen,
|
||||
s_gateway,
|
||||
@@ -5458,7 +5460,7 @@ nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpT
|
||||
switch (cmp_type) {
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
h = NM_HASH_COMBINE (h, obj->table_coerced);
|
||||
h = NM_HASH_COMBINE (h, nm_platform_route_table_uncoerce (obj->table_coerced, TRUE));
|
||||
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
|
||||
h = NM_HASH_COMBINE (h, obj->plen);
|
||||
h = NM_HASH_COMBINE (h, obj->metric);
|
||||
@@ -5484,7 +5486,10 @@ nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpT
|
||||
break;
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
|
||||
h = NM_HASH_COMBINE (h, obj->table_coerced);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
h = NM_HASH_COMBINE (h, nm_platform_route_table_uncoerce (obj->table_coerced, TRUE));
|
||||
else
|
||||
h = NM_HASH_COMBINE (h, obj->table_coerced);
|
||||
h = NM_HASH_COMBINE (h, obj->ifindex);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
|
||||
@@ -5527,7 +5532,8 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
|
||||
switch (cmp_type) {
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
NM_CMP_FIELD (a, b, table_coerced);
|
||||
NM_CMP_DIRECT (nm_platform_route_table_uncoerce (a->table_coerced, TRUE),
|
||||
nm_platform_route_table_uncoerce (b->table_coerced, TRUE));
|
||||
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
|
||||
NM_CMP_FIELD (a, b, plen);
|
||||
NM_CMP_FIELD (a, b, metric);
|
||||
@@ -5555,7 +5561,11 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
|
||||
break;
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
|
||||
NM_CMP_FIELD (a, b, table_coerced);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
|
||||
NM_CMP_DIRECT (nm_platform_route_table_uncoerce (a->table_coerced, TRUE),
|
||||
nm_platform_route_table_uncoerce (b->table_coerced, TRUE));
|
||||
} else
|
||||
NM_CMP_FIELD (a, b, table_coerced);
|
||||
NM_CMP_FIELD (a, b, ifindex);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
|
||||
@@ -5601,7 +5611,7 @@ nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj, NMPlatformIPRouteCmpT
|
||||
switch (cmp_type) {
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
h = NM_HASH_COMBINE (h, obj->table_coerced);
|
||||
h = NM_HASH_COMBINE (h, nm_platform_route_table_uncoerce (obj->table_coerced, TRUE));
|
||||
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
|
||||
h = NM_HASH_COMBINE (h, obj->plen);
|
||||
h = NM_HASH_COMBINE (h, nm_utils_ip6_route_metric_normalize (obj->metric));
|
||||
@@ -5614,7 +5624,10 @@ nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj, NMPlatformIPRouteCmpT
|
||||
break;
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
|
||||
h = NM_HASH_COMBINE (h, obj->table_coerced);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
h = NM_HASH_COMBINE (h, nm_platform_route_table_uncoerce (obj->table_coerced, TRUE));
|
||||
else
|
||||
h = NM_HASH_COMBINE (h, obj->table_coerced);
|
||||
h = NM_HASH_COMBINE (h, obj->ifindex);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
|
||||
@@ -5661,7 +5674,8 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
|
||||
switch (cmp_type) {
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
NM_CMP_FIELD (a, b, table_coerced);
|
||||
NM_CMP_DIRECT (nm_platform_route_table_uncoerce (a->table_coerced, TRUE),
|
||||
nm_platform_route_table_uncoerce (b->table_coerced, TRUE));
|
||||
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
|
||||
NM_CMP_FIELD (a, b, plen);
|
||||
NM_CMP_DIRECT (nm_utils_ip6_route_metric_normalize (a->metric), nm_utils_ip6_route_metric_normalize (b->metric));
|
||||
@@ -5674,7 +5688,11 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
|
||||
break;
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
|
||||
NM_CMP_FIELD (a, b, table_coerced);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
|
||||
NM_CMP_DIRECT (nm_platform_route_table_uncoerce (a->table_coerced, TRUE),
|
||||
nm_platform_route_table_uncoerce (b->table_coerced, TRUE));
|
||||
} else
|
||||
NM_CMP_FIELD (a, b, table_coerced);
|
||||
NM_CMP_FIELD (a, b, ifindex);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
|
||||
|
@@ -426,7 +426,7 @@ typedef union {
|
||||
*
|
||||
* This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and
|
||||
* zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main
|
||||
* table. Use nm_platform_route_table_coerce(). */ \
|
||||
* table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \
|
||||
guint32 table_coerced; \
|
||||
\
|
||||
/*end*/
|
||||
@@ -860,15 +860,21 @@ NMPlatform *nm_platform_get (void);
|
||||
|
||||
/**
|
||||
* nm_platform_route_table_coerce:
|
||||
* @table: the route table, either its original value, or its coerced.
|
||||
* @table: the route table, in its original value as received
|
||||
* from rtm_table/RTA_TABLE.
|
||||
*
|
||||
* Returns: returns the coerced table id. If the table id is like
|
||||
* RTA_TABLE, it returns a value for NMPlatformIPRoute.table_coerced
|
||||
* and vice versa.
|
||||
* Returns: returns the coerced table id, that can be stored in
|
||||
* NMPlatformIPRoute.table_coerced.
|
||||
*/
|
||||
static inline guint32
|
||||
nm_platform_route_table_coerce (guint32 table)
|
||||
{
|
||||
/* For kernel, the default table is RT_TABLE_MAIN (254).
|
||||
* We want that in NMPlatformIPRoute.table_coerced a numeric
|
||||
* zero is the default. Hence, @table_coerced swaps the
|
||||
* value 0 and 254. Use nm_platform_route_table_coerce()
|
||||
* and nm_platform_route_table_uncoerce() to convert between
|
||||
* the two domains. */
|
||||
switch (table) {
|
||||
case 0 /* RT_TABLE_UNSPEC */:
|
||||
return 254;
|
||||
@@ -879,6 +885,45 @@ nm_platform_route_table_coerce (guint32 table)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_route_table_uncoerce:
|
||||
* @table: the route table, in its coerced value
|
||||
* @normalize: whether to normalize RT_TABLE_UNSPEC to
|
||||
* RT_TABLE_MAIN. For kernel, routes with a table id
|
||||
* RT_TABLE_UNSPEC do not exist and are treated like
|
||||
* RT_TABLE_MAIN.
|
||||
*
|
||||
* Returns: reverts the coerced table ID in NMPlatformIPRoute.table_coerced
|
||||
* to the original value as kernel understands it.
|
||||
*/
|
||||
static inline guint32
|
||||
nm_platform_route_table_uncoerce (guint32 table_coerced, gboolean normalize)
|
||||
{
|
||||
/* this undoes nm_platform_route_table_coerce(). */
|
||||
switch (table_coerced) {
|
||||
case 0 /* RT_TABLE_UNSPEC */:
|
||||
return 254;
|
||||
case 254 /* RT_TABLE_MAIN */:
|
||||
return normalize ? 254 : 0;
|
||||
default:
|
||||
return table_coerced;
|
||||
}
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
nm_platform_route_table_is_main (guint32 table)
|
||||
{
|
||||
/* same as
|
||||
* nm_platform_route_table_uncoerce (table, TRUE) == RT_TABLE_MAIN
|
||||
* and
|
||||
* nm_platform_route_table_uncoerce (nm_platform_route_table_coerce (table), TRUE) == RT_TABLE_MAIN
|
||||
*
|
||||
* That is, the function operates the same on @table and its coerced
|
||||
* form.
|
||||
*/
|
||||
return table == 0 || table == 254;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_route_scope_inv:
|
||||
* @scope: the route scope, either its original value, or its inverse.
|
||||
|
Reference in New Issue
Block a user