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.
This commit is contained in:
Thomas Haller 2023-01-25 16:51:46 +01:00
parent 26592ebfe5
commit e99433866d
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728

View file

@ -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;
}