mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-04-22 05:50:49 +02:00
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
This commit is contained in:
commit
adad1d4358
19 changed files with 930 additions and 240 deletions
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1232,6 +1232,7 @@ ip_route_add(NMPlatform *platform, NMPNlmFlags flags, NMPObject *obj_stack)
|
|||
obj,
|
||||
FALSE,
|
||||
nlmsgflags,
|
||||
TRUE,
|
||||
&obj_old,
|
||||
&obj_new,
|
||||
&obj_replace,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
nmtst_test_data_unpack(test_data, &p_ifindex, NULL, NULL, NULL, NULL);
|
||||
|
||||
g_assert_cmpint(NMTSTP_ENV1_IFINDEX, ==, *p_ifindex);
|
||||
NMTSTP_ENV1_IFINDEX = -1;
|
||||
int *p_ifindexes;
|
||||
gpointer p_n_ifaces;
|
||||
int n_ifaces;
|
||||
int i;
|
||||
|
||||
_LOGT("TEST[%s]: teardown", test_data->testpath);
|
||||
|
||||
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));
|
||||
nmtst_test_data_unpack(test_data, &p_ifindexes, &p_n_ifaces, NULL, NULL, NULL, 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));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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__}; \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
return prot > RTPROT_STATIC && !NM_IN_SET(prot, RTPROT_DHCP, RTPROT_RA);
|
||||
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 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,
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -9704,6 +9724,14 @@ nm_platform_class_init(NMPlatformClass *platform_class)
|
|||
|
||||
platform_class->wifi_set_powersave = wifi_set_powersave;
|
||||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue