diff options
author | Thomas Haller <thaller@redhat.com> | 2023-01-19 11:54:10 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2023-01-19 11:54:10 +0100 |
commit | adad1d435814e6e195c97836073bce62bac40a47 (patch) | |
tree | 98c020c76704adbf4e14c9c04a916dc7f85011bd | |
parent | dabfea2fc265e563af85cad62743c1c18738294c (diff) | |
parent | 87522ad3167d386d52c2188655c06bb6e898815d (diff) |
platform: merge branch 'th/platform-cache-consistency-routes'
https://bugzilla.redhat.com/show_bug.cgi?id=2060684
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1494
-rw-r--r-- | src/core/NetworkManagerUtils.c | 4 | ||||
-rw-r--r-- | src/core/platform/nm-fake-platform.c | 1 | ||||
-rw-r--r-- | src/core/platform/tests/test-address.c | 2 | ||||
-rw-r--r-- | src/core/platform/tests/test-common.c | 346 | ||||
-rw-r--r-- | src/core/platform/tests/test-common.h | 133 | ||||
-rw-r--r-- | src/core/platform/tests/test-link.c | 12 | ||||
-rw-r--r-- | src/core/platform/tests/test-platform-general.c | 4 | ||||
-rw-r--r-- | src/core/platform/tests/test-route.c | 224 | ||||
-rw-r--r-- | src/core/platform/tests/test-tc.c | 8 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.c | 9 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.h | 39 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-test-utils.h | 23 | ||||
-rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 109 | ||||
-rw-r--r-- | src/libnm-platform/nm-linux-platform.h | 7 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.c | 76 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.h | 5 | ||||
-rw-r--r-- | src/libnm-platform/nmp-netns.c | 42 | ||||
-rw-r--r-- | src/libnm-platform/nmp-object.c | 107 | ||||
-rw-r--r-- | src/libnm-platform/nmp-object.h | 17 |
19 files changed, 929 insertions, 239 deletions
diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index f3c032ce9f..15a3e5ddcf 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -1848,11 +1848,11 @@ nm_platform_get(void) void nm_linux_platform_setup(void) { - nm_platform_setup(nm_linux_platform_new(FALSE, FALSE, FALSE)); + nm_platform_setup(nm_linux_platform_new(NULL, FALSE, FALSE, FALSE)); } void nm_linux_platform_setup_with_tc_cache(void) { - nm_platform_setup(nm_linux_platform_new(FALSE, FALSE, TRUE)); + nm_platform_setup(nm_linux_platform_new(NULL, FALSE, FALSE, TRUE)); } diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index f85a02e159..c92d9aef56 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -1232,6 +1232,7 @@ ip_route_add(NMPlatform *platform, NMPNlmFlags flags, NMPObject *obj_stack) obj, FALSE, nlmsgflags, + TRUE, &obj_old, &obj_new, &obj_replace, diff --git a/src/core/platform/tests/test-address.c b/src/core/platform/tests/test-address.c index 8e5ad13b43..0bce00c421 100644 --- a/src/core/platform/tests/test-address.c +++ b/src/core/platform/tests/test-address.c @@ -453,7 +453,7 @@ _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, FALSE) +#define add_test_func(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, 1, FALSE) add_test_func("/address/ipv4/general", test_ip4_address_general); add_test_func("/address/ipv6/general", test_ip6_address_general); diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index e408113ad4..e9c36a52dd 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -12,6 +12,7 @@ #include <sys/wait.h> #include <fcntl.h> #include <linux/if_tun.h> +#include <linux/rtnetlink.h> #include "n-acd/src/n-acd.h" @@ -21,8 +22,14 @@ (data)->ifname ? " ifname '" : "", (data)->ifname ?: "", (data)->ifname ? "'" : "", \ (data)->received_count -int NMTSTP_ENV1_IFINDEX = -1; -int NMTSTP_ENV1_EX = -1; +int NMTSTP_ENV1_IFINDEXES[]; + +const char *const NMTSTP_ENV1_DEVICE_NAME[] = { + "nm-test-device0", + "nm-test-device1", +}; + +int NMTSTP_ENV1_EX = -1; /*****************************************************************************/ @@ -540,7 +547,7 @@ _ip4_route_get(NMPlatform *platform, _init_platform(&platform, FALSE); - nmp_lookup_init_ip4_route_by_weak_id(&lookup, network, plen, metric, tos); + nmp_lookup_init_ip4_route_by_weak_id(&lookup, RT_TABLE_MAIN, network, plen, metric, tos); c = 0; nmp_cache_iter_for_each (&iter, nm_platform_lookup(platform, &lookup), &o) { @@ -633,7 +640,13 @@ _ip6_route_get(NMPlatform *platform, _init_platform(&platform, FALSE); - nmp_lookup_init_ip6_route_by_weak_id(&lookup, network, plen, metric, src, src_plen); + nmp_lookup_init_ip6_route_by_weak_id(&lookup, + RT_TABLE_MAIN, + network, + plen, + metric, + src, + src_plen); c = 0; nmp_cache_iter_for_each (&iter, nm_platform_lookup(platform, &lookup), &o) { @@ -732,6 +745,331 @@ nmtstp_run_command(const char *format, ...) /*****************************************************************************/ +static int +_assert_platform_sort_objs(gconstpointer ptr_a, gconstpointer ptr_b) +{ + const NMPObject *a = *((const NMPObject *const *) ptr_a); + const NMPObject *b = *((const NMPObject *const *) ptr_b); + + g_assert(NMP_OBJECT_IS_VALID(a)); + g_assert(NMP_OBJECT_IS_VALID(b)); + g_assert(NMP_OBJECT_GET_TYPE(a) == NMP_OBJECT_GET_TYPE(b)); + + NM_CMP_RETURN(nmp_object_id_cmp(a, b)); + g_assert_not_reached(); + return 0; +} + +static void +_assert_platform_printarr(NMPObjectType obj_type, GPtrArray *arr1, GPtrArray *arr2) +{ + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + guint i; + + _LOGT("compare arrays of %s. In cache %u entries, fetched %u entries", + NMP_OBJECT_TYPE_NAME(obj_type), + nm_g_ptr_array_len(arr1), + nm_g_ptr_array_len(arr2)); + + for (i = 0; i < nm_g_ptr_array_len(arr1); i++) { + _LOGT("cache[%u] %s", + i, + nmp_object_to_string(arr1->pdata[i], NMP_OBJECT_TO_STRING_ALL, sbuf, sizeof(sbuf))); + } + for (i = 0; i < nm_g_ptr_array_len(arr2); i++) { + _LOGT("fetch[%u] %s", + i, + nmp_object_to_string(arr2->pdata[i], NMP_OBJECT_TO_STRING_ALL, sbuf, sizeof(sbuf))); + } + + switch (obj_type) { + case NMP_OBJECT_TYPE_LINK: + nmtstp_run_command("ip -d link"); + break; + case NMP_OBJECT_TYPE_IP4_ADDRESS: + nmtstp_run_command("ip -d -4 address"); + break; + case NMP_OBJECT_TYPE_IP6_ADDRESS: + nmtstp_run_command("ip -d -6 address"); + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + nmtstp_run_command("ip -d -4 route show table all"); + break; + case NMP_OBJECT_TYPE_IP6_ROUTE: + nmtstp_run_command("ip -d -6 route show table all"); + break; + default: + g_assert_not_reached(); + break; + } +} + +static gboolean +_assert_platform_normalize_all(GPtrArray *arr) +{ + guint i; + gboolean normalized = FALSE; + + for (i = 0; i < nm_g_ptr_array_len(arr); i++) { + const NMPObject **ptr = (gpointer) &arr->pdata[i]; + NMPObject *new; + + switch (NMP_OBJECT_GET_TYPE(*ptr)) { + case NMP_OBJECT_TYPE_LINK: + new = nmp_object_clone(*ptr, FALSE); + new->link.rx_packets = 0; + new->link.rx_bytes = 0; + new->link.tx_packets = 0; + new->link.tx_bytes = 0; + nmp_object_ref_set(ptr, new); + nmp_object_unref(new); + normalized = TRUE; + default: + break; + } + } + return normalized; +} + +static void +_assert_platform_compare_arr(NMPObjectType obj_type, + const char *detail_type, + GPtrArray *arr1, + GPtrArray *arr2, + gboolean normalized, + gboolean share_multi_idx) +{ + const NMPClass *obj_class = nmp_class_from_type(obj_type); + char sbuf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; + char sbuf2[NM_UTILS_TO_STRING_BUFFER_SIZE]; + int idx; + int idx_pointer_comp = -1; + + for (idx = 0; TRUE; idx++) { + if (nm_g_ptr_array_len(arr1) == idx && nm_g_ptr_array_len(arr2) == idx) + break; + if (idx >= nm_g_ptr_array_len(arr1)) { + _assert_platform_printarr(obj_type, arr1, arr2); + g_error("Comparing %s (%s) for platform fails. Platform now shows entry #%u which is " + "not in the cache but expected %s", + obj_class->obj_type_name, + detail_type, + idx, + nmp_object_to_string(arr2->pdata[idx], + NMP_OBJECT_TO_STRING_ALL, + sbuf1, + sizeof(sbuf1))); + } + if (idx >= nm_g_ptr_array_len(arr2)) { + _assert_platform_printarr(obj_type, arr1, arr2); + g_error("Comparing %s (%s) for platform fails. Platform has no more entry #%u which is " + "still in the cache as %s", + obj_class->obj_type_name, + detail_type, + idx, + nmp_object_to_string(arr1->pdata[idx], + NMP_OBJECT_TO_STRING_ALL, + sbuf1, + sizeof(sbuf1))); + } + if (!nmp_object_equal(arr1->pdata[idx], arr2->pdata[idx])) { + _assert_platform_printarr(obj_type, arr1, arr2); + g_error("Comparing %s (%s) for platform fails. Platform entry #%u is now %s but in " + "cache is %s", + obj_class->obj_type_name, + detail_type, + idx, + nmp_object_to_string(arr2->pdata[idx], + NMP_OBJECT_TO_STRING_ALL, + sbuf1, + sizeof(sbuf1)), + nmp_object_to_string(arr1->pdata[idx], + NMP_OBJECT_TO_STRING_ALL, + sbuf2, + sizeof(sbuf2))); + } + + if (!normalized && (share_multi_idx != (arr1->pdata[idx] == arr2->pdata[idx])) + && idx_pointer_comp == -1) + idx_pointer_comp = idx; + } + + if (idx_pointer_comp != -1) { + _assert_platform_printarr(obj_type, arr1, arr2); + g_error("Comparing %s (%s) for platform fails for pointer comparison. Platform entry " + "#%u is now %s but in cache is %s", + obj_class->obj_type_name, + detail_type, + idx_pointer_comp, + nmp_object_to_string(arr2->pdata[idx_pointer_comp], + NMP_OBJECT_TO_STRING_ALL, + sbuf1, + sizeof(sbuf1)), + nmp_object_to_string(arr1->pdata[idx_pointer_comp], + NMP_OBJECT_TO_STRING_ALL, + sbuf2, + sizeof(sbuf2))); + } +} + +void +nmtstp_assert_platform(NMPlatform *platform, guint32 obj_type_flags) +{ + static const NMPObjectType obj_types[] = { + NMP_OBJECT_TYPE_IP4_ADDRESS, + NMP_OBJECT_TYPE_IP6_ADDRESS, + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_LINK, + }; + gboolean obj_type_flags_all = (obj_type_flags == 0u); + gs_unref_object NMPlatform *platform2 = NULL; + int i_obj_types; + gboolean share_multi_idx = nmtst_get_rand_bool(); + + /* This test creates a new NMLinuxPlatform instance. This will fill + * the cache with a new dump. + * + * Then it compares the content with @platform and checks that they + * agree. This tests that @platform cache is consistent, as it was + * updated based on netlink events. */ + + g_assert(NM_IS_LINUX_PLATFORM(platform)); + + _LOGD("assert-platform: start"); + + nm_platform_process_events(platform); + + platform2 = nm_linux_platform_new(share_multi_idx ? nm_platform_get_multi_idx(platform) : NULL, + TRUE, + nmtst_get_rand_bool(), + nmtst_get_rand_bool()); + g_assert(NM_IS_LINUX_PLATFORM(platform2)); + + for (i_obj_types = 0; i_obj_types < (int) G_N_ELEMENTS(obj_types); i_obj_types++) { + const NMPObjectType obj_type = obj_types[i_obj_types]; + const guint32 i_obj_type_flags = nmp_object_type_to_flags(obj_type); + gs_unref_ptrarray GPtrArray *arr1 = NULL; + gs_unref_ptrarray GPtrArray *arr2 = NULL; + NMPLookup lookup; + gboolean check_unordered = TRUE; + guint idx; + gboolean normalized; + + if (!obj_type_flags_all) { + if (!NM_FLAGS_ANY(obj_type_flags, i_obj_type_flags)) + continue; + obj_type_flags = NM_FLAGS_UNSET(obj_type_flags, i_obj_type_flags); + } + + nmp_lookup_init_obj_type(&lookup, obj_type); + + arr1 = nm_platform_lookup_clone(platform, &lookup, NULL, NULL) ?: g_ptr_array_new(); + arr2 = nm_platform_lookup_clone(platform2, &lookup, NULL, NULL) ?: g_ptr_array_new(); + + normalized = _assert_platform_normalize_all(arr1); + normalized = _assert_platform_normalize_all(arr2); + + if (check_unordered) { + /* We need to sort the two lists. */ + g_ptr_array_sort(arr1, _assert_platform_sort_objs); + g_ptr_array_sort(arr2, _assert_platform_sort_objs); + } + + _assert_platform_compare_arr(obj_type, "main", arr1, arr2, normalized, share_multi_idx); + + if (NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)) { + /* For routes, the WEAK_ID needs to be sorted and match the expected order. Check that. */ + g_assert(!normalized); + for (idx = 0; idx < nm_g_ptr_array_len(arr1); idx++) { + const NMPObject *obj1 = arr1->pdata[idx]; + const NMPObject *obj2 = arr2->pdata[idx]; + gs_unref_ptrarray GPtrArray *arr1b = NULL; + gs_unref_ptrarray GPtrArray *arr2b = NULL; + gs_unref_ptrarray GPtrArray *arr1b_sorted = NULL; + gs_unref_ptrarray GPtrArray *arr2b_sorted = NULL; + guint found_obj1 = 0; + guint found_obj2 = 0; + guint i; + + nmp_lookup_init_route_by_weak_id(&lookup, obj1); + arr1b = + nm_platform_lookup_clone(platform, &lookup, NULL, NULL) ?: g_ptr_array_new(); + g_assert_cmpint(arr1b->len, >, 0u); + + nmp_lookup_init_route_by_weak_id(&lookup, obj2); + arr2b = + nm_platform_lookup_clone(platform2, &lookup, NULL, NULL) ?: g_ptr_array_new(); + g_assert_cmpint(arr2b->len, ==, arr1b->len); + + /* First check that the lists agree, if we sort them. The list of + * weak-ids was supposed to honor the sort order from `ip route show`, + * but as that is not the case (see blow), first check whether at + * least the same routes are in the list (with wrong sort order). */ + arr1b_sorted = nm_g_ptr_array_new_clone(arr1b, NULL, NULL, NULL); + arr2b_sorted = nm_g_ptr_array_new_clone(arr2b, NULL, NULL, NULL); + g_ptr_array_sort(arr1b_sorted, _assert_platform_sort_objs); + g_ptr_array_sort(arr2b_sorted, _assert_platform_sort_objs); + _assert_platform_compare_arr(obj_type, + "weak-id-sorted", + arr1b_sorted, + arr2b_sorted, + normalized, + share_multi_idx); + + if (obj_type == NMP_OBJECT_TYPE_IP6_ROUTE) { + /* For IPv6, the weak-ids are actually not sorted correctly. + * This is because IPv6 multihop/ECMP routes get split into + * multiple objects, and we don't get this right. + * + * This may be a bug. But we probably don't rely on this + * anymore, because the weak-id were used to find which + * route got replaced with `NLM_F_REPLACE`, but that anyway + * doesn't work. We now always request a new dump. */ + } else if (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE) { + /* For IPv4, it also does not reliably always work. This may + * be a bug we want to fix. For now, ignore the check. + * + * This is probably caused by kernel bug + * https://bugzilla.redhat.com/show_bug.cgi?id=2162315 + * for which I think there is no workaround. + * + * Also, rhbz#2162315 means NMPlatform will merge two different + * routes together, if one of them were deleted, the RTM_DELROUTE + * message would wrongly delete single entry, leading to cache + * inconsistency. */ + } else { + /* Assert that also the original, not-sorted lists agree. */ + _assert_platform_compare_arr(obj_type, + "weak-id", + arr1b, + arr2b, + normalized, + share_multi_idx); + } + + for (i = 0; i < arr1b->len; i++) { + if (arr1b->pdata[i] == obj1) + found_obj1++; + if (arr2b->pdata[i] == obj2) + found_obj2++; + } + + g_assert_cmpint(found_obj1, ==, 1u); + g_assert_cmpint(found_obj2, ==, 1u); + } + } + } + + g_clear_object(&platform2); + + _LOGD("assert-platform: done"); + + g_assert_cmpint(obj_type_flags, ==, 0u); +} + +/*****************************************************************************/ + typedef struct { GMainLoop *loop; guint signal_counts; diff --git a/src/core/platform/tests/test-common.h b/src/core/platform/tests/test-common.h index 9319c79b8d..383a1fed47 100644 --- a/src/core/platform/tests/test-common.h +++ b/src/core/platform/tests/test-common.h @@ -18,8 +18,6 @@ #include "nm-test-utils-core.h" -#define DEVICE_NAME "nm-test-device" - /*****************************************************************************/ #define nmtstp_normalize_jiffies_time(requested_value, kernel_value) \ @@ -141,6 +139,10 @@ int nmtstp_run_command(const char *format, ...) _nm_printf(1, 2); /*****************************************************************************/ +void nmtstp_assert_platform(NMPlatform *platform, guint32 obj_type_flags); + +/*****************************************************************************/ + guint nmtstp_wait_for_signal(NMPlatform *platform, gint64 timeout_msec); guint nmtstp_wait_for_signal_until(NMPlatform *platform, gint64 until_ms); const NMPlatformLink *nmtstp_wait_for_link(NMPlatform *platform, @@ -535,36 +537,47 @@ void nmtstp_link_delete(NMPlatform *platform, /*****************************************************************************/ -extern int NMTSTP_ENV1_IFINDEX; +extern int NMTSTP_ENV1_IFINDEXES[2]; +extern const char *const NMTSTP_ENV1_DEVICE_NAME[G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES)]; + +#define DEVICE_NAME "nm-test-device0" +#define NMTSTP_ENV1_IFINDEX (NMTSTP_ENV1_IFINDEXES[0]) + extern int NMTSTP_ENV1_EX; static inline void _nmtstp_env1_wrapper_setup(const NmtstTestData *test_data) { - int *p_ifindex; + int *p_ifindexes; + gpointer p_n_ifaces; gpointer p_ifup; - - nmtst_test_data_unpack(test_data, &p_ifindex, NULL, NULL, NULL, &p_ifup); - - g_assert(p_ifindex && *p_ifindex == -1); + int n_ifaces; + int i; _LOGT("TEST[%s]: setup", test_data->testpath); - nmtstp_link_delete(NM_PLATFORM_GET, -1, -1, DEVICE_NAME, FALSE); + nmtst_test_data_unpack(test_data, &p_ifindexes, &p_n_ifaces, NULL, NULL, NULL, &p_ifup); - g_assert(NMTST_NM_ERR_SUCCESS(nm_platform_link_dummy_add(NM_PLATFORM_GET, DEVICE_NAME, NULL))); + n_ifaces = GPOINTER_TO_UINT(p_n_ifaces); + g_assert_cmpint(n_ifaces, >=, 1); + g_assert_cmpint(n_ifaces, <=, (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES)); - *p_ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - g_assert_cmpint(*p_ifindex, >, 0); - g_assert_cmpint(NMTSTP_ENV1_IFINDEX, ==, -1); + for (i = 0; i < (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES); i++) { + g_assert_cmpint(NMTSTP_ENV1_IFINDEXES[i], ==, 0); + g_assert_cmpint(p_ifindexes[i], ==, 0); + } - if (GPOINTER_TO_INT(p_ifup)) - g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, *p_ifindex, IFF_UP, TRUE) >= 0); + for (i = 0; i < n_ifaces; i++) { + p_ifindexes[i] = nmtstp_link_dummy_add(NULL, -1, NMTSTP_ENV1_DEVICE_NAME[i])->ifindex; + if (GPOINTER_TO_INT(p_ifup)) + nmtstp_link_set_updown(NULL, -1, p_ifindexes[i], TRUE); + } nm_platform_process_events(NM_PLATFORM_GET); - NMTSTP_ENV1_IFINDEX = *p_ifindex; - NMTSTP_ENV1_EX = nmtstp_run_command_check_external_global(); + for (i = 0; i < n_ifaces; i++) + NMTSTP_ENV1_IFINDEXES[i] = p_ifindexes[i]; + NMTSTP_ENV1_EX = nmtstp_run_command_check_external_global(); } static inline void @@ -575,7 +588,7 @@ _nmtstp_env1_wrapper_run(gconstpointer user_data) GTestFunc test_func; gconstpointer d; - nmtst_test_data_unpack(test_data, NULL, &test_func, &test_func_data, &d, NULL); + nmtst_test_data_unpack(test_data, NULL, NULL, &test_func, &test_func_data, &d, NULL); _LOGT("TEST[%s]: run", test_data->testpath); if (test_func) @@ -587,55 +600,73 @@ _nmtstp_env1_wrapper_run(gconstpointer user_data) static inline void _nmtstp_env1_wrapper_teardown(const NmtstTestData *test_data) { - int *p_ifindex; + int *p_ifindexes; + gpointer p_n_ifaces; + int n_ifaces; + int i; - nmtst_test_data_unpack(test_data, &p_ifindex, NULL, NULL, NULL, NULL); + _LOGT("TEST[%s]: teardown", test_data->testpath); - g_assert_cmpint(NMTSTP_ENV1_IFINDEX, ==, *p_ifindex); - NMTSTP_ENV1_IFINDEX = -1; + nmtst_test_data_unpack(test_data, &p_ifindexes, &p_n_ifaces, NULL, NULL, NULL, NULL); - _LOGT("TEST[%s]: teardown", test_data->testpath); + n_ifaces = GPOINTER_TO_UINT(p_n_ifaces); + g_assert_cmpint(n_ifaces, >=, 1); + g_assert_cmpint(n_ifaces, <=, (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES)); + + for (i = 0; i < (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES); i++) { + if (i < n_ifaces) + g_assert_cmpint(p_ifindexes[i], >, 0); + else + g_assert_cmpint(p_ifindexes[i], ==, 0); + g_assert_cmpint(NMTSTP_ENV1_IFINDEXES[i], ==, p_ifindexes[i]); + NMTSTP_ENV1_IFINDEXES[i] = 0; + } - g_assert_cmpint(*p_ifindex, ==, nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME)); - g_assert(nm_platform_link_delete(NM_PLATFORM_GET, *p_ifindex)); + for (i = 0; i < n_ifaces; i++) + nmtstp_link_delete(NULL, -1, p_ifindexes[i], NMTSTP_ENV1_DEVICE_NAME[i], TRUE); nm_platform_process_events(NM_PLATFORM_GET); _LOGT("TEST[%s]: finished", test_data->testpath); - *p_ifindex = -1; + for (i = 0; i < (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES); i++) + p_ifindexes[i] = 0; } /* add test function, that set's up a particular environment, consisting * of a dummy device with ifindex NMTSTP_ENV1_IFINDEX. */ -#define _nmtstp_env1_add_test_func_full(testpath, test_func, test_data_func, arg, ifup) \ - nmtst_add_test_func_full(testpath, \ - _nmtstp_env1_wrapper_run, \ - _nmtstp_env1_wrapper_setup, \ - _nmtstp_env1_wrapper_teardown, \ - ({ \ - static int _ifindex = -1; \ - &_ifindex; \ - }), \ - ({ \ - GTestFunc _test_func = (test_func); \ - _test_func; \ - }), \ - ({ \ - GTestDataFunc _test_func = (test_data_func); \ - _test_func; \ - }), \ - (arg), \ - ({ \ - gboolean _ifup = (ifup); \ - GINT_TO_POINTER(_ifup); \ +#define _nmtstp_env1_add_test_func_full(testpath, test_func, test_data_func, arg, n_ifaces, ifup) \ + nmtst_add_test_func_full(testpath, \ + _nmtstp_env1_wrapper_run, \ + _nmtstp_env1_wrapper_setup, \ + _nmtstp_env1_wrapper_teardown, \ + ({ \ + static int _ifindexes[G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES)] = {0}; \ + _ifindexes; \ + }), \ + ({ \ + guint _n_ifaces = (n_ifaces); \ + GUINT_TO_POINTER(_n_ifaces); \ + }), \ + ({ \ + GTestFunc _test_func = (test_func); \ + _test_func; \ + }), \ + ({ \ + GTestDataFunc _test_func = (test_data_func); \ + _test_func; \ + }), \ + (arg), \ + ({ \ + gboolean _ifup = (ifup); \ + GINT_TO_POINTER(!!_ifup); \ })) -#define nmtstp_env1_add_test_func_data(testpath, test_func, arg, ifup) \ - _nmtstp_env1_add_test_func_full(testpath, NULL, test_func, arg, ifup) +#define nmtstp_env1_add_test_func_data(testpath, test_func, arg, n_ifaces, ifup) \ + _nmtstp_env1_add_test_func_full(testpath, NULL, test_func, arg, n_ifaces, ifup) -#define nmtstp_env1_add_test_func(testpath, test_func, ifup) \ - _nmtstp_env1_add_test_func_full(testpath, test_func, NULL, NULL, ifup) +#define nmtstp_env1_add_test_func(testpath, test_func, n_ifaces, ifup) \ + _nmtstp_env1_add_test_func_full(testpath, test_func, NULL, NULL, n_ifaces, ifup) /*****************************************************************************/ diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index c0321d3a3d..6c61bac2d2 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -2858,7 +2858,7 @@ _test_netns_create_platform(void) netns = nmp_netns_new(); g_assert(NMP_IS_NETNS(netns)); - platform = nm_linux_platform_new(TRUE, TRUE, TRUE); + platform = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); g_assert(NM_IS_LINUX_PLATFORM(platform)); nmp_netns_pop(netns); @@ -2947,7 +2947,7 @@ test_netns_general(gpointer fixture, gconstpointer test_data) if (_check_sysctl_skip()) return; - platform_1 = nm_linux_platform_new(TRUE, TRUE, TRUE); + platform_1 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); platform_2 = _test_netns_create_platform(); /* add some dummy devices. The "other-*" devices are there to bump the ifindex */ @@ -3075,7 +3075,7 @@ test_netns_set_netns(gpointer fixture, gconstpointer test_data) if (_test_netns_check_skip()) return; - platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE); + platforms[0] = platform_0 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform(); platforms[2] = platform_2 = _test_netns_create_platform(); @@ -3174,7 +3174,7 @@ test_netns_push(gpointer fixture, gconstpointer test_data) if (_check_sysctl_skip()) return; - pl[0].platform = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE); + pl[0].platform = platform_0 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); pl[1].platform = platform_1 = _test_netns_create_platform(); pl[2].platform = platform_2 = _test_netns_create_platform(); @@ -3321,7 +3321,7 @@ test_netns_bind_to_path(gpointer fixture, gconstpointer test_data) if (_test_netns_check_skip()) return; - platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE); + platforms[0] = platform_0 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform(); platforms[2] = platform_2 = _test_netns_create_platform(); @@ -3486,7 +3486,7 @@ test_sysctl_netns_switch(void) if (_test_netns_check_skip()) return; - platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE); + platforms[0] = platform_0 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform(); platforms[2] = platform_2 = _test_netns_create_platform(); PL = platforms[nmtst_get_rand_uint32() % 3]; diff --git a/src/core/platform/tests/test-platform-general.c b/src/core/platform/tests/test-platform-general.c index db2a705435..cebd44f65b 100644 --- a/src/core/platform/tests/test-platform-general.c +++ b/src/core/platform/tests/test-platform-general.c @@ -31,7 +31,7 @@ test_init_linux_platform(void) { gs_unref_object NMPlatform *platform = NULL; - platform = nm_linux_platform_new(TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); + platform = nm_linux_platform_new(NULL, TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); } /*****************************************************************************/ @@ -42,7 +42,7 @@ test_link_get_all(void) gs_unref_object NMPlatform *platform = NULL; gs_unref_ptrarray GPtrArray *links = NULL; - platform = nm_linux_platform_new(TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); + platform = nm_linux_platform_new(NULL, TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); links = nm_platform_link_get_all(platform, TRUE); } diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index de34cfaef1..001ecbc70f 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -2160,6 +2160,213 @@ 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", NMTSTP_ENV1_DEVICE_NAME[i]); + nmtstp_run_command("ip route append 7:7:7::/64 dev %s", NMTSTP_ENV1_DEVICE_NAME[i]); + } +} + +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" + "%s" /* redirect */ + "", + addr_family_char[IS_IPv4], + ifname, + 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("babel", "bgp"); + } + 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 (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_assert_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 @@ -2171,9 +2378,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); @@ -2206,4 +2415,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)); + } } diff --git a/src/core/platform/tests/test-tc.c b/src/core/platform/tests/test-tc.c index 6a2019c84a..832fbea6bb 100644 --- a/src/core/platform/tests/test-tc.c +++ b/src/core/platform/tests/test-tc.c @@ -214,8 +214,8 @@ _nmtstp_init_tests(int *argc, char ***argv) void _nmtstp_setup_tests(void) { - nmtstp_env1_add_test_func("/link/qdisc/1", test_qdisc1, TRUE); - nmtstp_env1_add_test_func("/link/qdisc/fq_codel", test_qdisc_fq_codel, TRUE); - nmtstp_env1_add_test_func("/link/qdisc/sfq", test_qdisc_sfq, TRUE); - nmtstp_env1_add_test_func("/link/qdisc/tbf", test_qdisc_tbf, TRUE); + nmtstp_env1_add_test_func("/link/qdisc/1", test_qdisc1, 1, TRUE); + nmtstp_env1_add_test_func("/link/qdisc/fq_codel", test_qdisc_fq_codel, 1, TRUE); + nmtstp_env1_add_test_func("/link/qdisc/sfq", test_qdisc_sfq, 1, TRUE); + nmtstp_env1_add_test_func("/link/qdisc/tbf", test_qdisc_tbf, 1, TRUE); } diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index d2e989841f..702a63e9f6 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -2130,15 +2130,16 @@ nm_strv_cleanup(char **strv, gboolean strip_whitespace, gboolean skip_empty, gbo /*****************************************************************************/ GPtrArray * -_nm_g_ptr_array_copy(GPtrArray *array, - GCopyFunc func, - gpointer user_data, - GDestroyNotify element_free_func) +nm_g_ptr_array_new_clone(GPtrArray *array, + GCopyFunc func, + gpointer user_data, + GDestroyNotify element_free_func) { GPtrArray *new_array; guint i; g_return_val_if_fail(array, NULL); + nm_assert((!!func) == (!!element_free_func)); new_array = g_ptr_array_new_full(array->len, element_free_func); for (i = 0; i < array->len; i++) { diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 7ad2874244..083ed137ee 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -2068,40 +2068,29 @@ nm_g_ptr_array_pdata(const GPtrArray *arr) return arr ? arr->pdata : NULL; } -GPtrArray *_nm_g_ptr_array_copy(GPtrArray *array, - GCopyFunc func, - gpointer user_data, - GDestroyNotify element_free_func); - /** - * nm_g_ptr_array_copy: + * nm_g_ptr_array_new_clone: * @array: the #GPtrArray to clone. * @func: the copy function. * @user_data: the user data for the copy function - * @element_free_func: the free function of the elements. @array MUST have - * the same element_free_func. This argument is only used on older - * glib, that doesn't support g_ptr_array_copy(). + * @element_free_func: the free function of the elements. This function + * must agree with the owner-ship semantics of @func. * * This is a replacement for g_ptr_array_copy(), which is not available * before glib 2.62. Since GPtrArray does not allow to access the internal * element_free_func, we cannot add a compatibility implementation of g_ptr_array_copy() - * and the user must provide a suitable destroy function. + * as the caller must provide the correct element_free_func. * - * Note that the @element_free_func MUST correspond to free function set in @array. + * So this is not the same as g_ptr_array_copy() (hence the different name) because + * g_ptr_array_copy() uses the free func of the source array, which we cannot access. + * With g_ptr_array_copy() the copy func must agree with the array's free func. + * Here, it must agree with the provided @element_free_func. This allows for example + * to do a shallow-copy without cloning the elements (which you cannot do with g_ptr_array_copy()). */ -#if GLIB_CHECK_VERSION(2, 62, 0) -#define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ - ({ \ - _nm_unused GDestroyNotify const _element_free_func = (element_free_func); \ - \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS; \ - g_ptr_array_copy((array), (func), (user_data)); \ - G_GNUC_END_IGNORE_DEPRECATIONS; \ - }) -#else -#define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ - _nm_g_ptr_array_copy((array), (func), (user_data), (element_free_func)) -#endif +GPtrArray *nm_g_ptr_array_new_clone(GPtrArray *array, + GCopyFunc func, + gpointer user_data, + GDestroyNotify element_free_func); /*****************************************************************************/ @@ -2510,7 +2499,7 @@ nm_strv_ptrarray_clone(const GPtrArray *src, gboolean null_if_empty) { if (!src || (null_if_empty && src->len == 0)) return NULL; - return nm_g_ptr_array_copy((GPtrArray *) src, nm_copy_func_g_strdup, NULL, g_free); + return nm_g_ptr_array_new_clone((GPtrArray *) src, nm_copy_func_g_strdup, NULL, g_free); } static inline void diff --git a/src/libnm-glib-aux/nm-test-utils.h b/src/libnm-glib-aux/nm-test-utils.h index 5196c9a076..50280d92b4 100644 --- a/src/libnm-glib-aux/nm-test-utils.h +++ b/src/libnm-glib-aux/nm-test-utils.h @@ -652,7 +652,7 @@ __nmtst_init(int *argc, if (!log_level && log_domains) { /* if the log level is not specified (but the domain is), we assume * the caller wants to set it depending on is_debug */ - log_level = is_debug ? "DEBUG" : "WARN"; + log_level = is_debug ? "TRACE" : "WARN"; } if (!__nmtst_internal.assert_logging) { @@ -3069,6 +3069,27 @@ nmtst_ip_address_new(int addr_family, const char *str) /*****************************************************************************/ +static inline gpointer +nmtst_keeper_add(GPtrArray **p_arr, gpointer ptr) +{ + if (!p_arr) { + /* If not GPtrArray in/out argument is given, track the pointer + * via _nmtst_testdata_track_add(), which means it stays alive + * until the end of the test. */ + _nmtst_testdata_track_add(ptr, g_free); + } else { + if (!*p_arr) + *p_arr = g_ptr_array_new_with_free_func(g_free); + + g_ptr_array_add(*p_arr, ptr); + } + return ptr; +} + +#define nmtst_keeper_printf(p_ptr, ...) nmtst_keeper_add((p_ptr), g_strdup_printf(__VA_ARGS__)) + +/*****************************************************************************/ + #define nmtst_gbytes_from_arr(...) \ ({ \ const guint8 _arr[] = {__VA_ARGS__}; \ diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index a4a6448e71..762b1645e1 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -590,25 +590,29 @@ NM_LINUX_PLATFORM_FROM_PRIVATE(NMLinuxPlatformPrivate *priv) #define _NMLOG2(level, ...) _LOG(level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) #define _NMLOG2_err(errsv, level, ...) _LOG_err(errsv, level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) -#define _LOG_print(__level, __domain, __errsv, self, ...) \ - G_STMT_START \ - { \ - char __prefix[32]; \ - const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - NMPlatform *const __self = (self); \ - \ - if (__self && nm_platform_get_log_with_ptr(__self)) { \ - g_snprintf(__prefix, sizeof(__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ - __p_prefix = __prefix; \ - } \ - _nm_log(__level, \ - __domain, \ - __errsv, \ - NULL, \ - NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __p_prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ +#define _LOG_print(__level, __domain, __errsv, self, ...) \ + G_STMT_START \ + { \ + char __prefix[64]; \ + const char *__p_prefix = _NMLOG_PREFIX_NAME; \ + NMPlatform *const __self = (self); \ + \ + if (__self && nm_platform_get_log_with_ptr(__self)) { \ + g_snprintf(__prefix, \ + sizeof(__prefix), \ + "%s[" NM_HASH_OBFUSCATE_PTR_FMT "]", \ + _NMLOG_PREFIX_NAME, \ + NM_HASH_OBFUSCATE_PTR(__self)); \ + __p_prefix = __prefix; \ + } \ + _nm_log(__level, \ + __domain, \ + __errsv, \ + NULL, \ + NULL, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __p_prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ G_STMT_END #define _LOG(level, domain, self, ...) \ @@ -3783,15 +3787,6 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter else return NULL; - if (!NM_IN_SET(rtm->rtm_type, - RTN_UNICAST, - RTN_LOCAL, - RTN_BLACKHOLE, - RTN_UNREACHABLE, - RTN_PROHIBIT, - RTN_THROW)) - return NULL; - if (nlmsg_parse_arr(nlh, sizeof(struct rtmsg), tb, policy) < 0) return NULL; @@ -5304,7 +5299,7 @@ ip_route_get_lock_flag(const NMPlatformIPRoute *route) } static gboolean -ip_route_ignored_protocol(const NMPlatformIPRoute *route) +ip_route_is_alive(const NMPlatformIPRoute *route) { guint8 prot; @@ -5316,12 +5311,29 @@ ip_route_ignored_protocol(const NMPlatformIPRoute *route) nm_assert(nmp_utils_ip_config_source_from_rtprot(prot) == route->rt_source); - /* We ignore all routes outside a certain subest of rtm_protocol. NetworkManager - * itself wouldn't configure those, so they are always configured by somebody - * external. We thus ignore them to avoid the overhead that processing them brings. - * For example, the BGP daemon "bird" might configure a huge number of RTPROT_BIRD routes. */ + if (prot > RTPROT_STATIC && !NM_IN_SET(prot, RTPROT_DHCP, RTPROT_RA)) { + /* We ignore certain rtm_protocol, because NetworkManager would only ever + * configure certain protocols. Other routes are not configured by NetworkManager + * and we don't track them in the platform cache. + * + * This is to help with the performance overhead of a huge number of + * routes, for example with the bird BGP software, that adds routes + * with RTPROT_BIRD protocol. */ + return FALSE; + } + + if (!NM_IN_SET(nm_platform_route_type_uncoerce(route->type_coerced), + RTN_UNICAST, + RTN_LOCAL, + RTN_BLACKHOLE, + RTN_UNREACHABLE, + RTN_PROHIBIT, + RTN_THROW)) { + /* Certain route types are ignored and not placed into the cache. */ + return FALSE; + } - return prot > RTPROT_STATIC && !NM_IN_SET(prot, RTPROT_DHCP, RTPROT_RA); + return TRUE; } /* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */ @@ -7825,6 +7837,7 @@ _rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg) gboolean resync_required = FALSE; gboolean only_dirty = FALSE; gboolean is_ipv6; + gboolean route_is_alive; /* IPv4 routes that are a response to RTM_GETROUTE must have * the cloned flag while IPv6 routes don't have to. */ @@ -7854,24 +7867,13 @@ _rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg) } } - if (ip_route_ignored_protocol(NMP_OBJECT_CAST_IP_ROUTE(obj))) { - /* We ignore certain rtm_protocol, because NetworkManager would only ever - * configure certain protocols. Other routes were not added by NetworkManager - * and we don't need to track them in the platform cache. - * - * This is to help with the performance overhead of a huge number of - * routes, for example with the bird BGP software, that adds routes - * with RTPROT_BIRD protocol. - * - * Even if this is a IPv6 multipath route, we abort (parse_nlmsg_iter). There - * is nothing for us to do. */ - return; - } + route_is_alive = ip_route_is_alive(NMP_OBJECT_CAST_IP_ROUTE(obj)); cache_op = nmp_cache_update_netlink_route(cache, obj, is_dump, msghdr->nlmsg_flags, + route_is_alive, &obj_old, &obj_new, &obj_replace, @@ -7918,6 +7920,8 @@ _rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg) delayed_action_schedule(platform, delayed_action_refresh_from_needle_object(obj), NULL); + /* We are done here. */ + return; } break; } @@ -10843,8 +10847,8 @@ constructed(GObject *_object) : (!nmp_netns_get_current() ? "no netns support" : nm_sprintf_bufa(100, - "in netns[%p]%s", - nmp_netns_get_current(), + "in netns[" NM_HASH_OBFUSCATE_PTR_FMT "]%s", + NM_HASH_OBFUSCATE_PTR(nmp_netns_get_current()), nmp_netns_get_current() == nmp_netns_get_initial() ? "/main" : "")), nm_platform_get_use_udev(platform) ? "use" : "no", @@ -10987,7 +10991,10 @@ path_is_read_only_fs(const char *path) } NMPlatform * -nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support, gboolean cache_tc) +nm_linux_platform_new(NMDedupMultiIndex *multi_idx, + gboolean log_with_ptr, + gboolean netns_support, + gboolean cache_tc) { gboolean use_udev = FALSE; @@ -10995,6 +11002,8 @@ nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support, gboolean ca use_udev = TRUE; return g_object_new(NM_TYPE_LINUX_PLATFORM, + NM_PLATFORM_MULTI_IDX, + multi_idx, NM_PLATFORM_LOG_WITH_PTR, log_with_ptr, NM_PLATFORM_USE_UDEV, diff --git a/src/libnm-platform/nm-linux-platform.h b/src/libnm-platform/nm-linux-platform.h index 546387a9d5..08135a4acb 100644 --- a/src/libnm-platform/nm-linux-platform.h +++ b/src/libnm-platform/nm-linux-platform.h @@ -23,6 +23,11 @@ typedef struct _NMLinuxPlatformClass NMLinuxPlatformClass; GType nm_linux_platform_get_type(void); -NMPlatform *nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support, gboolean cache_tc); +struct _NMDedupMultiIndex; + +NMPlatform *nm_linux_platform_new(struct _NMDedupMultiIndex *multi_idx, + gboolean log_with_ptr, + gboolean netns_support, + gboolean cache_tc); #endif /* __NETWORKMANAGER_LINUX_PLATFORM_H__ */ diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 85bd785ac8..6fad736cce 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -115,28 +115,32 @@ nmp_link_address_get_as_bytes(const NMPLinkAddress *addr) #define _NMLOG_DOMAIN LOGD_PLATFORM #define _NMLOG_PREFIX_NAME "platform" -#define NMLOG_COMMON(level, name, ...) \ - G_STMT_START \ - { \ - char __prefix[32]; \ - const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - const NMPlatform *const __self = (self); \ - const char *__name = name; \ - \ - if (__self && NM_PLATFORM_GET_PRIVATE(__self)->log_with_ptr) { \ - g_snprintf(__prefix, sizeof(__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ - __p_prefix = __prefix; \ - } \ - _nm_log((level), \ - _NMLOG_DOMAIN, \ - 0, \ - __name, \ - NULL, \ - "%s: %s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __p_prefix, \ - NM_PRINT_FMT_QUOTED(__name, "(", __name, ") ", "") \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ +#define NMLOG_COMMON(level, name, ...) \ + G_STMT_START \ + { \ + char __prefix[64]; \ + const char *__p_prefix = _NMLOG_PREFIX_NAME; \ + const NMPlatform *const __self = (self); \ + const char *__name = name; \ + \ + if (__self && NM_PLATFORM_GET_PRIVATE(__self)->log_with_ptr) { \ + g_snprintf(__prefix, \ + sizeof(__prefix), \ + "%s[" NM_HASH_OBFUSCATE_PTR_FMT "]", \ + _NMLOG_PREFIX_NAME, \ + NM_HASH_OBFUSCATE_PTR(__self)); \ + __p_prefix = __prefix; \ + } \ + _nm_log((level), \ + _NMLOG_DOMAIN, \ + 0, \ + __name, \ + NULL, \ + "%s: %s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __p_prefix, \ + NM_PRINT_FMT_QUOTED(__name, "(", __name, ") ", "") \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ G_STMT_END #define _NMLOG(level, ...) \ @@ -180,6 +184,7 @@ static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = {0}; enum { PROP_0, + PROP_MULTI_IDX, PROP_NETNS_SUPPORT, PROP_USE_UDEV, PROP_LOG_WITH_PTR, @@ -9617,6 +9622,20 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self); switch (prop_id) { + case PROP_MULTI_IDX: + /* construct-only */ + { + NMDedupMultiIndex *multi_idx; + + multi_idx = g_value_get_pointer(value); + if (!multi_idx) + multi_idx = nm_dedup_multi_index_new(); + else + multi_idx = nm_dedup_multi_index_ref(multi_idx); + + priv->multi_idx = multi_idx; + break; + } case PROP_NETNS_SUPPORT: /* construct-only */ if (g_value_get_boolean(value)) { @@ -9663,8 +9682,9 @@ constructor(GType type, guint n_construct_params, GObjectConstructParam *constru self = NM_PLATFORM(object); priv = NM_PLATFORM_GET_PRIVATE(self); - priv->multi_idx = nm_dedup_multi_index_new(); - priv->cache = nmp_cache_new(priv->multi_idx, priv->use_udev); + nm_assert(priv->multi_idx); + + priv->cache = nmp_cache_new(priv->multi_idx, priv->use_udev); c_list_init(&priv->ip6_dadfailed_lst_head); return object; @@ -9706,6 +9726,14 @@ nm_platform_class_init(NMPlatformClass *platform_class) g_object_class_install_property( object_class, + PROP_MULTI_IDX, + g_param_spec_pointer(NM_PLATFORM_MULTI_IDX, + "", + "", + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property( + object_class, PROP_NETNS_SUPPORT, g_param_spec_boolean(NM_PLATFORM_NETNS_SUPPORT, "", diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index ea46321534..dec38c1c93 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -23,10 +23,11 @@ /*****************************************************************************/ +#define NM_PLATFORM_CACHE_TC "cache-tc" +#define NM_PLATFORM_LOG_WITH_PTR "log-with-ptr" +#define NM_PLATFORM_MULTI_IDX "multi-idx" #define NM_PLATFORM_NETNS_SUPPORT "netns-support" #define NM_PLATFORM_USE_UDEV "use-udev" -#define NM_PLATFORM_LOG_WITH_PTR "log-with-ptr" -#define NM_PLATFORM_CACHE_TC "cache-tc" /*****************************************************************************/ diff --git a/src/libnm-platform/nmp-netns.c b/src/libnm-platform/nmp-netns.c index 864e30e94f..c18f67ab1b 100644 --- a/src/libnm-platform/nmp-netns.c +++ b/src/libnm-platform/nmp-netns.c @@ -66,26 +66,28 @@ __ns_types_to_str(int ns_types, int ns_types_already_set, char *buf, gsize len) #define _NMLOG_DOMAIN LOGD_PLATFORM #define _NMLOG_PREFIX_NAME "netns" -#define _NMLOG(level, netns, ...) \ - G_STMT_START \ - { \ - NMLogLevel _level = (level); \ - \ - if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \ - NMPNetns *_netns = (netns); \ - char _sbuf[20]; \ - \ - _nm_log(_level, \ - _NMLOG_DOMAIN, \ - 0, \ - NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - (_netns ? nm_sprintf_buf(_sbuf, "[%p]", _netns) \ - : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ +#define _NMLOG(level, netns, ...) \ + G_STMT_START \ + { \ + NMLogLevel _level = (level); \ + \ + if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \ + NMPNetns *_netns = (netns); \ + char _sbuf[32]; \ + \ + _nm_log(_level, \ + _NMLOG_DOMAIN, \ + 0, \ + NULL, \ + NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + (_netns ? nm_sprintf_buf(_sbuf, \ + "[" NM_HASH_OBFUSCATE_PTR_FMT "]", \ + NM_HASH_OBFUSCATE_PTR(_netns)) \ + : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ G_STMT_END /*****************************************************************************/ diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index e510685b01..9ba027ba95 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -2336,19 +2336,23 @@ nmp_lookup_init_route_by_weak_id(NMPLookup *lookup, const NMPObject *obj) switch (NMP_OBJECT_GET_TYPE(obj)) { case NMP_OBJECT_TYPE_IP4_ROUTE: r4 = NMP_OBJECT_CAST_IP4_ROUTE(obj); - return nmp_lookup_init_ip4_route_by_weak_id(lookup, - r4->network, - r4->plen, - r4->metric, - r4->tos); + return nmp_lookup_init_ip4_route_by_weak_id( + lookup, + nm_platform_route_table_uncoerce(r4->table_coerced, TRUE), + r4->network, + r4->plen, + r4->metric, + r4->tos); case NMP_OBJECT_TYPE_IP6_ROUTE: r6 = NMP_OBJECT_CAST_IP6_ROUTE(obj); - return nmp_lookup_init_ip6_route_by_weak_id(lookup, - &r6->network, - r6->plen, - r6->metric, - &r6->src, - r6->src_plen); + return nmp_lookup_init_ip6_route_by_weak_id( + lookup, + nm_platform_route_table_uncoerce(r6->table_coerced, TRUE), + &r6->network, + r6->plen, + r6->metric, + &r6->src, + r6->src_plen); default: nm_assert_not_reached(); return NULL; @@ -2357,6 +2361,7 @@ nmp_lookup_init_route_by_weak_id(NMPLookup *lookup, const NMPObject *obj) const NMPLookup * nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup, + guint32 route_table, in_addr_t network, guint plen, guint32 metric, @@ -2367,9 +2372,10 @@ nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup, nm_assert(lookup); o = _nmp_object_stackinit_from_type(&lookup->selector_obj, NMP_OBJECT_TYPE_IP4_ROUTE); - o->ip4_route.ifindex = 1; - o->ip4_route.plen = plen; - o->ip4_route.metric = metric; + o->ip4_route.ifindex = 1; + o->ip4_route.plen = plen; + o->ip4_route.table_coerced = nm_platform_route_table_coerce(route_table); + o->ip4_route.metric = metric; if (network) o->ip4_route.network = network; o->ip4_route.tos = tos; @@ -2379,6 +2385,7 @@ nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup, const NMPLookup * nmp_lookup_init_ip6_route_by_weak_id(NMPLookup *lookup, + guint32 route_table, const struct in6_addr *network, guint plen, guint32 metric, @@ -2390,9 +2397,10 @@ nmp_lookup_init_ip6_route_by_weak_id(NMPLookup *lookup, nm_assert(lookup); o = _nmp_object_stackinit_from_type(&lookup->selector_obj, NMP_OBJECT_TYPE_IP6_ROUTE); - o->ip6_route.ifindex = 1; - o->ip6_route.plen = plen; - o->ip6_route.metric = metric; + o->ip6_route.ifindex = 1; + o->ip6_route.plen = plen; + o->ip6_route.table_coerced = nm_platform_route_table_coerce(route_table); + o->ip6_route.metric = metric; if (network) o->ip6_route.network = *network; if (src) @@ -2951,6 +2959,7 @@ nmp_cache_update_netlink_route(NMPCache *cache, NMPObject *obj_hand_over, gboolean is_dump, guint16 nlmsgflags, + gboolean route_is_alive, const NMPObject **out_obj_old, const NMPObject **out_obj_new, const NMPObject **out_obj_replace, @@ -2969,30 +2978,60 @@ nmp_cache_update_netlink_route(NMPCache *cache, nm_assert(cache); nm_assert(NMP_OBJECT_IS_VALID(obj_hand_over)); nm_assert(!NMP_OBJECT_IS_STACKINIT(obj_hand_over)); - /* A link object from netlink must have the udev related fields unset. - * We could implement to handle that, but there is no need to support such - * a use-case */ nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_hand_over), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); nm_assert(nm_dedup_multi_index_obj_find(cache->multi_idx, obj_hand_over) != obj_hand_over); + if (NM_FLAGS_HAS(nlmsgflags, NLM_F_REPLACE)) { + /* This means, that the message indicates that another route was replaced. + * Since we don't cache all routes (see "route_is_alive"), we cannot know + * with certainty which route was replaced. + * + * Even if we would cache *all* routes (which we cannot, if kernel adds new + * routing features that modify the known nmp_object_id_equal()), it would + * be hard to find the right route that was replaced. Well, probably we + * would have to keep NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID sorted by order + * of notifications, which is hard. The code below actually makes an effort + * to do that, but it's not actually used, because we just resync. + * + * The only proper solution for this would be to improve kernel with [1] + * and [2]. + * + * [1] https://bugzilla.redhat.com/show_bug.cgi?id=1337855 + * [2] https://bugzilla.redhat.com/show_bug.cgi?id=1337860 + * + * We need to resync. + */ + if (NMP_OBJECT_GET_TYPE(obj_hand_over) == NMP_OBJECT_TYPE_IP4_ROUTE + && !nmp_cache_lookup_all(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, obj_hand_over)) { + /* For IPv4, we can do a small optimization. We skip the resync, if we have + * no conflicting routes (by weak-id). + * + * This optimization does not work for IPv6 (maybe should be fixed). + */ + } else { + entry_replace = NULL; + resync_required = TRUE; + goto out; + } + } + entry_old = _lookup_entry(cache, obj_hand_over); entry_new = NULL; NM_SET_OUT(out_obj_old, nmp_object_ref(nm_dedup_multi_entry_get_obj(entry_old))); - if (!entry_old) { - if (!nmp_object_is_alive(obj_hand_over)) - goto update_done; + is_alive = route_is_alive && nmp_object_is_alive(obj_hand_over); - _idxcache_update(cache, NULL, obj_hand_over, is_dump, &entry_new); - ops_type = NMP_CACHE_OPS_ADDED; + if (!entry_old) { + if (is_alive) { + _idxcache_update(cache, NULL, obj_hand_over, is_dump, &entry_new); + ops_type = NMP_CACHE_OPS_ADDED; + } goto update_done; } - is_alive = nmp_object_is_alive(obj_hand_over); - if (!is_alive) { /* the update would make @entry_old invalid. Remove it. */ _idxcache_update(cache, entry_old, NULL, FALSE, NULL); @@ -3025,19 +3064,11 @@ update_done: if (is_dump) goto out; - if (!entry_new) { - if (NM_FLAGS_HAS(nlmsgflags, NLM_F_REPLACE) - && nmp_cache_lookup_all(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, obj_hand_over)) { - /* hm. @obj_hand_over was not added, meaning it was not alive. - * However, we track some other objects with the same weak-id. - * It's unclear what that means. To be sure, resync. */ - resync_required = TRUE; - } + if (!entry_new) goto out; - } - /* FIXME: for routes, we only maintain the order correctly for the BY_WEAK_ID - * index. For all other indexes their order becomes messed up. */ + /* For routes, we only maintain the order correctly for the BY_WEAK_ID + * index. For all other indexes, their order is not preserved. */ entry_cur = _lookup_entry_with_idx_type(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, entry_new->obj); if (!entry_cur) { diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index dcf431255e..0d5f84b310 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -561,6 +561,8 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) return FALSE; } +#define NMP_OBJECT_TYPE_NAME(obj_type) (nmp_class_from_type(obj_type)->obj_type_name) + #define NMP_OBJECT_CAST_OBJECT(obj) \ ({ \ typeof(obj) _obj = (obj); \ @@ -869,11 +871,13 @@ nmp_lookup_init_object_by_ifindex(NMPLookup *lookup, NMPObjectType obj_type, int const NMPLookup *nmp_lookup_init_route_default(NMPLookup *lookup, NMPObjectType obj_type); const NMPLookup *nmp_lookup_init_route_by_weak_id(NMPLookup *lookup, const NMPObject *obj); const NMPLookup *nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup, + guint32 route_table, in_addr_t network, guint plen, guint32 metric, guint8 tos); const NMPLookup *nmp_lookup_init_ip6_route_by_weak_id(NMPLookup *lookup, + guint32 route_table, const struct in6_addr *network, guint plen, guint32 metric, @@ -971,6 +975,7 @@ NMPCacheOpsType nmp_cache_update_netlink_route(NMPCache *cache, NMPObject *obj_hand_over, gboolean is_dump, guint16 nlmsgflags, + gboolean route_is_alive, const NMPObject **out_obj_old, const NMPObject **out_obj_new, const NMPObject **out_obj_replace, @@ -1132,6 +1137,7 @@ nm_platform_lookup_route_default_clone(NMPlatform *platform, static inline const NMDedupMultiHeadEntry * nm_platform_lookup_ip4_route_by_weak_id(NMPlatform *platform, + guint32 route_table, in_addr_t network, guint plen, guint32 metric, @@ -1139,12 +1145,13 @@ nm_platform_lookup_ip4_route_by_weak_id(NMPlatform *platform, { NMPLookup lookup; - nmp_lookup_init_ip4_route_by_weak_id(&lookup, network, plen, metric, tos); + nmp_lookup_init_ip4_route_by_weak_id(&lookup, route_table, network, plen, metric, tos); return nm_platform_lookup(platform, &lookup); } static inline const NMDedupMultiHeadEntry * nm_platform_lookup_ip6_route_by_weak_id(NMPlatform *platform, + guint32 route_table, const struct in6_addr *network, guint plen, guint32 metric, @@ -1153,7 +1160,13 @@ nm_platform_lookup_ip6_route_by_weak_id(NMPlatform *platform, { NMPLookup lookup; - nmp_lookup_init_ip6_route_by_weak_id(&lookup, network, plen, metric, src, src_plen); + nmp_lookup_init_ip6_route_by_weak_id(&lookup, + route_table, + network, + plen, + metric, + src, + src_plen); return nm_platform_lookup(platform, &lookup); } |