summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-02-01 23:49:37 +0100
committerThomas Haller <thaller@redhat.com>2022-02-09 19:13:03 +0100
commit92f51c6b43ad334faca83107c025ce746eea4c0f (patch)
treee5877d63337d653224766709902bbf5e8a180bef
parent7ad14b86f80f0dc106e1c5756fb90ce1c96a3758 (diff)
downloadNetworkManager-92f51c6b43ad334faca83107c025ce746eea4c0f.tar.gz
platform: add support for blackhole,unreachable,prohibit route type
-rw-r--r--src/core/platform/tests/test-route.c62
-rw-r--r--src/libnm-platform/nm-linux-platform.c44
-rw-r--r--src/libnm-platform/nmp-object.c10
3 files changed, 108 insertions, 8 deletions
diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c
index 37909d55ef..4974a409cb 100644
--- a/src/core/platform/tests/test-route.c
+++ b/src/core/platform/tests/test-route.c
@@ -1886,6 +1886,64 @@ again:
/*****************************************************************************/
+static void
+test_blackhole(gconstpointer test_data)
+{
+ int TEST_IDX = GPOINTER_TO_INT(test_data);
+ const int addr_family = (TEST_IDX == 1) ? AF_INET : AF_INET6;
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ const NMDedupMultiHeadEntry *head_entry;
+ NMDedupMultiIter iter;
+ const NMPObject *obj;
+ NMPObject obj_stack;
+ NMPlatformIPXRoute rr = {};
+ int r = -1;
+ int i;
+
+ if (IS_IPv4) {
+ rr.r4 = (const NMPlatformIP4Route){
+ .type_coerced = nmtst_rand_select(RTN_BLACKHOLE, RTN_UNREACHABLE, RTN_PROHIBIT),
+ };
+ } else {
+ rr.r6 = (const NMPlatformIP6Route){
+ .type_coerced = nmtst_rand_select(RTN_BLACKHOLE, RTN_UNREACHABLE, RTN_PROHIBIT),
+ .metric = 1000,
+ };
+ }
+
+ nm_platform_ip_route_normalize(addr_family, &rr.rx);
+
+ if (IS_IPv4)
+ r = nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r4);
+ else
+ r = nm_platform_ip6_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r6);
+
+ g_assert_cmpint(r, ==, 0);
+
+ nmp_object_stackinit(&obj_stack, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), &rr);
+
+ obj = nm_platform_lookup_obj(NM_PLATFORM_GET, NMP_CACHE_ID_TYPE_OBJECT_TYPE, &obj_stack);
+
+ _LOGT(">>> adding %s",
+ nmp_object_to_string(&obj_stack, NMP_OBJECT_TO_STRING_ALL, g_alloca(1000), 1000));
+ _LOGT(">>> found %s",
+ nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_ALL, g_alloca(1000), 1000));
+
+ g_assert(obj);
+
+ head_entry = nm_platform_lookup_object(NM_PLATFORM_GET, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), 0);
+ g_assert(head_entry);
+ g_assert_cmpint(head_entry->len, ==, 1);
+ i = 0;
+ nm_dedup_multi_iter_for_each (&iter, head_entry) {
+ i++;
+ g_assert(iter.current->obj == obj);
+ }
+ g_assert_cmpint(i, ==, 1);
+}
+
+/*****************************************************************************/
+
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
void
@@ -1923,4 +1981,8 @@ _nmtstp_setup_tests(void)
add_test_func_data("/route/rule/3", test_rule, GINT_TO_POINTER(3));
add_test_func_data("/route/rule/4", test_rule, GINT_TO_POINTER(4));
}
+ if (nmtstp_is_root_test()) {
+ add_test_func_data("/route/blackhole/1", test_blackhole, GINT_TO_POINTER(1));
+ add_test_func_data("/route/blackhole/2", test_blackhole, GINT_TO_POINTER(2));
+ }
}
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index 411a49d599..93935b98d4 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -3423,7 +3423,12 @@ _new_from_nl_route(struct nlmsghdr *nlh, gboolean id_only)
else
return NULL;
- if (!NM_IN_SET(rtm->rtm_type, RTN_UNICAST, RTN_LOCAL))
+ if (!NM_IN_SET(rtm->rtm_type,
+ RTN_UNICAST,
+ RTN_LOCAL,
+ RTN_BLACKHOLE,
+ RTN_UNREACHABLE,
+ RTN_PROHIBIT))
return NULL;
if (nlmsg_parse_arr(nlh, sizeof(struct rtmsg), tb, policy) < 0)
@@ -3497,16 +3502,45 @@ rta_multipath_done:;
/* If no nexthops have been provided via RTA_MULTIPATH
* we add it as regular nexthop to maintain backwards
* compatibility */
- nh.ifindex = ifindex;
- nh.gateway = gateway;
+ nh.ifindex = ifindex;
+ nh.gateway = gateway;
+ nh.is_present = TRUE;
} else {
/* Kernel supports new style nexthop configuration,
* verify that it is a duplicate and ignore old-style nexthop. */
if (nh.ifindex != ifindex || memcmp(&nh.gateway, &gateway, addr_len) != 0)
return NULL;
}
- } else if (!nh.is_present)
- return NULL;
+ }
+
+ if (nm_platform_route_type_is_nodev(rtm->rtm_type)) {
+ /* These routes are special. They don't have an device/ifindex.
+ *
+ * Well, actually, for IPv6 kernel will always say that the device is
+ * 1 (lo). Of course it does!! */
+ if (nh.is_present) {
+ if (IS_IPv4) {
+ if (nh.ifindex != 0 || nh.gateway.addr4 != 0) {
+ /* we only accept kernel to notify about the ifindex/gateway, if it
+ * is zero. This is only to be a bit forgiving, but we really don't
+ * know how to handle such routes that have an ifindex. */
+ return NULL;
+ }
+ } else {
+ if (!NM_IN_SET(nh.ifindex, 0, 1) || !IN6_IS_ADDR_UNSPECIFIED(&nh.gateway.addr6)) {
+ /* We allow an ifindex of 1 (will be normalized to zero). Otherwise,
+ * we don't expect a device/next hop. */
+ return NULL;
+ }
+ nh.ifindex = 0;
+ }
+ }
+ } else {
+ if (!nh.is_present) {
+ /* a "normal" route needs a device. This is not the route we are looking for. */
+ return NULL;
+ }
+ }
/*****************************************************************/
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index 8bd43ef0e5..d518e6e589 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -386,7 +386,11 @@ _idx_obj_part(const DedupMultiIdxType *idx_type,
nm_hash_update_val(h, obj_a);
return 0;
}
- nm_assert(NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex > 0);
+ nm_assert(NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex > 0
+ || (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex == 0
+ && NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_a),
+ NMP_OBJECT_TYPE_IP4_ROUTE,
+ NMP_OBJECT_TYPE_IP6_ROUTE)));
if (obj_b) {
return NMP_OBJECT_GET_TYPE(obj_a) == NMP_OBJECT_GET_TYPE(obj_b)
&& NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex
@@ -401,14 +405,14 @@ _idx_obj_part(const DedupMultiIdxType *idx_type,
case NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID:
obj_type = NMP_OBJECT_GET_TYPE(obj_a);
if (!NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)
- || NMP_OBJECT_CAST_IP_ROUTE(obj_a)->ifindex <= 0) {
+ || NMP_OBJECT_CAST_IP_ROUTE(obj_a)->ifindex < 0) {
if (h)
nm_hash_update_val(h, obj_a);
return 0;
}
if (obj_b) {
return obj_type == NMP_OBJECT_GET_TYPE(obj_b)
- && NMP_OBJECT_CAST_IP_ROUTE(obj_b)->ifindex > 0
+ && NMP_OBJECT_CAST_IP_ROUTE(obj_b)->ifindex >= 0
&& (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
? (nm_platform_ip4_route_cmp(&obj_a->ip4_route,
&obj_b->ip4_route,