From e99433866d3d79a5e75947d396f705f2f8cbb6b3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 25 Jan 2023 16:51:46 +0100 Subject: [PATCH] platform/tests: ignore ip-tunnel interfaces in nmtstp_assert_platform() Certain ip-tunnel modules automatically create network interfaces (for example, "ip_gre" module creates "gre0" and others). Btw, that's not the same as `modprobe bonding max_bonds=1`, where loading the module merely automatically creates a "bond0" interface. In case of ip tunnel modules, these generated interfaces seem essential to how the tunnel works, for example they cannot be deleted. I don't understand the purpose of those interfaces, but they seem not just regular tunnel interfaces (unlike, "bond0" which is a regular bond interface, albeit automatically created). Btw, if at the time when loading the module, an interface with such name already exists, it will bump the name (for example, adding a "gre1" interfaces, and so on). That adds to the ugliness of the whole thing, but for our unit tests, that is no problem. Our unit tests run in a separate netns, and we don't create conflicting interfaces. That is, an interface named "gre0" is always the special tunnel interface and we can/do rely on that. Note that when the kernel module gets loaded, it adds those interfaces to all netns. Thus, even if "test-route-linux" does not do anything with ip tunnels, such an interface can always appear in a netns, simply by running "test-link-linux" (or any other tool that creates a tunnel) in parallel or even in another container. Theoretically, we could just ensure that we load all the conflicting ip-tunnel modules (with nmtstp_ensure_module()). There there are two problems. First, there might be other tunnel modules that interfere but are not covered by nmtstp_ensure_module(). Second, when kernel creates those interfaces, it does not send correct RTM_NEWLINK notifications (a bug), so our platform cache will not be correct, and nmtstp_assert_platform() will fail. The only solution is to detect and ignore those interfaces. Also, ignore all interfaces of link-type "unknown". Those might be from other modules that we don't know about and that exhibit the same problem. --- src/core/platform/tests/test-common.c | 53 ++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index 18098234c8..8064ea4392 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -858,23 +858,56 @@ _assert_platform_normalize_all(GPtrArray *arr) gboolean normalized = FALSE; for (i = 0; i < nm_g_ptr_array_len(arr); i++) { - const NMPObject **ptr = (gpointer) &arr->pdata[i]; - NMPObject *new; + const NMPObject **ptr = (gpointer) &arr->pdata[i]; + nm_auto_nmpobj NMPObject *new = NULL; + gboolean skip = FALSE; 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; + { + const NMPlatformLink *link = NMP_OBJECT_CAST_LINK(*ptr); + + if (nmtstp_link_is_iptunnel_special(link)) { + /* These are special interfaces for the ip tunnel modules, like + * "gre0" created by the "ip_gre" module. + * + * These interfaces can appear at any moment, when the module + * gets loaded (by anybody on the host). We might want to avoid + * that by calling nmtstp_ensure_module(), but it's worse. + * Kernel does not send correct RTM_NEWLINK events when those + * interfaces get created. So the cache content based on the + * events will differ from a new load from a dump. + * + * We need to ignore those interfaces. */ + skip = TRUE; + } else if (link->type == NM_LINK_TYPE_UNKNOWN) { + /* The link type is not detected. This might be a generated + * interface like nmtstp_link_is_iptunnel_special(), but for + * kernel modules that we don't know about. Ignore them too. */ + skip = TRUE; + } + + if (!skip) { + 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; + } + if (nmp_object_ref_set(ptr, new)) + normalized = TRUE; + break; + } default: break; } } + + while (g_ptr_array_remove(arr, NULL)) { + /* Remove NULL values. */ + normalized = TRUE; + } + return normalized; }