summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-09-22 15:26:56 +0200
committerThomas Haller <thaller@redhat.com>2017-09-26 11:30:58 +0200
commit166002ca667c2f0081b411ee94f331d6f37231b6 (patch)
tree333c7323a9ad3de6c18ebd1b5d6e00e4dd6b819a
parent7070d17cedd09d07f12ce977dd1e16cecf8d4b45 (diff)
downloadNetworkManager-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.c2
-rw-r--r--src/platform/nm-platform.c42
-rw-r--r--src/platform/nm-platform.h55
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.
*