diff options
author | Thomas Haller <thaller@redhat.com> | 2017-09-22 15:26:56 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-09-26 11:30:58 +0200 |
commit | 166002ca667c2f0081b411ee94f331d6f37231b6 (patch) | |
tree | 333c7323a9ad3de6c18ebd1b5d6e00e4dd6b819a | |
parent | 7070d17cedd09d07f12ce977dd1e16cecf8d4b45 (diff) | |
download | NetworkManager-166002ca667c2f0081b411ee94f331d6f37231b6.tar.gz |
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.
-rw-r--r-- | src/platform/nm-linux-platform.c | 2 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 42 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 55 |
3 files changed, 81 insertions, 18 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 1edc2183bb..7245d16e77 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -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 diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 686943a13f..b0cd3bc997 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -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)); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index e68457ca2b..bbc268125c 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -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; @@ -880,6 +886,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. * |