diff options
Diffstat (limited to 'src/core/platform/tests/test-route.c')
| -rw-r--r-- | src/core/platform/tests/test-route.c | 397 |
1 files changed, 319 insertions, 78 deletions
diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index 148ed792..bd8fdc27 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -27,7 +27,7 @@ _wait_for_ipv4_addr_device_route(NMPlatform *platform, /* 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); + addr = nm_ip4_addr_clear_host_address(addr, plen); NMTST_WAIT_ASSERT(400, { NMDedupMultiIter iter; NMPLookup lookup; @@ -41,7 +41,7 @@ _wait_for_ipv4_addr_device_route(NMPlatform *platform, &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) + if (r->plen == plen && addr == nm_ip4_addr_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; @@ -333,30 +333,33 @@ test_ip4_route(void) /* 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); + 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[0].n_nexthops = 1; + 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[1].n_nexthops = 1; + 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); + rts[2].n_nexthops = 1; g_assert_cmpint(routes->len, ==, 3); nmtst_platform_ip4_routes_equal_aptr((const NMPObject *const *) routes->pdata, rts, @@ -635,21 +638,22 @@ test_ip4_route_options(gconstpointer test_data) 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, - .mss = 1300, - .quickack = TRUE, - .rto_min = 1000, + .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, + .mss = 1300, + .quickack = TRUE, + .rto_min = 1000, + .n_nexthops = 1, }); break; case 2: @@ -663,12 +667,13 @@ test_ip4_route_options(gconstpointer test_data) .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, + .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, + .n_nexthops = 1, }); rts_add[rts_n++] = ((NMPlatformIP4Route){ .ifindex = IFINDEX, @@ -678,6 +683,7 @@ test_ip4_route_options(gconstpointer test_data) .r_rtm_flags = RTNH_F_ONLINK, .plen = 24, .metric = 20, + .n_nexthops = 1, }); break; default: @@ -691,24 +697,23 @@ test_ip4_route_options(gconstpointer test_data) 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)); + g_assert(nm_platform_ip4_address_add(NM_PLATFORM_GET, + a->ifindex, + a->address, + a->plen, + a->peer_address, + nm_ip4_addr_get_broadcast_address(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]))); + nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i], NULL))); for (i = 0; i < rts_n; i++) { rts_cmp[i] = rts_add[i]; @@ -747,7 +752,7 @@ test_ip6_route_get(void) nmtstp_wait_for_signal(NM_PLATFORM_GET, 10); if (nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, - nmtst_inet6_from_string("fd01:abcd::"), + nmtst_inet6_from_string_p("fd01:abcd::"), 64, NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, NULL, @@ -755,7 +760,7 @@ test_ip6_route_get(void) break; }); - a = nmtst_inet6_from_string("fd01:abcd::42"); + a = nmtst_inet6_from_string_p("fd01:abcd::42"); result = nm_platform_ip_route_get(NM_PLATFORM_GET, AF_INET6, a, @@ -797,7 +802,7 @@ test_ip6_route_options(gconstpointer test_data) 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"), + .network = nmtst_inet6_from_string("2001:db8:a:b:0:0:0:0"), .plen = 64, .gateway = in6addr_any, .metric = 1024, @@ -812,7 +817,7 @@ test_ip6_route_options(gconstpointer test_data) case 2: addr[addr_n++] = ((NMPlatformIP6Address){ .ifindex = IFINDEX, - .address = *nmtst_inet6_from_string("2000::2"), + .address = nmtst_inet6_from_string("2000::2"), .plen = 128, .peer_address = in6addr_any, .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, @@ -822,17 +827,17 @@ test_ip6_route_options(gconstpointer test_data) rts_add[rts_n++] = ((NMPlatformIP6Route){ .ifindex = IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = *nmtst_inet6_from_string("1010::1"), + .network = nmtst_inet6_from_string("1010::1"), .plen = 128, .gateway = in6addr_any, .metric = 256, - .pref_src = *nmtst_inet6_from_string("2000::2"), + .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"), + .address = nmtst_inet6_from_string("2001:db8:8086::5"), .plen = 128, .peer_address = in6addr_any, .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, @@ -842,7 +847,7 @@ test_ip6_route_options(gconstpointer test_data) 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::"), + .network = nmtst_inet6_from_string("2001:db8:8086::"), .plen = 110, .metric = 10021, .mss = 0, @@ -850,9 +855,9 @@ test_ip6_route_options(gconstpointer test_data) 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::"), + .network = nmtst_inet6_from_string("2001:db8:abad:c0de::"), .plen = 64, - .gateway = *nmtst_inet6_from_string("2001:db8:8086::1"), + .gateway = nmtst_inet6_from_string("2001:db8:8086::1"), .metric = 21, .mss = 0, }); @@ -918,7 +923,7 @@ test_ip(gconstpointer test_data) const NMPlatformLink *l; char ifname[IFNAMSIZ]; char ifname2[IFNAMSIZ]; - char s1[NM_UTILS_INET_ADDRSTRLEN]; + char s1[NM_INET_ADDRSTRLEN]; NMPlatform *platform = NM_PLATFORM_GET; const int EX_ = -1; struct { @@ -983,8 +988,8 @@ 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))); + g_assert(NMTST_NM_ERR_SUCCESS( + nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_APPEND, r, NULL))); } else { i = nmtst_get_rand_uint32() % order_len; idx = order_idx[i]; @@ -1171,7 +1176,7 @@ _rule_check_kernel_support(NMPlatform *platform, int attribute) .addr_family = AF_INET, .priority = PROBE_PRORITY, .uid_range = - { + { .start = 0, .end = 0, }, @@ -1278,7 +1283,7 @@ _rule_create_random(NMPlatform *platform) guint32 p; int addr_size; guint i; - char saddr[NM_UTILS_INET_ADDRSTRLEN]; + char saddr[NM_INET_ADDRSTRLEN]; static struct { guint32 uid; guint32 euid; @@ -1331,7 +1336,7 @@ _rule_create_random(NMPlatform *platform) 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( + 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); @@ -1931,7 +1936,7 @@ test_blackhole(gconstpointer test_data) 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); + r = nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r4, NULL); else r = nm_platform_ip6_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r6); @@ -2155,6 +2160,229 @@ test_mptcp(gconstpointer test_data) /*****************************************************************************/ +static void +_ensure_onlink_routes(void) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS(NMTSTP_ENV1_DEVICE_NAME) && NMTSTP_ENV1_DEVICE_NAME[i]; i++) { + nmtstp_run_command("ip route append 7.7.7.0/24 dev %s%s", + NMTSTP_ENV1_DEVICE_NAME[i], + nmtst_is_debug() ? "" : " &>/dev/null"); + nmtstp_run_command("ip route append 7:7:7::/64 dev %s%s", + NMTSTP_ENV1_DEVICE_NAME[i], + nmtst_is_debug() ? "" : " &>/dev/null"); + } +} + +static void +test_cache_consistency_routes(gconstpointer test_data) +{ + const int TEST_IDX = GPOINTER_TO_INT(test_data); + NMPlatform *platform = NM_PLATFORM_GET; + gboolean is_test_quick = nmtst_test_quick(); + const int N_RUN = is_test_quick ? 50 : 500; + int i_run; + gs_unref_ptrarray GPtrArray *keeper = g_ptr_array_new_with_free_func(g_free); + + _ensure_onlink_routes(); + + for (i_run = 0; i_run < N_RUN; i_run++) { + const char *extra_options[100]; + gsize n_extra_options = 0; + gs_free char *extra_options_str = NULL; + int i_if; + int ifindex; + const char *ifname; + int IS_IPv4; + const char *op; + const char *prefix; + const char *s; + const char *route_type; + int i; + int n; + char addr_family_char[2] = {'6', '4'}; + + g_ptr_array_set_size(keeper, 0); + + switch (TEST_IDX) { + case 1: + IS_IPv4 = TRUE; + break; + case 2: + IS_IPv4 = FALSE; + break; + default: + IS_IPv4 = nmtst_get_rand_bool(); + break; + } + + i_if = nmtst_get_rand_uint32() % 2; + op = nmtst_rand_select_str("flush", "add", "change", "append", "prepend", "replace"); + + ifindex = NMTSTP_ENV1_IFINDEXES[i_if]; + ifname = NMTSTP_ENV1_DEVICE_NAME[i_if]; + + g_assert_cmpint(ifindex, ==, nm_platform_link_get_ifindex(platform, ifname)); + + if (nm_streq(op, "flush")) { + if (!nmtst_get_rand_one_case_in(10)) { + /* flush more seldom. */ + continue; + } + nmtstp_run_command("ip -%c route flush dev %s" + " table %s" /* table */ + "%s" /* redirect */ + "", + addr_family_char[IS_IPv4], + ifname, + nmtst_rand_select_str("main", "10222", "10223", "all"), + nmtst_is_debug() ? "" : " &>/dev/null"); + _ensure_onlink_routes(); + goto done; + } + + route_type = nmtst_get_rand_one_case_in(4) + ? nmtst_rand_select_str("unicast", "blackhole", "local", "broadcast") + : NULL; + + if (NM_IN_STRSET(route_type, "blackhole")) { + ifindex = 0; + ifname = NULL; + } + + if (IS_IPv4) { + prefix = nmtst_rand_select_str("192.168.4.0/24", + "192.168.5.0/24", + "192.168.5.5/32", + "default"); + } else { + prefix = + nmtst_rand_select_str("a:b:c:d::/64", "a:b:c:e::/64", "a:b:c:f::/64", "default"); + } + + s = nmtst_rand_select_str(NULL, "kernel", "bird"); + if (s) { + if (nmtst_get_rand_bool()) { + s = nm_streq(s, "kernel") ? nmtst_rand_select_str("boot", "static", "ra") + : nmtst_rand_select_str("zebra", "bird"); + } + extra_options[n_extra_options++] = "proto"; + extra_options[n_extra_options++] = s; + } + + s = nmtst_rand_select_str(NULL, "10", "20"); + if (s) { + extra_options[n_extra_options++] = "metric"; + extra_options[n_extra_options++] = s; + } + + s = nmtst_rand_select_str(NULL, "10222", "10223"); + if (s) { + extra_options[n_extra_options++] = "table"; + extra_options[n_extra_options++] = s; + } + + if (!IS_IPv4 && NM_IN_STRSET(op, "add", "change", "append", "prepend", "replace")) { + /* kernel has a bug with append/prepend of IPv6 routes with next-hops. + * This leads to wrong notification messages, wrong merging of multi-hop + * routes and cache inconsistency in NMPlatform. + * + * https://bugzilla.redhat.com/show_bug.cgi?id=2161994 + * + * For now, disable the test case to make the unit test not fail. + * + * While being a kernel bug, it leads to cache inconsistency in NMPlatform, + * which is a problem for NetworkManager. I don't see how we can detect + * this problem to trigger a refresh. */ + } else if (ifname && nmtst_get_rand_one_case_in(3)) { + n = (nmtst_get_rand_uint32() % 4) + 1; + for (i = 0; i < n; i++) { + extra_options[n_extra_options++] = "nexthop"; + extra_options[n_extra_options++] = "via"; + if (IS_IPv4) { + extra_options[n_extra_options++] = + nmtst_keeper_printf(&keeper, "7.7.7.%d", i + 1); + } else { + extra_options[n_extra_options++] = + nmtst_keeper_printf(&keeper, "7:7:7:7::%d", i + 1); + } + extra_options[n_extra_options++] = "dev"; + extra_options[n_extra_options++] = NMTSTP_ENV1_DEVICE_NAME[nmtst_get_rand_bool()]; + if (IS_IPv4 && i == 0) { + /* For IPv4, there is a problem if we configure a route with + * only one next-hop and a weight. In that case, kernel allows + * to add duplicates (that only differ by weight), but on netlink + * the weight is not exposed, so the routes look identical and + * are deduplicated by the hash. + * See https://bugzilla.redhat.com/show_bug.cgi?id=2162315 + * + * This needs a kernel fix. Workaround that issue here, otherwise the test + * will randomly fail. */ + } else if (nmtst_get_rand_one_case_in(3)) { + extra_options[n_extra_options++] = "weight"; + extra_options[n_extra_options++] = "5"; + } + } + + ifname = NULL; + ifindex = 0; + } + + g_assert_cmpint(n_extra_options, <, G_N_ELEMENTS(extra_options)); + extra_options[n_extra_options] = NULL; + + if (nmtst_is_debug()) + nmtstp_run_command("ip -%c -d route show table all", addr_family_char[IS_IPv4]); + + /* We ignore errors. The reason is that operations like "change" might fail if + * the route doesn't exist. That's fine for our test. We just do randomly things + * and some of them will stick. */ + nmtstp_run_command( + "ip -%c route " + "%s" /* op */ + "%s%s" /* route_type */ + " %s" /* prefix */ + "%s%s" /* ifname */ + "%s%s" /* extra_options */ + "%s" /* redirect */ + "", + addr_family_char[IS_IPv4], + op, + NM_PRINT_FMT_QUOTED2(route_type, " ", route_type, ""), + prefix, + NM_PRINT_FMT_QUOTED2(ifname, " dev ", ifname, ""), + NM_PRINT_FMT_QUOTED2(extra_options[0], + " ", + (extra_options_str = g_strjoinv(" ", (char **) extra_options)), + ""), + nmtst_is_debug() ? "" : " &>/dev/null"); + + if (nmtst_is_debug()) + nmtstp_run_command("ip -%c -d route show table all", addr_family_char[IS_IPv4]); +done: + nm_platform_process_events(platform); + + if (!is_test_quick || (i_run + 1 == N_RUN) || nmtst_get_rand_one_case_in(5)) { + nmtstp_check_platform( + platform, + nmtst_get_rand_one_case_in(5) + ? 0u + : nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))); + } + } + + if (is_test_quick) { + gs_free char *msg = NULL; + + msg = g_strdup_printf("Ran a quick version of test %s (try NMTST_DEBUG=slow)", + nmtst_test_get_path()); + g_test_skip(msg); + } +} + +/*****************************************************************************/ + NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; void @@ -2166,9 +2394,11 @@ _nmtstp_init_tests(int *argc, char ***argv) 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(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, 1, TRUE) #define add_test_func_data(testpath, test_func, arg) \ - nmtstp_env1_add_test_func_data(testpath, test_func, arg, TRUE) + nmtstp_env1_add_test_func_data(testpath, test_func, arg, 1, TRUE) +#define add_test_func_data_with_if2(testpath, test_func, arg) \ + nmtstp_env1_add_test_func_data(testpath, test_func, arg, 2, TRUE) add_test_func("/route/ip4", test_ip4_route); add_test_func("/route/ip6", test_ip6_route); @@ -2201,4 +2431,15 @@ _nmtstp_setup_tests(void) add_test_func_data("/route/mptcp/1", test_mptcp, GINT_TO_POINTER(1)); add_test_func_data("/route/mptcp/2", test_mptcp, GINT_TO_POINTER(2)); } + if (nmtstp_is_root_test()) { + add_test_func_data_with_if2("/route/test_cache_consistency_routes/1", + test_cache_consistency_routes, + GINT_TO_POINTER(1)); + add_test_func_data_with_if2("/route/test_cache_consistency_routes/2", + test_cache_consistency_routes, + GINT_TO_POINTER(2)); + add_test_func_data_with_if2("/route/test_cache_consistency_routes/3", + test_cache_consistency_routes, + GINT_TO_POINTER(3)); + } } |