diff options
Diffstat (limited to 'src/platform/tests/test-route.c')
| -rw-r--r-- | src/platform/tests/test-route.c | 1926 |
1 files changed, 0 insertions, 1926 deletions
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c deleted file mode 100644 index 1305e586..00000000 --- a/src/platform/tests/test-route.c +++ /dev/null @@ -1,1926 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2016 - 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <linux/rtnetlink.h> -#include <linux/fib_rules.h> - -#include "nm-core-utils.h" -#include "platform/nm-platform-utils.h" -#include "platform/nmp-rules-manager.h" - -#include "test-common.h" - -#define DEVICE_IFINDEX NMTSTP_ENV1_IFINDEX -#define EX NMTSTP_ENV1_EX - -static void -_wait_for_ipv4_addr_device_route(NMPlatform *platform, - gint64 timeout_msec, - int ifindex, - in_addr_t addr, - guint8 plen) -{ - /* Wait that the addresses gets a device-route. After adding a address, - * the device route is not added immediately. It takes a moment... */ - - addr = nm_utils_ip4_address_clear_host_address(addr, plen); - NMTST_WAIT_ASSERT(400, { - NMDedupMultiIter iter; - NMPLookup lookup; - const NMPObject *o; - - nmp_cache_iter_for_each ( - &iter, - nm_platform_lookup(platform, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex)), - &o) { - const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE(o); - - if (r->plen == plen && addr == nm_utils_ip4_address_clear_host_address(r->network, plen) - && r->metric == 0 && r->scope_inv == nm_platform_route_scope_inv(RT_SCOPE_LINK) - && r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) - return; - } - nmtstp_assert_wait_for_signal(platform, - (nmtst_wait_end_us - g_get_monotonic_time()) / 1000); - }); -} - -static void -_wait_for_ipv6_addr_non_tentative(NMPlatform * platform, - gint64 timeout_msec, - int ifindex, - guint addr_n, - const struct in6_addr *addrs) -{ - guint i; - - /* Wait that the addresses become non-tentative. Dummy interfaces are NOARP - * and thus don't do DAD, but the kernel sets the address as tentative for a - * small amount of time, which prevents the immediate addition of the route - * with RTA_PREFSRC */ - - NMTST_WAIT_ASSERT(timeout_msec, { - gboolean should_wait = FALSE; - const NMPlatformIP6Address *plt_addr; - - for (i = 0; i < addr_n; i++) { - plt_addr = nm_platform_ip6_address_get(platform, ifindex, &addrs[i]); - if (!plt_addr || NM_FLAGS_HAS(plt_addr->n_ifa_flags, IFA_F_TENTATIVE)) { - should_wait = TRUE; - break; - } - } - if (!should_wait) - return; - nmtstp_assert_wait_for_signal(platform, - (nmtst_wait_end_us - g_get_monotonic_time()) / 1000); - }); -} - -static void -ip4_route_callback(NMPlatform * platform, - int obj_type_i, - int ifindex, - const NMPlatformIP4Route *received, - int change_type_i, - SignalData * data) -{ - const NMPObjectType obj_type = obj_type_i; - const NMPlatformSignalChangeType change_type = change_type_i; - NMPObject o_id; - nm_auto_nmpobj NMPObject *o_id_p = nmp_object_new(NMP_OBJECT_TYPE_IP4_ROUTE, NULL); - - g_assert_cmpint(obj_type, ==, NMP_OBJECT_TYPE_IP4_ROUTE); - g_assert(received); - g_assert_cmpint(received->ifindex, ==, ifindex); - g_assert(data && data->name); - g_assert_cmpstr(data->name, ==, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED); - - /* run code for initializing the ID only */ - nmp_object_stackinit_id(&o_id, NMP_OBJECT_UP_CAST(received)); - nmp_object_copy(o_id_p, NMP_OBJECT_UP_CAST(received), TRUE); - nmp_object_copy(o_id_p, NMP_OBJECT_UP_CAST(received), FALSE); - - if (data->ifindex && data->ifindex != received->ifindex) - return; - if (data->change_type != change_type) - return; - - if (data->loop) - g_main_loop_quit(data->loop); - - data->received_count++; - _LOGD("Received signal '%s' %dth time.", data->name, data->received_count); -} - -static void -ip6_route_callback(NMPlatform * platform, - int obj_type_i, - int ifindex, - const NMPlatformIP6Route *received, - int change_type_i, - SignalData * data) -{ - const NMPObjectType obj_type = obj_type_i; - const NMPlatformSignalChangeType change_type = change_type_i; - NMPObject o_id; - nm_auto_nmpobj NMPObject *o_id_p = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - - g_assert_cmpint(obj_type, ==, NMP_OBJECT_TYPE_IP6_ROUTE); - g_assert(received); - g_assert_cmpint(received->ifindex, ==, ifindex); - g_assert(data && data->name); - g_assert_cmpstr(data->name, ==, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED); - - /* run code for initializing the ID only */ - nmp_object_stackinit_id(&o_id, NMP_OBJECT_UP_CAST(received)); - nmp_object_copy(o_id_p, NMP_OBJECT_UP_CAST(received), TRUE); - nmp_object_copy(o_id_p, NMP_OBJECT_UP_CAST(received), FALSE); - - if (data->ifindex && data->ifindex != received->ifindex) - return; - if (data->change_type != change_type) - return; - - if (data->loop) - g_main_loop_quit(data->loop); - - data->received_count++; - _LOGD("Received signal '%s' %dth time.", data->name, data->received_count); -} - -static void -test_ip4_route_metric0(void) -{ - int ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - SignalData *route_added = add_signal(NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_ADDED, - ip4_route_callback); - SignalData *route_changed = add_signal(NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_CHANGED, - ip4_route_callback); - SignalData *route_removed = add_signal(NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_REMOVED, - ip4_route_callback); - in_addr_t network = - nmtst_inet4_from_string("192.0.2.5"); /* from 192.0.2.0/24 (TEST-NET-1) (rfc5737) */ - int plen = 32; - int metric = 22987; - int mss = 1000; - - /* No routes initially */ - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, 0, 0); - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, metric, 0); - - /* add the first route */ - nmtstp_ip4_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - network, - plen, - INADDR_ANY, - 0, - metric, - mss); - accept_signal(route_added); - - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, 0, 0); - nmtstp_assert_ip4_route_exists(NULL, 1, DEVICE_NAME, network, plen, metric, 0); - - /* Deleting route with metric 0 does nothing */ - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, network, plen, 0)); - ensure_no_signal(route_removed); - - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, 0, 0); - nmtstp_assert_ip4_route_exists(NULL, 1, DEVICE_NAME, network, plen, metric, 0); - - /* add the second route */ - nmtstp_ip4_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - network, - plen, - INADDR_ANY, - 0, - 0, - mss); - accept_signal(route_added); - - nmtstp_assert_ip4_route_exists(NULL, 1, DEVICE_NAME, network, plen, 0, 0); - nmtstp_assert_ip4_route_exists(NULL, 1, DEVICE_NAME, network, plen, metric, 0); - - /* Delete route with metric 0 */ - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, network, plen, 0)); - accept_signal(route_removed); - - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, 0, 0); - nmtstp_assert_ip4_route_exists(NULL, 1, DEVICE_NAME, network, plen, metric, 0); - - /* Delete route with metric 0 again (we expect nothing to happen) */ - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, network, plen, 0)); - ensure_no_signal(route_removed); - - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, 0, 0); - nmtstp_assert_ip4_route_exists(NULL, 1, DEVICE_NAME, network, plen, metric, 0); - - /* Delete the other route */ - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, network, plen, metric)); - accept_signal(route_removed); - - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, 0, 0); - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, metric, 0); - - free_signal(route_added); - free_signal(route_changed); - free_signal(route_removed); -} - -static void -test_ip4_route(void) -{ - int ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - SignalData * route_added = add_signal(NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_ADDED, - ip4_route_callback); - SignalData * route_changed = add_signal(NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_CHANGED, - ip4_route_callback); - SignalData * route_removed = add_signal(NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_REMOVED, - ip4_route_callback); - GPtrArray * routes; - NMPlatformIP4Route rts[3]; - in_addr_t network; - guint8 plen = 24; - in_addr_t gateway; - /* Choose a high metric so that we hopefully don't conflict. */ - int metric = 22986; - int mss = 1000; - - inet_pton(AF_INET, "192.0.3.0", &network); - inet_pton(AF_INET, "198.51.100.1", &gateway); - - /* Add route to gateway */ - nmtstp_ip4_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - gateway, - 32, - INADDR_ANY, - 0, - metric, - mss); - accept_signal(route_added); - - /* Add route */ - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, metric, 0); - nmtstp_ip4_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - network, - plen, - gateway, - 0, - metric, - mss); - nmtstp_assert_ip4_route_exists(NULL, 1, DEVICE_NAME, network, plen, metric, 0); - accept_signal(route_added); - - /* Add route again */ - nmtstp_ip4_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - network, - plen, - gateway, - 0, - metric, - mss); - accept_signals(route_changed, 0, 1); - - /* Add default route */ - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, 0, 0, metric, 0); - nmtstp_ip4_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - 0, - 0, - gateway, - 0, - metric, - mss); - nmtstp_assert_ip4_route_exists(NULL, 1, DEVICE_NAME, 0, 0, metric, 0); - accept_signal(route_added); - - /* Add default route again */ - nmtstp_ip4_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - 0, - 0, - gateway, - 0, - metric, - mss); - accept_signals(route_changed, 0, 1); - - /* Test route listing */ - routes = nmtstp_ip4_route_get_all(NM_PLATFORM_GET, ifindex); - memset(rts, 0, sizeof(rts)); - rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[0].network = gateway; - rts[0].plen = 32; - rts[0].ifindex = ifindex; - rts[0].gateway = INADDR_ANY; - rts[0].metric = metric; - rts[0].mss = mss; - rts[0].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_LINK); - rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[1].network = network; - rts[1].plen = plen; - rts[1].ifindex = ifindex; - rts[1].gateway = gateway; - rts[1].metric = metric; - rts[1].mss = mss; - rts[1].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE); - rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[2].network = 0; - rts[2].plen = 0; - rts[2].ifindex = ifindex; - rts[2].gateway = gateway; - rts[2].metric = metric; - rts[2].mss = mss; - rts[2].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE); - g_assert_cmpint(routes->len, ==, 3); - nmtst_platform_ip4_routes_equal_aptr((const NMPObject *const *) routes->pdata, - rts, - routes->len, - TRUE); - g_ptr_array_unref(routes); - - /* Remove route */ - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, network, plen, metric)); - nmtstp_assert_ip4_route_exists(NULL, 0, DEVICE_NAME, network, plen, metric, 0); - accept_signal(route_removed); - - /* Remove route again */ - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, network, plen, metric)); - - /* Remove default route */ - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, 0, 0, metric)); - accept_signal(route_removed); - - /* Remove route to gateway */ - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, gateway, 32, metric)); - accept_signal(route_removed); - - free_signal(route_added); - free_signal(route_changed); - free_signal(route_removed); -} - -static void -test_ip6_route(void) -{ - int ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - SignalData * route_added = add_signal(NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_ADDED, - ip6_route_callback); - SignalData * route_changed = add_signal(NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_CHANGED, - ip6_route_callback); - SignalData * route_removed = add_signal(NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, - NM_PLATFORM_SIGNAL_REMOVED, - ip6_route_callback); - GPtrArray * routes; - NMPlatformIP6Route rts[3]; - struct in6_addr network; - guint8 plen = 64; - struct in6_addr gateway, pref_src; - /* Choose a high metric so that we hopefully don't conflict. */ - const int metric = 22987; - int mss = 1000; - - inet_pton(AF_INET6, "2001:db8:a:b:0:0:0:0", &network); - inet_pton(AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway); - inet_pton(AF_INET6, "::42", &pref_src); - - g_assert(nm_platform_ip6_address_add(NM_PLATFORM_GET, - ifindex, - pref_src, - 128, - in6addr_any, - NM_PLATFORM_LIFETIME_PERMANENT, - NM_PLATFORM_LIFETIME_PERMANENT, - 0)); - accept_signals(route_added, 0, 3); - - _wait_for_ipv6_addr_non_tentative(NM_PLATFORM_GET, 200, ifindex, 1, &pref_src); - - /* Add route to gateway */ - nmtstp_ip6_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - gateway, - 128, - in6addr_any, - in6addr_any, - metric, - mss); - accept_signals(route_added, 0, 3); - - /* Add route */ - g_assert(!nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, &network, plen, metric, NULL, 0)); - nmtstp_ip6_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - network, - plen, - gateway, - pref_src, - metric, - mss); - g_assert(nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, &network, plen, metric, NULL, 0)); - accept_signal(route_added); - - /* Add route again */ - nmtstp_ip6_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - network, - plen, - gateway, - pref_src, - metric, - mss); - accept_signals(route_changed, 0, 1); - - /* Add default route */ - g_assert(!nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, &in6addr_any, 0, metric, NULL, 0)); - nmtstp_ip6_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - in6addr_any, - 0, - gateway, - in6addr_any, - metric, - mss); - g_assert(nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, &in6addr_any, 0, metric, NULL, 0)); - accept_signal(route_added); - - /* Add default route again */ - nmtstp_ip6_route_add(NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - in6addr_any, - 0, - gateway, - in6addr_any, - metric, - mss); - accept_signals(route_changed, 0, 1); - - /* Test route listing */ - routes = nmtstp_ip6_route_get_all(NM_PLATFORM_GET, ifindex); - memset(rts, 0, sizeof(rts)); - rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[0].network = gateway; - rts[0].plen = 128; - rts[0].ifindex = ifindex; - rts[0].gateway = in6addr_any; - rts[0].pref_src = in6addr_any; - rts[0].metric = metric; - rts[0].mss = mss; - rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[1].network = network; - rts[1].plen = plen; - rts[1].ifindex = ifindex; - rts[1].gateway = gateway; - rts[1].pref_src = pref_src; - rts[1].metric = metric; - rts[1].mss = mss; - rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[2].network = in6addr_any; - rts[2].plen = 0; - rts[2].ifindex = ifindex; - rts[2].gateway = gateway; - rts[2].pref_src = in6addr_any; - rts[2].metric = metric; - rts[2].mss = mss; - g_assert_cmpint(routes->len, ==, 3); - nmtst_platform_ip6_routes_equal_aptr((const NMPObject *const *) routes->pdata, - rts, - routes->len, - TRUE); - g_ptr_array_unref(routes); - - /* Remove route */ - g_assert(nmtstp_platform_ip6_route_delete(NM_PLATFORM_GET, ifindex, network, plen, metric)); - g_assert(!nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, &network, plen, metric, NULL, 0)); - accept_signal(route_removed); - - /* Remove route again */ - g_assert(nmtstp_platform_ip6_route_delete(NM_PLATFORM_GET, ifindex, network, plen, metric)); - - /* Remove default route */ - g_assert(nmtstp_platform_ip6_route_delete(NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); - accept_signal(route_removed); - - /* Remove route to gateway */ - g_assert(nmtstp_platform_ip6_route_delete(NM_PLATFORM_GET, ifindex, gateway, 128, metric)); - accept_signal(route_removed); - - free_signal(route_added); - free_signal(route_changed); - free_signal(route_removed); -} - -/*****************************************************************************/ - -static void -test_ip4_route_get(void) -{ - int ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - in_addr_t a; - int result; - nm_auto_nmpobj NMPObject *route = NULL; - const NMPlatformIP4Route *r; - - nmtstp_run_command_check("ip route add 1.2.3.0/24 dev %s", DEVICE_NAME); - - NMTST_WAIT_ASSERT(100, { - nmtstp_wait_for_signal(NM_PLATFORM_GET, 10); - if (nmtstp_ip4_route_get(NM_PLATFORM_GET, - ifindex, - nmtst_inet4_from_string("1.2.3.0"), - 24, - 0, - 0)) - break; - }); - - a = nmtst_inet4_from_string("1.2.3.1"); - result = nm_platform_ip_route_get(NM_PLATFORM_GET, - AF_INET, - &a, - nmtst_get_rand_uint32() % 2 ? 0 : ifindex, - &route); - - g_assert(NMTST_NM_ERR_SUCCESS(result)); - g_assert(NMP_OBJECT_GET_TYPE(route) == NMP_OBJECT_TYPE_IP4_ROUTE); - g_assert(!NMP_OBJECT_IS_STACKINIT(route)); - g_assert(route->parent._ref_count == 1); - r = NMP_OBJECT_CAST_IP4_ROUTE(route); - g_assert(NM_FLAGS_HAS(r->r_rtm_flags, RTM_F_CLONED)); - g_assert(r->ifindex == ifindex); - g_assert(r->network == a); - g_assert(r->plen == 32); - - nmtstp_run_command_check("ip route flush dev %s", DEVICE_NAME); - - nmtstp_wait_for_signal(NM_PLATFORM_GET, 50); -} - -static void -test_ip4_zero_gateway(void) -{ - int ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - - nmtstp_run_command_check("ip route add 1.2.3.1/32 via 0.0.0.0 dev %s", DEVICE_NAME); - nmtstp_run_command_check("ip route add 1.2.3.2/32 dev %s", DEVICE_NAME); - - NMTST_WAIT_ASSERT(100, { - nmtstp_wait_for_signal(NM_PLATFORM_GET, 10); - if (nmtstp_ip4_route_get(NM_PLATFORM_GET, - ifindex, - nmtst_inet4_from_string("1.2.3.1"), - 32, - 0, - 0) - && nmtstp_ip4_route_get(NM_PLATFORM_GET, - ifindex, - nmtst_inet4_from_string("1.2.3.2"), - 32, - 0, - 0)) - break; - }); - - nmtstp_run_command_check("ip route flush dev %s", DEVICE_NAME); - - nmtstp_wait_for_signal(NM_PLATFORM_GET, 50); -} - -static void -test_ip4_route_options(gconstpointer test_data) -{ - const int TEST_IDX = GPOINTER_TO_INT(test_data); - const int IFINDEX = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - gs_unref_ptrarray GPtrArray *routes = NULL; -#define RTS_MAX 3 - NMPlatformIP4Route rts_add[RTS_MAX] = {}; - NMPlatformIP4Route rts_cmp[RTS_MAX] = {}; - NMPlatformIP4Address addr[1] = {}; - guint i; - guint rts_n = 0; - guint addr_n = 0; - - switch (TEST_IDX) { - case 1: - rts_add[rts_n++] = ((NMPlatformIP4Route){ - .ifindex = IFINDEX, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = nmtst_inet4_from_string("172.16.1.0"), - .plen = 24, - .metric = 20, - .tos = 0x28, - .window = 10000, - .cwnd = 16, - .initcwnd = 30, - .initrwnd = 50, - .mtu = 1350, - .lock_cwnd = TRUE, - }); - break; - case 2: - addr[addr_n++] = ((NMPlatformIP4Address){ - .ifindex = IFINDEX, - .address = nmtst_inet4_from_string("172.16.1.5"), - .peer_address = nmtst_inet4_from_string("172.16.1.5"), - .plen = 24, - .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, - .preferred = NM_PLATFORM_LIFETIME_PERMANENT, - .n_ifa_flags = 0, - }); - rts_add[rts_n++] = ((NMPlatformIP4Route){ - .ifindex = IFINDEX, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = nmtst_inet4_from_string("172.17.1.0"), - .gateway = nmtst_inet4_from_string("172.16.1.1"), - .plen = 24, - .metric = 20, - }); - rts_add[rts_n++] = ((NMPlatformIP4Route){ - .ifindex = IFINDEX, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = nmtst_inet4_from_string("172.19.1.0"), - .gateway = nmtst_inet4_from_string("172.18.1.1"), - .r_rtm_flags = RTNH_F_ONLINK, - .plen = 24, - .metric = 20, - }); - break; - default: - g_assert_not_reached(); - break; - } - g_assert(rts_n <= G_N_ELEMENTS(rts_add)); - g_assert(addr_n <= G_N_ELEMENTS(addr)); - - for (i = 0; i < addr_n; i++) { - const NMPlatformIP4Address *a = &addr[i]; - - g_assert(a->ifindex == IFINDEX); - g_assert(nm_platform_ip4_address_add( - NM_PLATFORM_GET, - a->ifindex, - a->address, - a->plen, - a->peer_address, - nm_platform_ip4_broadcast_address_create(a->address, a->plen), - a->lifetime, - a->preferred, - a->n_ifa_flags, - a->label)); - if (a->peer_address == a->address) - _wait_for_ipv4_addr_device_route(NM_PLATFORM_GET, 200, a->ifindex, a->address, a->plen); - } - - for (i = 0; i < rts_n; i++) - g_assert(NMTST_NM_ERR_SUCCESS( - nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]))); - - for (i = 0; i < rts_n; i++) { - rts_cmp[i] = rts_add[i]; - nm_platform_ip_route_normalize(AF_INET, NM_PLATFORM_IP_ROUTE_CAST(&rts_cmp[i])); - } - - routes = nmtstp_ip4_route_get_all(NM_PLATFORM_GET, IFINDEX); - g_assert_cmpint(routes->len, ==, rts_n); - nmtst_platform_ip4_routes_equal_aptr((const NMPObject *const *) routes->pdata, - rts_cmp, - routes->len, - TRUE); - - for (i = 0; i < rts_n; i++) { - g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, - IFINDEX, - rts_add[i].network, - rts_add[i].plen, - rts_add[i].metric)); - } -#undef RTS_MAX -} - -static void -test_ip6_route_get(void) -{ - int ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - const struct in6_addr *a; - int result; - nm_auto_nmpobj NMPObject *route = NULL; - const NMPlatformIP6Route *r; - - nmtstp_run_command_check("ip -6 route add fd01:abcd::/64 via fe80::99 dev %s", DEVICE_NAME); - - NMTST_WAIT_ASSERT(100, { - nmtstp_wait_for_signal(NM_PLATFORM_GET, 10); - if (nmtstp_ip6_route_get(NM_PLATFORM_GET, - ifindex, - nmtst_inet6_from_string("fd01:abcd::"), - 64, - NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, - NULL, - 0)) - break; - }); - - a = nmtst_inet6_from_string("fd01:abcd::42"); - result = nm_platform_ip_route_get(NM_PLATFORM_GET, - AF_INET6, - a, - nmtst_get_rand_uint32() % 2 ? 0 : ifindex, - &route); - - g_assert(NMTST_NM_ERR_SUCCESS(result)); - g_assert(NMP_OBJECT_GET_TYPE(route) == NMP_OBJECT_TYPE_IP6_ROUTE); - g_assert(!NMP_OBJECT_IS_STACKINIT(route)); - g_assert(route->parent._ref_count == 1); - r = NMP_OBJECT_CAST_IP6_ROUTE(route); - g_assert(r->ifindex == ifindex); - nmtst_assert_ip6_address(&r->network, "fd01:abcd::42"); - g_assert_cmpint(r->plen, ==, 128); - nmtst_assert_ip6_address(&r->gateway, "fe80::99"); - - nmtstp_run_command_check("ip -6 route flush dev %s", DEVICE_NAME); - - nmtstp_wait_for_signal(NM_PLATFORM_GET, 50); -} - -static void -test_ip6_route_options(gconstpointer test_data) -{ - const int TEST_IDX = GPOINTER_TO_INT(test_data); - const int IFINDEX = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - gs_unref_ptrarray GPtrArray *routes = NULL; -#define RTS_MAX 3 - NMPlatformIP6Route rts_add[RTS_MAX] = {}; - NMPlatformIP6Route rts_cmp[RTS_MAX] = {}; - NMPlatformIP6Address addr[1] = {}; - struct in6_addr addr_in6[G_N_ELEMENTS(addr)] = {}; - guint rts_n = 0; - guint addr_n = 0; - guint i; - - switch (TEST_IDX) { - case 1: - rts_add[rts_n++] = ((NMPlatformIP6Route){ - .ifindex = IFINDEX, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = *nmtst_inet6_from_string("2001:db8:a:b:0:0:0:0"), - .plen = 64, - .gateway = in6addr_any, - .metric = 1024, - .window = 20000, - .cwnd = 8, - .initcwnd = 22, - .initrwnd = 33, - .mtu = 1300, - .lock_mtu = TRUE, - }); - break; - case 2: - addr[addr_n++] = ((NMPlatformIP6Address){ - .ifindex = IFINDEX, - .address = *nmtst_inet6_from_string("2000::2"), - .plen = 128, - .peer_address = in6addr_any, - .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, - .preferred = NM_PLATFORM_LIFETIME_PERMANENT, - .n_ifa_flags = 0, - }); - rts_add[rts_n++] = ((NMPlatformIP6Route){ - .ifindex = IFINDEX, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = *nmtst_inet6_from_string("1010::1"), - .plen = 128, - .gateway = in6addr_any, - .metric = 256, - .pref_src = *nmtst_inet6_from_string("2000::2"), - }); - break; - case 3: - addr[addr_n++] = ((NMPlatformIP6Address){ - .ifindex = IFINDEX, - .address = *nmtst_inet6_from_string("2001:db8:8086::5"), - .plen = 128, - .peer_address = in6addr_any, - .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, - .preferred = NM_PLATFORM_LIFETIME_PERMANENT, - .n_ifa_flags = 0, - }); - rts_add[rts_n++] = ((NMPlatformIP6Route){ - .ifindex = IFINDEX, - .rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER), - .network = *nmtst_inet6_from_string("2001:db8:8086::"), - .plen = 110, - .metric = 10021, - .mss = 0, - }); - rts_add[rts_n++] = ((NMPlatformIP6Route){ - .ifindex = IFINDEX, - .rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER), - .network = *nmtst_inet6_from_string("2001:db8:abad:c0de::"), - .plen = 64, - .gateway = *nmtst_inet6_from_string("2001:db8:8086::1"), - .metric = 21, - .mss = 0, - }); - break; - default: - g_assert_not_reached(); - } - g_assert(rts_n <= G_N_ELEMENTS(rts_add)); - g_assert(addr_n <= G_N_ELEMENTS(addr)); - - for (i = 0; i < addr_n; i++) { - g_assert(addr[i].ifindex == IFINDEX); - addr_in6[i] = addr[i].address; - g_assert(nm_platform_ip6_address_add(NM_PLATFORM_GET, - IFINDEX, - addr[i].address, - addr[i].plen, - addr[i].peer_address, - addr[i].lifetime, - addr[i].preferred, - addr[i].n_ifa_flags)); - } - _wait_for_ipv6_addr_non_tentative(NM_PLATFORM_GET, 400, IFINDEX, addr_n, addr_in6); - - for (i = 0; i < rts_n; i++) - g_assert(NMTST_NM_ERR_SUCCESS( - nm_platform_ip6_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]))); - - for (i = 0; i < rts_n; i++) { - rts_cmp[i] = rts_add[i]; - nm_platform_ip_route_normalize(AF_INET6, NM_PLATFORM_IP_ROUTE_CAST(&rts_cmp[i])); - } - - routes = nmtstp_ip6_route_get_all(NM_PLATFORM_GET, IFINDEX); - g_assert_cmpint(routes->len, ==, rts_n); - nmtst_platform_ip6_routes_equal_aptr((const NMPObject *const *) routes->pdata, - rts_cmp, - routes->len, - TRUE); - - for (i = 0; i < rts_n; i++) { - g_assert(nmtstp_platform_ip6_route_delete(NM_PLATFORM_GET, - IFINDEX, - rts_add[i].network, - rts_add[i].plen, - rts_add[i].metric)); - } - - for (i = 0; i < addr_n; i++) { - nmtstp_ip6_address_del(NM_PLATFORM_GET, EX, IFINDEX, rts_add[i].network, rts_add[i].plen); - } -#undef RTS_MAX -} - -/*****************************************************************************/ - -static void -test_ip(gconstpointer test_data) -{ - const int TEST_IDX = GPOINTER_TO_INT(test_data); - const int IFINDEX = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - guint i, j, k; - const NMPlatformLink *l; - char ifname[IFNAMSIZ]; - char ifname2[IFNAMSIZ]; - char s1[NM_UTILS_INET_ADDRSTRLEN]; - NMPlatform * platform = NM_PLATFORM_GET; - const int EX_ = -1; - struct { - int ifindex; - } iface_data[10] = { - {0}, - }; - int order_idx[G_N_ELEMENTS(iface_data)] = {0}; - guint order_len; - guint try; - - for (i = 0; i < G_N_ELEMENTS(iface_data); i++) { - nm_sprintf_buf(ifname, "v%02u", i); - nm_sprintf_buf(ifname2, "w%02u", i); - - g_assert(!nm_platform_link_get_by_ifname(platform, ifname)); - g_assert(!nm_platform_link_get_by_ifname(platform, ifname2)); - l = nmtstp_link_veth_add(platform, EX_, ifname, ifname2); - iface_data[i].ifindex = l->ifindex; - - nmtstp_link_set_updown(platform, EX_, iface_data[i].ifindex, TRUE); - nmtstp_link_set_updown(platform, - EX_, - nmtstp_link_get(platform, -1, ifname2)->ifindex, - TRUE); - - nm_sprintf_buf(s1, "192.168.7.%d", 100 + i); - nmtstp_ip4_address_add(platform, - EX_, - iface_data[i].ifindex, - nmtst_inet4_from_string(s1), - 24, - nmtst_inet4_from_string(s1), - 3600, - 3600, - 0, - NULL); - } - - order_len = 0; - for (try = 0; try < 5 * G_N_ELEMENTS(order_idx); try++) { - NMPObject o; - NMPlatformIP4Route * r; - guint idx; - const NMDedupMultiHeadEntry *head_entry; - NMPLookup lookup; - - nmp_object_stackinit(&o, NMP_OBJECT_TYPE_IP4_ROUTE, NULL); - r = NMP_OBJECT_CAST_IP4_ROUTE(&o); - r->network = nmtst_inet4_from_string("192.168.9.0"); - r->plen = 24; - r->metric = 109; - - if (order_len == 0 - || (order_len < G_N_ELEMENTS(order_idx) && nmtst_get_rand_uint32() % 2)) { -again_find_idx: - idx = nmtst_get_rand_uint32() % G_N_ELEMENTS(iface_data); - for (i = 0; i < order_len; i++) { - if (order_idx[i] == idx) - goto again_find_idx; - } - order_idx[order_len++] = idx; - - r->ifindex = iface_data[idx].ifindex; - g_assert( - NMTST_NM_ERR_SUCCESS(nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_APPEND, r))); - } else { - i = nmtst_get_rand_uint32() % order_len; - idx = order_idx[i]; - for (i++; i < order_len; i++) - order_idx[i - 1] = order_idx[i]; - order_len--; - - r->ifindex = iface_data[idx].ifindex; - g_assert(nm_platform_object_delete(platform, &o)); - } - - head_entry = - nm_platform_lookup(platform, - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_IP4_ROUTE)); - for (j = 0; j < G_N_ELEMENTS(iface_data); j++) { - gboolean has; - NMDedupMultiIter iter; - const NMPObject *o_cached; - - has = FALSE; - for (k = 0; k < order_len; k++) { - if (order_idx[k] == j) { - g_assert(!has); - has = TRUE; - } - } - - nmp_cache_iter_for_each (&iter, head_entry, &o_cached) { - const NMPlatformIP4Route *r_cached = NMP_OBJECT_CAST_IP4_ROUTE(o_cached); - - if (r_cached->ifindex != iface_data[j].ifindex || r_cached->metric != 109) - continue; - - g_assert(has); - has = FALSE; - } - g_assert(!has); - } - } - - for (i = 0; i < G_N_ELEMENTS(iface_data); i++) - g_assert(nm_platform_link_delete(platform, iface_data[i].ifindex)); - - (void) TEST_IDX; - (void) IFINDEX; -} - -/*****************************************************************************/ - -#define FRA_SUPPRESS_IFGROUP 13 -#define FRA_SUPPRESS_PREFIXLEN 14 -#define FRA_L3MDEV 19 -#define FRA_UID_RANGE 20 -#define FRA_PROTOCOL 21 -#define FRA_IP_PROTO 22 -#define FRA_SPORT_RANGE 23 -#define FRA_DPORT_RANGE 24 - -static const NMPObject * -_rule_find_by_priority(NMPlatform *platform, guint32 priority) -{ - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter iter; - const NMPObject * o; - const NMPObject * obj = NULL; - NMPLookup lookup; - - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); - head_entry = nm_platform_lookup(platform, &lookup); - nmp_cache_iter_for_each (&iter, head_entry, &o) { - if (NMP_OBJECT_CAST_ROUTING_RULE(o)->priority != priority) - continue; - g_assert(!obj); - obj = o; - } - return obj; -} - -static const NMPObject * -_rule_check_kernel_support_one(NMPlatform *platform, const NMPlatformRoutingRule *rr) -{ - nm_auto_nmpobj const NMPObject *obj = NULL; - int r; - - g_assert(!_rule_find_by_priority(platform, rr->priority)); - - r = nm_platform_routing_rule_add(platform, NMP_NLM_FLAG_ADD, rr); - g_assert_cmpint(r, ==, 0); - - obj = nmp_object_ref(_rule_find_by_priority(platform, rr->priority)); - g_assert(obj); - - r = nm_platform_object_delete(platform, obj); - g_assert_cmpint(r, ==, TRUE); - - g_assert(!_rule_find_by_priority(platform, rr->priority)); - - return g_steal_pointer(&obj); -} - -static gboolean -_rule_check_kernel_support(NMPlatform *platform, int attribute) -{ - static int support[] = { - [FRA_SUPPRESS_IFGROUP] = 0, - [FRA_SUPPRESS_PREFIXLEN] = 0, - [FRA_L3MDEV] = 0, - [FRA_UID_RANGE] = 0, - [FRA_PROTOCOL] = 0, - [FRA_IP_PROTO] = 0, - [FRA_SPORT_RANGE] = 0, - [FRA_DPORT_RANGE] = 0, - }; - const guint32 PROBE_PRORITY = 12033; - gboolean sup; - int i; - - g_assert(NM_IS_PLATFORM(platform)); - - if (attribute == -1) { - for (i = 0; i < G_N_ELEMENTS(support); i++) { - if (support[i] < 0) { - /* indicate that some test was skipped. */ - return FALSE; - } - } - return TRUE; - } - - g_assert(attribute >= 0 && attribute < G_N_ELEMENTS(support)); - - if (support[attribute] != 0) - return support[attribute] >= 0; - - switch (attribute) { - case FRA_SUPPRESS_IFGROUP: - { - nm_auto_nmpobj const NMPObject *obj = NULL; - const NMPlatformRoutingRule rr = { - .addr_family = AF_INET, - .priority = PROBE_PRORITY, - .suppress_ifgroup_inverse = ~((guint32) 1245), - }; - - obj = _rule_check_kernel_support_one(platform, &rr); - - sup = NMP_OBJECT_CAST_ROUTING_RULE(obj)->suppress_prefixlen_inverse - == rr.suppress_ifgroup_inverse; - break; - } - case FRA_SUPPRESS_PREFIXLEN: - { - nm_auto_nmpobj const NMPObject *obj = NULL; - const NMPlatformRoutingRule rr = { - .addr_family = AF_INET, - .priority = PROBE_PRORITY, - .suppress_prefixlen_inverse = ~((guint32) 1245), - }; - - obj = _rule_check_kernel_support_one(platform, &rr); - - sup = NMP_OBJECT_CAST_ROUTING_RULE(obj)->suppress_prefixlen_inverse - == rr.suppress_prefixlen_inverse; - break; - } - case FRA_L3MDEV: - { - nm_auto_nmpobj const NMPObject *obj = NULL; - const NMPlatformRoutingRule rr = { - .addr_family = AF_INET, - .priority = PROBE_PRORITY, - .l3mdev = TRUE, - }; - - obj = _rule_check_kernel_support_one(platform, &rr); - - sup = NMP_OBJECT_CAST_ROUTING_RULE(obj)->l3mdev != 0; - break; - } - case FRA_UID_RANGE: - { - nm_auto_nmpobj const NMPObject *obj = NULL; - const NMPlatformRoutingRule rr = { - .addr_family = AF_INET, - .priority = PROBE_PRORITY, - .uid_range = - { - .start = 0, - .end = 0, - }, - .uid_range_has = TRUE, - }; - - obj = _rule_check_kernel_support_one(platform, &rr); - - sup = NMP_OBJECT_CAST_ROUTING_RULE(obj)->uid_range_has; - break; - } - case FRA_PROTOCOL: - { - nm_auto_nmpobj const NMPObject *obj = NULL; - const NMPlatformRoutingRule rr = { - .addr_family = AF_INET, - .priority = PROBE_PRORITY, - .protocol = 30, - }; - - obj = _rule_check_kernel_support_one(platform, &rr); - - sup = NMP_OBJECT_CAST_ROUTING_RULE(obj)->protocol == 30; - break; - } - case FRA_IP_PROTO: - { - nm_auto_nmpobj const NMPObject *obj = NULL; - const NMPlatformRoutingRule rr = { - .addr_family = AF_INET, - .priority = PROBE_PRORITY, - .ip_proto = 30, - }; - - obj = _rule_check_kernel_support_one(platform, &rr); - - sup = NMP_OBJECT_CAST_ROUTING_RULE(obj)->ip_proto == 30; - break; - } - case FRA_SPORT_RANGE: - case FRA_DPORT_RANGE: - /* these were added at the same time as FRA_IP_PROTO. */ - sup = _rule_check_kernel_support(platform, FRA_IP_PROTO); - break; - default: - g_assert_not_reached(); - return FALSE; - } - - support[attribute] = sup ? 1 : -1; - - _LOGD("kernel support for routing rule attribute #%d %s", - attribute, - sup ? "detected" : "not detected"); - return sup; -} - -static const NMPObject * -_platform_has_routing_rule(NMPlatform *platform, const NMPObject *obj) -{ - const NMPObject *o; - - g_assert(NM_IS_PLATFORM(platform)); - g_assert(NMP_OBJECT_IS_VALID(obj)); - g_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_ROUTING_RULE); - - o = nm_platform_lookup_obj(platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj); - if (o) - g_assert(nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(obj), - NMP_OBJECT_CAST_ROUTING_RULE(o), - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) - == 0); - - return o; -} - -static guint32 -_rr_rand_choose_u32(guint32 p) -{ - /* mostly, we just return zero. We want that each rule only has few - * fields set -- having most fields at zero. */ - if ((p % 10000u) < 7500u) - return 0; - - /* give 0xFFFFFFFFu extra probability. */ - if ((p % 10000u) < 8250u) - return 0xFFFFFFFFu; - - /* choose a small number. */ - if ((p % 10000u) < 9125u) - return (~p) % 10; - - /* finally, full random number. */ - return ~p; -} - -#define _rr_rand_choose_u8(p) ((guint8) _rr_rand_choose_u32((p))) - -static const NMPObject * -_rule_create_random(NMPlatform *platform) -{ - NMPObject * obj; - NMPlatformRoutingRule *rr; - guint32 p; - int addr_size; - guint i; - char saddr[NM_UTILS_INET_ADDRSTRLEN]; - static struct { - guint32 uid; - guint32 euid; - bool initialized; - } uids; - - if (G_UNLIKELY(!uids.initialized)) { - uids.uid = getuid(); - uids.euid = geteuid(); - uids.initialized = TRUE; - } - - obj = nmp_object_new(NMP_OBJECT_TYPE_ROUTING_RULE, NULL); - rr = NMP_OBJECT_CAST_ROUTING_RULE(obj); - - rr->addr_family = nmtst_rand_select(AF_INET, AF_INET6); - - addr_size = nm_utils_addr_family_to_size(rr->addr_family); - - p = nmtst_get_rand_uint32(); - if ((p % 1000u) < 50) - rr->priority = 10000 + ((~p) % 20u); - - p = nmtst_get_rand_uint32(); - if ((p % 1000u) < 40) - nm_sprintf_buf(rr->iifname, "t-iif-%u", (~p) % 20); - else if ((p % 1000u) < 80) - nm_sprintf_buf(rr->iifname, "%s", DEVICE_NAME); - - p = nmtst_get_rand_uint32(); - if ((p % 1000u) < 40) - nm_sprintf_buf(rr->oifname, "t-oif-%d", (~p) % 20); - else if ((p % 1000u) < 80) - nm_sprintf_buf(rr->oifname, "%s", DEVICE_NAME); - - for (i = 0; i < 2; i++) { - NMIPAddr *p_addr = i ? &rr->src : &rr->dst; - guint8 * p_len = i ? &rr->src_len : &rr->dst_len; - - p = nmtst_get_rand_uint32(); - if ((p % 1000u) < 100) { - /* if we set src_len/dst_len to zero, the src/dst is actually ignored. - * - * For fuzzying, still set the address. It shall have no further effect. - * */ - *p_len = (~p) % (addr_size * 8 + 1); - p = nmtst_get_rand_uint32(); - if ((p % 3u) == 0) { - if (rr->addr_family == AF_INET) - p_addr->addr4 = - nmtst_inet4_from_string(nm_sprintf_buf(saddr, "192.192.5.%u", (~p) % 256u)); - else - p_addr->addr6 = *nmtst_inet6_from_string( - nm_sprintf_buf(saddr, "1:2:3:4::f:%02x", (~p) % 256u)); - } else if ((p % 3u) == 1) - nmtst_rand_buf(NULL, p_addr, addr_size); - } - } - - p = nmtst_get_rand_uint32(); - if ((p % 1000u) < 50) - rr->tun_id = 10000 + ((~p) % 20); - -again_action: - p = nmtst_get_rand_uint32(); - if ((p % 1000u) < 500) - rr->action = FR_ACT_UNSPEC; - else if ((p % 1000u) < 750) - rr->action = (~p) % 12u; - else - rr->action = (~p) % 0x100u; - - rr->priority = _rr_rand_choose_u32(nmtst_get_rand_uint32()); - - if (rr->action == FR_ACT_GOTO && rr->priority == G_MAXINT32) - goto again_action; - - p = nmtst_get_rand_uint32(); - if ((p % 10000u) < 100) - rr->goto_target = rr->priority + 1; - else - rr->goto_target = _rr_rand_choose_u32(nmtst_get_rand_uint32()); - if (rr->action == FR_ACT_GOTO && rr->goto_target <= rr->priority) - goto again_action; - - p = nmtst_get_rand_uint32(); - if ((p % 1000u) < 25) { - if (_rule_check_kernel_support(platform, FRA_L3MDEV)) { - rr->l3mdev = TRUE; - rr->table = RT_TABLE_UNSPEC; - } - } - -again_table: - if (!rr->l3mdev) { - p = nmtst_get_rand_uint32(); - if ((p % 1000u) < 700) - rr->table = RT_TABLE_UNSPEC; - else if ((p % 1000u) < 850) - rr->table = RT_TABLE_MAIN; - else - rr->table = 10000 + ((~p) % 10); - if (rr->action == FR_ACT_TO_TBL && rr->table == RT_TABLE_UNSPEC) - goto again_table; - } - - rr->fwmark = _rr_rand_choose_u32(nmtst_get_rand_uint32()); - rr->fwmask = _rr_rand_choose_u32(nmtst_get_rand_uint32()); - - rr->flow = _rr_rand_choose_u32(nmtst_get_rand_uint32()); - - if (_rule_check_kernel_support(platform, FRA_PROTOCOL)) - rr->protocol = _rr_rand_choose_u8(nmtst_get_rand_uint32()); - -#define IPTOS_TOS_MASK 0x1E - -again_tos: - rr->tos = _rr_rand_choose_u8(nmtst_get_rand_uint32()); - if (rr->addr_family == AF_INET && rr->tos & ~IPTOS_TOS_MASK) - goto again_tos; - - if (_rule_check_kernel_support(platform, FRA_IP_PROTO)) - rr->ip_proto = _rr_rand_choose_u8(nmtst_get_rand_uint32()); - - if (_rule_check_kernel_support(platform, FRA_SUPPRESS_PREFIXLEN)) - rr->suppress_prefixlen_inverse = ~_rr_rand_choose_u32(nmtst_get_rand_uint32()); - - if (_rule_check_kernel_support(platform, FRA_SUPPRESS_IFGROUP)) - rr->suppress_ifgroup_inverse = ~_rr_rand_choose_u32(nmtst_get_rand_uint32()); - - if (_rule_check_kernel_support(platform, FRA_UID_RANGE)) { - p = nmtst_get_rand_uint32(); - rr->uid_range_has = (p % 10000u) < 200; - } - -again_uid_range: - rr->uid_range.start = nmtst_rand_select(0u, uids.uid, uids.euid); - rr->uid_range.end = nmtst_rand_select(0u, uids.uid, uids.euid); - if (rr->uid_range_has) { - if (rr->uid_range.end < rr->uid_range.start) - NM_SWAP(&rr->uid_range.start, &rr->uid_range.end); - if (rr->uid_range.start == ((guint32) -1) || rr->uid_range.end == ((guint32) -1)) - goto again_uid_range; - } - - for (i = 0; i < 2; i++) { - NMFibRulePortRange *range = i ? &rr->sport_range : &rr->dport_range; - int attribute = i ? FRA_SPORT_RANGE : FRA_DPORT_RANGE; - - if (!_rule_check_kernel_support(platform, attribute)) - continue; - - p = nmtst_get_rand_uint32(); - if ((p % 10000u) < 300) { - while (range->start == 0) { - p = p ^ nmtst_get_rand_uint32(); - range->start = nmtst_rand_select(1u, 0xFFFEu, ((p) % 0xFFFEu) + 1); - range->end = - nmtst_rand_select(1u, 0xFFFEu, ((p >> 16) % 0xFFFEu) + 1, range->start); - if (range->end < range->start) - NM_SWAP(&range->start, &range->end); - } - } - } - - p = nmtst_get_rand_uint32() % 1000u; - if (p < 100) - rr->flags |= FIB_RULE_INVERT; - - return obj; -} - -static gboolean -_rule_fuzzy_equal(const NMPObject *obj, const NMPObject *obj_comp, int op_type) -{ - const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE(obj); - NMPlatformRoutingRule rr_co = *NMP_OBJECT_CAST_ROUTING_RULE(obj_comp); - - switch (op_type) { - case RTM_NEWRULE: - /* when adding rules with RTM_NEWRULE, kernel checks whether an existing - * rule already exists and may fail with EEXIST. This check has issues - * and reject legitimate rules (rh#1686075). - * - * Work around that. */ - if (rr->src_len == 0) - rr_co.src_len = 0; - if (rr->dst_len == 0) - rr_co.dst_len = 0; - if (rr->flow == 0) - rr_co.flow = 0; - if (rr->tos == 0) - rr_co.tos = 0; - rr_co.suppress_prefixlen_inverse = rr->suppress_prefixlen_inverse; - rr_co.suppress_ifgroup_inverse = rr->suppress_ifgroup_inverse; - if (!NM_FLAGS_HAS(rr->flags, FIB_RULE_INVERT)) - rr_co.flags &= ~((guint32) FIB_RULE_INVERT); - else - rr_co.flags |= ((guint32) FIB_RULE_INVERT); - break; - case RTM_DELRULE: - /* when deleting a rule with RTM_DELRULE, kernel tries to find the - * candidate to delete. It might delete the wrong rule (rh#1685816). */ - if (rr->action == FR_ACT_UNSPEC) - rr_co.action = FR_ACT_UNSPEC; - if (rr->iifname[0] == '\0') - rr_co.iifname[0] = '\0'; - if (rr->oifname[0] == '\0') - rr_co.oifname[0] = '\0'; - if (rr->src_len == 0) - rr_co.src_len = 0; - if (rr->dst_len == 0) - rr_co.dst_len = 0; - if (rr->tun_id == 0) - rr_co.tun_id = 0; - if (rr->fwmark == 0) - rr_co.fwmark = 0; - if (rr->fwmask == 0) - rr_co.fwmask = 0; - if (rr->flow == 0) - rr_co.flow = 0; - if (rr->protocol == 0) - rr_co.protocol = 0; - if (rr->table == RT_TABLE_UNSPEC) - rr_co.table = RT_TABLE_UNSPEC; - if (rr->l3mdev == 0) - rr_co.l3mdev = 0; - if (rr->tos == 0) - rr_co.tos = 0; - if (rr->ip_proto == 0) - rr_co.ip_proto = 0; - rr_co.suppress_prefixlen_inverse = rr->suppress_prefixlen_inverse; - if (rr->suppress_ifgroup_inverse == 0) - rr_co.suppress_ifgroup_inverse = 0; - if (!rr->uid_range_has) - rr_co.uid_range_has = FALSE; - if (rr->sport_range.start == 0 && rr->sport_range.end == 0) { - rr_co.sport_range.start = 0; - rr_co.sport_range.end = 0; - } - if (rr->dport_range.start == 0 && rr->dport_range.end == 0) { - rr_co.dport_range.start = 0; - rr_co.dport_range.end = 0; - } - if (!NM_FLAGS_HAS(rr->flags, FIB_RULE_INVERT)) - rr_co.flags &= ~((guint32) FIB_RULE_INVERT); - else - rr_co.flags |= ((guint32) FIB_RULE_INVERT); - break; - default: - g_assert_not_reached(); - break; - } - - return nm_platform_routing_rule_cmp(rr, &rr_co, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0; -} - -static void -test_rule(gconstpointer test_data) -{ - const int TEST_IDX = GPOINTER_TO_INT(test_data); - const gboolean TEST_SYNC = (TEST_IDX == 4); - gs_unref_ptrarray GPtrArray *objs = NULL; - gs_unref_ptrarray GPtrArray *objs_initial = NULL; - NMPlatform * platform = NM_PLATFORM_GET; - guint i, j, n; - int r; - gboolean had_an_issue_exist = FALSE; - - nm_platform_process_events(platform); - - objs_initial = nmtstp_platform_routing_rules_get_all(platform, AF_UNSPEC); - g_assert(objs_initial); - g_assert_cmpint(objs_initial->len, ==, 5); - - nmtstp_run_command_check("ip rule add table 766"); - nm_platform_process_events(platform); - - for (i = 6; i > 0; i--) { - gs_unref_ptrarray GPtrArray *objs_extern = NULL; - const NMPObject * obj; - - objs_extern = nmtstp_platform_routing_rules_get_all(platform, AF_UNSPEC); - - g_assert(objs_extern); - g_assert_cmpint(objs_extern->len, ==, i); - - if (TEST_IDX != 1) - nmtst_rand_perm(NULL, objs_extern->pdata, NULL, sizeof(gpointer), objs_extern->len); - - obj = objs_extern->pdata[0]; - - r = nm_platform_object_delete(platform, obj); - g_assert_cmpint(r, ==, TRUE); - - g_assert(!_platform_has_routing_rule(platform, obj)); - } - - g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), ==, 0); - -#define RR(...) \ - nmp_object_new(NMP_OBJECT_TYPE_ROUTING_RULE, \ - (const NMPlatformObject *) &((NMPlatformRoutingRule){__VA_ARGS__})) - - objs = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); - - g_ptr_array_add(objs, RR(.addr_family = AF_INET, .priority = 10, )); - - g_ptr_array_add( - objs, - RR(.addr_family = AF_INET, .priority = 400, .action = FR_ACT_GOTO, .goto_target = 10000, )); - - g_ptr_array_add(objs, RR(.addr_family = AF_INET6, )); - - g_ptr_array_add(objs, - RR(.addr_family = AF_INET6, .action = FR_ACT_TO_TBL, .table = RT_TABLE_MAIN, )); - - g_ptr_array_add(objs, RR(.addr_family = AF_INET6, .priority = 30, )); - - g_ptr_array_add(objs, RR(.addr_family = AF_INET6, .priority = 50, .iifname = "t-iif-1", )); - - g_ptr_array_add(objs, RR(.addr_family = AF_INET6, .priority = 50, .iifname = "t-oif-1", )); - - g_ptr_array_add(objs, RR(.addr_family = AF_INET, .priority = 50, .iifname = "t-oif-2", )); - - g_ptr_array_add(objs, RR(.addr_family = AF_INET, .priority = 51, .iifname = DEVICE_NAME, )); - - if (TEST_IDX == 1) { - g_ptr_array_add(objs, RR(.addr_family = AF_INET, .table = 10000, )); - } - - if (TEST_IDX != 1) { - nmtst_rand_perm(NULL, objs->pdata, NULL, sizeof(gpointer), objs->len); - g_ptr_array_set_size(objs, nmtst_get_rand_uint32() % (objs->len + 1)); - } - - n = (TEST_IDX != 1) ? nmtst_get_rand_uint32() % 50u : 0u; - for (i = 0; i < n; i++) { - nm_auto_nmpobj const NMPObject *o = NULL; - guint try = 0; - -again: - o = _rule_create_random(platform); - for (j = 0; j < objs->len; j++) { - if (nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(o), - NMP_OBJECT_CAST_ROUTING_RULE(objs->pdata[j]), - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) - == 0) { - try++; - g_assert(try < 200); - nm_clear_pointer(&o, nmp_object_unref); - goto again; - } - } - g_ptr_array_add(objs, (gpointer) g_steal_pointer(&o)); - } - - if (TEST_IDX != 1) - nmtst_rand_perm(NULL, objs->pdata, NULL, sizeof(gpointer), objs->len); - - if (TEST_SYNC) { - gs_unref_hashtable GHashTable *unique_priorities = g_hash_table_new(NULL, NULL); - nm_auto_unref_rules_manager NMPRulesManager *rules_manager = - nmp_rules_manager_new(platform); - gs_unref_ptrarray GPtrArray *objs_sync = NULL; - gconstpointer USER_TAG_1 = &platform; - gconstpointer USER_TAG_2 = &unique_priorities; - - objs_sync = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); - - /* ensure that priorities are unique. Otherwise, it confuses the test, because - * kernel may wrongly be unable to add/delete routes based on a wrong match - * (rh#1685816, rh#1685816). */ - for (i = 0; i < objs->len; i++) { - const NMPObject *obj = objs->pdata[i]; - guint32 prio = NMP_OBJECT_CAST_ROUTING_RULE(obj)->priority; - - if (!NM_IN_SET(prio, 0, 32766, 32767) - && !g_hash_table_contains(unique_priorities, GUINT_TO_POINTER(prio))) { - g_hash_table_add(unique_priorities, GUINT_TO_POINTER(prio)); - g_ptr_array_add(objs_sync, (gpointer) nmp_object_ref(obj)); - } - } - - for (i = 0; i < objs_sync->len; i++) { - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - 1, - USER_TAG_1, - NULL); - if (nmtst_get_rand_bool()) { - /* this has no effect, because a negative priority (of same absolute value) - * has lower priority than the positive priority above. */ - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -1, - USER_TAG_2, - NULL); - } - if (nmtst_get_rand_uint32() % objs_sync->len == 0) { - nmp_rules_manager_sync(rules_manager, FALSE); - g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), - ==, - i + 1); - } - } - - nmp_rules_manager_sync(rules_manager, FALSE); - g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), - ==, - objs_sync->len); - - for (i = 0; i < objs_sync->len; i++) { - switch (nmtst_get_rand_uint32() % 3) { - case 0: - nmp_rules_manager_untrack(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - USER_TAG_1); - nmp_rules_manager_untrack(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - USER_TAG_1); - break; - case 1: - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -1, - USER_TAG_1, - NULL); - break; - case 2: - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -2, - USER_TAG_2, - NULL); - break; - } - if (nmtst_get_rand_uint32() % objs_sync->len == 0) { - nmp_rules_manager_sync(rules_manager, FALSE); - g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), - ==, - objs_sync->len - i - 1); - } - } - - nmp_rules_manager_sync(rules_manager, FALSE); - - } else { - for (i = 0; i < objs->len;) { - const NMPObject *obj = objs->pdata[i]; - - for (j = 0; j < objs->len; j++) - g_assert((j < i) == (!!_platform_has_routing_rule(platform, objs->pdata[j]))); - - r = nm_platform_routing_rule_add(platform, - NMP_NLM_FLAG_ADD, - NMP_OBJECT_CAST_ROUTING_RULE(obj)); - - if (r == -EEXIST) { - g_assert(!_platform_has_routing_rule(platform, obj)); - /* this should not happen, but there are bugs in kernel (rh#1686075). */ - for (j = 0; j < i; j++) { - const NMPObject *obj2 = objs->pdata[j]; - - g_assert(_platform_has_routing_rule(platform, obj2)); - - if (_rule_fuzzy_equal(obj, obj2, RTM_NEWRULE)) { - r = 0; - break; - } - } - if (r == 0) { - /* OK, the rule is shadowed by another rule, and kernel does not allow - * us to add this one (rh#1686075). Drop this from the test. */ - g_ptr_array_remove_index(objs, i); - had_an_issue_exist = TRUE; - continue; - } - } - - if (r != 0) { - NMPLookup lookup; - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter iter; - const NMPObject * o; - - g_print(">>> failing... errno=%d, rule=%s\n", - r, - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0)); - - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); - head_entry = nm_platform_lookup(platform, &lookup); - nmp_cache_iter_for_each (&iter, head_entry, &o) { - char ch = ' '; - - if (NMP_OBJECT_CAST_ROUTING_RULE(o)->addr_family - == NMP_OBJECT_CAST_ROUTING_RULE(obj)->addr_family - && NMP_OBJECT_CAST_ROUTING_RULE(o)->priority - == NMP_OBJECT_CAST_ROUTING_RULE(obj)->priority) - ch = '*'; - g_print(">>> existing rule: %c %s\n", - ch, - nmp_object_to_string(o, NMP_OBJECT_TO_STRING_ALL, NULL, 0)); - } - - nmtstp_run_command_check("ip rule"); - nmtstp_run_command_check("ip -6 rule"); - g_assert_cmpint(r, ==, 0); - } - - g_assert(_platform_has_routing_rule(platform, obj)); - - g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), - ==, - i + 1); - - i++; - } - - if (TEST_IDX != 1) - nmtst_rand_perm(NULL, objs->pdata, NULL, sizeof(gpointer), objs->len); - - if (_LOGD_ENABLED()) { - nmtstp_run_command_check("ip rule"); - nmtstp_run_command_check("ip -6 rule"); - } - - for (i = 0; i < objs->len; i++) { - const NMPObject *obj = objs->pdata[i]; - const NMPObject *obj2; - - for (j = 0; j < objs->len; j++) - g_assert((j < i) == (!_platform_has_routing_rule(platform, objs->pdata[j]))); - - g_assert(_platform_has_routing_rule(platform, obj)); - - r = nm_platform_object_delete(platform, obj); - g_assert_cmpint(r, ==, TRUE); - - obj2 = _platform_has_routing_rule(platform, obj); - - if (obj2) { - guint k; - - /* When deleting a rule, kernel does a fuzzy match, ignoring for example: - * - action, if it is FR_ACT_UNSPEC - * - iifname,oifname if it is unspecified - * rh#1685816 - * - * That means, we may have deleted the wrong rule. Which one? */ - k = i; - for (j = i + 1; j < objs->len; j++) { - if (!_platform_has_routing_rule(platform, objs->pdata[j])) { - g_assert_cmpint(k, ==, i); - k = j; - } - } - g_assert_cmpint(k, >, i); - - if (!_rule_fuzzy_equal(obj, objs->pdata[k], RTM_DELRULE)) { - g_print(">>> failing...\n"); - g_print(">>> no fuzzy match between: %s\n", - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0)); - g_print( - ">>> and: %s\n", - nmp_object_to_string(objs->pdata[k], NMP_OBJECT_TO_STRING_ALL, NULL, 0)); - g_assert_not_reached(); - } - - objs->pdata[i] = objs->pdata[k]; - objs->pdata[k] = (gpointer) obj; - obj2 = NULL; - } - - g_assert(!obj2); - - g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), - ==, - objs->len - i - 1); - } - } - - g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), ==, 0); - - for (i = 0; i < objs_initial->len; i++) { - const NMPObject *obj = objs_initial->pdata[i]; - - for (j = 0; j < objs_initial->len; j++) - g_assert((j < i) == (!!_platform_has_routing_rule(platform, objs_initial->pdata[j]))); - - r = nm_platform_routing_rule_add(platform, - NMP_NLM_FLAG_ADD, - NMP_OBJECT_CAST_ROUTING_RULE(obj)); - g_assert_cmpint(r, ==, 0); - } - for (j = 0; j < objs_initial->len; j++) - g_assert(_platform_has_routing_rule(platform, objs_initial->pdata[j])); - g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), - ==, - objs_initial->len); - - /* the tests passed as good as we could (as good as we implemented workarounds for them). - * Still, with this kernel, not all features were fully tested. Mark the test as skipped. */ - if (had_an_issue_exist) - g_test_skip("adding a rule failed with EEXIST although it should not (rh#1686075)"); - else if (!_rule_check_kernel_support(platform, -1)) - g_test_skip("some kernel features were not available and skipped for the test"); -} - -/*****************************************************************************/ - -NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; - -void -_nmtstp_init_tests(int *argc, char ***argv) -{ - nmtst_init_with_logging(argc, argv, NULL, "ALL"); -} - -void -_nmtstp_setup_tests(void) -{ -#define add_test_func(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, TRUE) -#define add_test_func_data(testpath, test_func, arg) \ - nmtstp_env1_add_test_func_data(testpath, test_func, arg, TRUE) - add_test_func("/route/ip4", test_ip4_route); - add_test_func("/route/ip6", test_ip6_route); - add_test_func("/route/ip4_metric0", test_ip4_route_metric0); - add_test_func_data("/route/ip4_options/1", test_ip4_route_options, GINT_TO_POINTER(1)); - if (nmtstp_is_root_test()) - add_test_func_data("/route/ip4_options/2", test_ip4_route_options, GINT_TO_POINTER(2)); - add_test_func_data("/route/ip6_options/1", test_ip6_route_options, GINT_TO_POINTER(1)); - add_test_func_data("/route/ip6_options/2", test_ip6_route_options, GINT_TO_POINTER(2)); - add_test_func_data("/route/ip6_options/3", test_ip6_route_options, GINT_TO_POINTER(3)); - - if (nmtstp_is_root_test()) { - add_test_func_data("/route/ip/1", test_ip, GINT_TO_POINTER(1)); - add_test_func("/route/ip4_route_get", test_ip4_route_get); - add_test_func("/route/ip6_route_get", test_ip6_route_get); - add_test_func("/route/ip4_zero_gateway", test_ip4_zero_gateway); - } - - if (nmtstp_is_root_test()) { - add_test_func_data("/route/rule/1", test_rule, GINT_TO_POINTER(1)); - add_test_func_data("/route/rule/2", test_rule, GINT_TO_POINTER(2)); - 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)); - } -} |