NetworkManager/src/libnm-platform/tests/test-nm-platform.c
Rahul Rajesh 6b5e216623 platform: add support for GENEVE tunnels
GENEVE (Generic Network Virtualization Encapsulation) is a network
tunneling protocol that provides a flexible encapsulation format for
overlay networks. It uses UDP as the transport protocol and supports
variable-length metadata in the tunnel header.

This patch adds GENEVE tunnel to NM's platform layer:

- Add platform API functions (nm_platform_link_geneve_add,
  nm_platform_link_get_lnk_geneve)

- Netlink message parsing for the following attributes:
  * IFLA_GENEVE_ID - VNI (Virtual Network Identifier)
  IPv4 and IPv6 remote
  * IFLA_GENEVE_REMOTE
  * IFLA_GENEVE_REMOTE6
  TTL, TOS, and DF flags
  * IFLA_GENEVE_TTL
  * IFLA_GENEVE_TOS
  * IFLA_GENEVE_DF
  UDP destination port
  * IFLA_GENEVE_PORT

- Add test cases for GENEVE tunnel creation and detection with two test
  modes covering IPv4 and IPv6.

The implementation tries to follow the same patterns as other tunnel
types (GRE, VXLAN, etc.) and integrates with the existing platform
abstraction layer.

(cherry picked from commit 29c8bbe21a)
(cherry picked from commit b071b0fafa)
2026-05-13 11:39:54 +02:00

496 lines
19 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "libnm-glib-aux/nm-default-glib-i18n-prog.h"
#include "libnm-log-core/nm-logging.h"
#include "libnm-platform/nm-netlink.h"
#include "libnm-platform/nmp-netns.h"
#include "libnm-platform/nm-platform-utils.h"
#include "libnm-platform/nmp-object.h"
#include "libnm-glib-aux/nm-test-utils.h"
/*****************************************************************************/
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectIP4Address));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectIP4Route));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectIP6Address));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectIP6Route));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLink));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkBond));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkBridge));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkGeneve));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkGre));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkInfiniband));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkIp6Tnl));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkIpIp));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkMacsec));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkMacvlan));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkSit));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkTun));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkVlan));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkVrf));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkVti));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkVti6));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkVxlan));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkWireGuard));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectQdisc));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectRoutingRule));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectTfilter));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIP4Address));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIP4Route));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIP6Address));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIP6Route));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIPAddress));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIPAddress));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIPRoute));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIPXAddress));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIPXRoute));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLink));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkBond));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkBridge));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkGeneve));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkGre));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkInfiniband));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkIp6Tnl));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkIpIp));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkMacsec));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkMacvlan));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkSit));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkTun));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkVlan));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkVrf));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkVti));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkVti6));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkVxlan));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkWireGuard));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformObjWithIfindex));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformQdisc));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformRoutingRule));
G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformTfilter));
/*****************************************************************************/
static void
test_use_symbols(void)
{
static void (*const SYMBOLS[])(void) = {
(void (*)(void)) nl_nlmsghdr_to_str,
(void (*)(void)) nlmsg_hdr,
(void (*)(void)) nlmsg_reserve,
(void (*)(void)) nla_reserve,
(void (*)(void)) nlmsg_alloc_convert,
(void (*)(void)) nlmsg_alloc_new,
(void (*)(void)) nlmsg_alloc,
(void (*)(void)) nlmsg_free,
(void (*)(void)) nlmsg_append,
(void (*)(void)) nlmsg_parse,
(void (*)(void)) nlmsg_put,
(void (*)(void)) nla_strlcpy,
(void (*)(void)) nla_memcpy,
(void (*)(void)) nla_put,
(void (*)(void)) nla_find,
(void (*)(void)) nla_nest_cancel,
(void (*)(void)) nla_nest_start,
(void (*)(void)) nla_nest_end,
(void (*)(void)) nla_parse,
(void (*)(void)) nlmsg_get_proto,
(void (*)(void)) nlmsg_set_proto,
(void (*)(void)) nlmsg_set_src,
(void (*)(void)) nlmsg_get_creds,
(void (*)(void)) nlmsg_set_creds,
(void (*)(void)) genlmsg_put,
(void (*)(void)) genlmsg_data,
(void (*)(void)) genlmsg_user_hdr,
(void (*)(void)) genlmsg_hdr,
(void (*)(void)) genlmsg_user_data,
(void (*)(void)) genlmsg_attrdata,
(void (*)(void)) genlmsg_len,
(void (*)(void)) genlmsg_attrlen,
(void (*)(void)) genlmsg_valid_hdr,
(void (*)(void)) genlmsg_parse,
(void (*)(void)) genl_ctrl_resolve,
(void (*)(void)) nl_socket_new,
(void (*)(void)) nl_socket_free,
(void (*)(void)) nl_socket_get_fd,
(void (*)(void)) nl_socket_get_local_port,
(void (*)(void)) nl_socket_get_msg_buf_size,
(void (*)(void)) nl_socket_set_passcred,
(void (*)(void)) nl_socket_set_msg_buf_size,
(void (*)(void)) nlmsg_get_dst,
(void (*)(void)) nl_socket_set_buffer_size,
(void (*)(void)) nl_socket_add_memberships,
(void (*)(void)) nl_wait_for_ack,
(void (*)(void)) nl_recvmsgs,
(void (*)(void)) nl_sendmsg,
(void (*)(void)) nl_send_iovec,
(void (*)(void)) nl_complete_msg,
(void (*)(void)) nl_send,
(void (*)(void)) nl_send_auto,
(void (*)(void)) nl_recv,
(void (*)(void)) nmp_netns_bind_to_path,
(void (*)(void)) nmp_netns_bind_to_path_destroy,
(void (*)(void)) nmp_netns_get_current,
(void (*)(void)) nmp_netns_get_fd_mnt,
(void (*)(void)) nmp_netns_get_fd_net,
(void (*)(void)) nmp_netns_get_initial,
(void (*)(void)) nmp_netns_is_initial,
(void (*)(void)) nmp_netns_new,
(void (*)(void)) nmp_netns_pop,
(void (*)(void)) nmp_netns_push,
(void (*)(void)) nmp_netns_push_type,
NULL,
};
/* The only (not very exciting) purpose of this test is to see that
* we can use various symbols and don't get a linker error. */
assert(G_N_ELEMENTS(SYMBOLS) == NM_PTRARRAY_LEN(SYMBOLS) + 1);
}
/*****************************************************************************/
static void
test_nmp_link_mode_all_advertised_modes_bits(void)
{
guint32 flags[(SCHAR_MAX + 1) / 32];
guint max_bit;
int i;
memset(flags, 0, sizeof(flags));
max_bit = 0;
for (i = 0; i < (int) G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes_bits); i++) {
if (i > 0) {
g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i - 1],
<,
_nmp_link_mode_all_advertised_modes_bits[i]);
}
g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i], <, SCHAR_MAX);
g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i] / 32, <, G_N_ELEMENTS(flags));
flags[_nmp_link_mode_all_advertised_modes_bits[i] / 32] |=
(1u << (_nmp_link_mode_all_advertised_modes_bits[i] % 32u));
max_bit = NM_MAX(max_bit, _nmp_link_mode_all_advertised_modes_bits[i]);
}
g_assert_cmpint((max_bit + 31u) / 32u, ==, G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes));
for (i = 0; i < (int) G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes); i++) {
if (flags[i] != _nmp_link_mode_all_advertised_modes[i]) {
NM_PRAGMA_WARNING_DISABLE_DANGLING_POINTER
g_error("_nmp_link_mode_all_advertised_modes[%d] should be 0x%0x but is 0x%0x "
"(according to the bits in _nmp_link_mode_all_advertised_modes_bits)",
i,
flags[i],
_nmp_link_mode_all_advertised_modes[i]);
NM_PRAGMA_WARNING_REENABLE
}
}
}
/*****************************************************************************/
static void
test_nmp_utils_bridge_vlans_normalize(void)
{
NMPlatformBridgeVlan vlans[10];
NMPlatformBridgeVlan expect[10];
guint vlans_len;
/* Single one is unmodified */
vlans[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 10,
.untagged = TRUE,
};
expect[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 10,
.untagged = TRUE,
};
vlans_len = 1;
nmp_utils_bridge_vlan_normalize(vlans, &vlans_len);
g_assert(vlans_len == 1);
g_assert(nmp_utils_bridge_normalized_vlans_equal(vlans, vlans_len, expect, vlans_len));
/* Not merged if flags are different */
vlans[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 10,
.untagged = TRUE,
};
vlans[1] = (NMPlatformBridgeVlan) {
.vid_start = 11,
.vid_end = 11,
.pvid = TRUE,
};
vlans[2] = (NMPlatformBridgeVlan) {
.vid_start = 20,
.vid_end = 25,
};
vlans[3] = (NMPlatformBridgeVlan) {
.vid_start = 26,
.vid_end = 30,
.untagged = TRUE,
};
vlans[4] = (NMPlatformBridgeVlan) {
.vid_start = 40,
.vid_end = 40,
.untagged = TRUE,
};
vlans[5] = (NMPlatformBridgeVlan) {
.vid_start = 40,
.vid_end = 40,
.untagged = TRUE,
.pvid = TRUE,
};
expect[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 10,
.untagged = TRUE,
};
expect[1] = (NMPlatformBridgeVlan) {
.vid_start = 11,
.vid_end = 11,
.pvid = TRUE,
};
expect[2] = (NMPlatformBridgeVlan) {
.vid_start = 20,
.vid_end = 25,
};
expect[3] = (NMPlatformBridgeVlan) {
.vid_start = 26,
.vid_end = 30,
.untagged = TRUE,
};
expect[4] = (NMPlatformBridgeVlan) {
.vid_start = 40,
.vid_end = 40,
.untagged = TRUE,
};
expect[5] = (NMPlatformBridgeVlan) {
.vid_start = 40,
.vid_end = 40,
.untagged = TRUE,
.pvid = TRUE,
};
vlans_len = 6;
nmp_utils_bridge_vlan_normalize(vlans, &vlans_len);
g_assert(vlans_len == 6);
g_assert(nmp_utils_bridge_normalized_vlans_equal(vlans, vlans_len, expect, vlans_len));
/* Overlapping and contiguous ranges are merged */
vlans[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 10,
.untagged = TRUE,
};
vlans[1] = (NMPlatformBridgeVlan) {
.vid_start = 11,
.vid_end = 20,
.untagged = TRUE,
};
vlans[2] = (NMPlatformBridgeVlan) {
.vid_start = 19,
.vid_end = 30,
.untagged = TRUE,
};
expect[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 30,
.untagged = TRUE,
};
vlans_len = 3;
nmp_utils_bridge_vlan_normalize(vlans, &vlans_len);
g_assert(vlans_len == 1);
g_assert(nmp_utils_bridge_normalized_vlans_equal(vlans, vlans_len, expect, vlans_len));
vlans[0] = (NMPlatformBridgeVlan) {
.vid_start = 20,
.vid_end = 20,
};
vlans[1] = (NMPlatformBridgeVlan) {
.vid_start = 4,
.vid_end = 4,
.pvid = TRUE,
};
vlans[2] = (NMPlatformBridgeVlan) {
.vid_start = 33,
.vid_end = 33,
};
vlans[3] = (NMPlatformBridgeVlan) {
.vid_start = 100,
.vid_end = 100,
.untagged = TRUE,
};
vlans[4] = (NMPlatformBridgeVlan) {
.vid_start = 34,
.vid_end = 40,
};
vlans[5] = (NMPlatformBridgeVlan) {
.vid_start = 21,
.vid_end = 32,
};
expect[0] = (NMPlatformBridgeVlan) {
.vid_start = 4,
.vid_end = 4,
.pvid = TRUE,
};
expect[1] = (NMPlatformBridgeVlan) {
.vid_start = 20,
.vid_end = 40,
};
expect[2] = (NMPlatformBridgeVlan) {
.vid_start = 100,
.vid_end = 100,
.untagged = TRUE,
};
vlans_len = 6;
nmp_utils_bridge_vlan_normalize(vlans, &vlans_len);
g_assert(vlans_len == 3);
g_assert(nmp_utils_bridge_normalized_vlans_equal(vlans, vlans_len, expect, vlans_len));
}
static void
test_nmp_utils_bridge_normalized_vlans_equal(void)
{
NMPlatformBridgeVlan a[10];
NMPlatformBridgeVlan b[10];
/* Both empty */
g_assert(nmp_utils_bridge_normalized_vlans_equal(NULL, 0, NULL, 0));
g_assert(nmp_utils_bridge_normalized_vlans_equal(a, 0, b, 0));
g_assert(nmp_utils_bridge_normalized_vlans_equal(a, 0, NULL, 0));
g_assert(nmp_utils_bridge_normalized_vlans_equal(NULL, 0, b, 0));
/* One empty, other not */
a[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 10,
.untagged = TRUE,
};
g_assert(!nmp_utils_bridge_normalized_vlans_equal(a, 1, NULL, 0));
g_assert(!nmp_utils_bridge_normalized_vlans_equal(NULL, 0, a, 1));
/* Equal range + VLAN */
a[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 10,
.untagged = TRUE,
};
a[1] = (NMPlatformBridgeVlan) {
.vid_start = 11,
.vid_end = 11,
.pvid = TRUE,
};
b[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 10,
.untagged = TRUE,
};
b[1] = (NMPlatformBridgeVlan) {
.vid_start = 11,
.vid_end = 11,
.pvid = TRUE,
};
g_assert(nmp_utils_bridge_normalized_vlans_equal(a, 2, b, 2));
g_assert(nmp_utils_bridge_normalized_vlans_equal(b, 2, a, 2));
/* Different flag */
b[1].pvid = FALSE;
g_assert(!nmp_utils_bridge_normalized_vlans_equal(a, 2, b, 2));
g_assert(!nmp_utils_bridge_normalized_vlans_equal(b, 2, a, 2));
/* Different ranges */
a[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 30,
.untagged = TRUE,
};
b[0] = (NMPlatformBridgeVlan) {
.vid_start = 1,
.vid_end = 29,
.untagged = TRUE,
};
g_assert(!nmp_utils_bridge_normalized_vlans_equal(a, 1, b, 1));
g_assert(!nmp_utils_bridge_normalized_vlans_equal(b, 1, a, 1));
b[0].vid_start = 2;
b[0].vid_end = 30;
g_assert(!nmp_utils_bridge_normalized_vlans_equal(a, 1, b, 1));
g_assert(!nmp_utils_bridge_normalized_vlans_equal(b, 1, a, 1));
}
/*****************************************************************************/
static void
test_nmpclass_consistency(void)
{
NMPObjectType obj_type;
NMPObjectType obj_type2;
G_STATIC_ASSERT(G_N_ELEMENTS(_nmp_classes) == NMP_OBJECT_TYPE_MAX);
for (obj_type = 1; obj_type <= NMP_OBJECT_TYPE_MAX; obj_type++) {
const NMPClass *klass = nmp_class_from_type(obj_type);
gboolean is_lnk;
g_assert(klass);
g_assert(klass == &_nmp_classes[obj_type - 1]);
g_assert_cmpint(klass->obj_type, ==, obj_type);
g_assert(klass->obj_type_name);
g_assert((!!klass->cmd_obj_cmp) == (!!klass->cmd_obj_hash_update));
g_assert((!!klass->cmd_plobj_cmp) == (!!klass->cmd_plobj_hash_update));
g_assert((!!klass->cmd_plobj_id_cmp) == (!!klass->cmd_plobj_id_hash_update));
g_assert((!!klass->cmd_obj_cmp) != (!!klass->cmd_plobj_cmp));
g_assert((!!klass->cmd_obj_hash_update) != (!!klass->cmd_plobj_hash_update));
g_assert((!klass->cmd_obj_cmp) || (!klass->cmd_plobj_id_cmp));
g_assert((!klass->cmd_obj_hash_update) || (!klass->cmd_plobj_id_hash_update));
g_assert_cmpint(klass->sizeof_public, >, 0);
g_assert_cmpint(klass->sizeof_data, >=, klass->sizeof_public);
g_assert((!!klass->cmd_obj_to_string) != (!!klass->cmd_plobj_to_string));
g_assert(!klass->cmd_plobj_to_string_id || klass->cmd_plobj_to_string);
is_lnk = (obj_type >= NMP_OBJECT_TYPE_LNK_BRIDGE && obj_type <= NMP_OBJECT_TYPE_LNK_BOND);
if (klass->lnk_link_type == NM_LINK_TYPE_NONE) {
G_STATIC_ASSERT(NM_LINK_TYPE_NONE == 0);
g_assert(!is_lnk);
} else
g_assert(is_lnk);
for (obj_type2 = 1; obj_type2 < obj_type; obj_type2++) {
const NMPClass *klass2 = nmp_class_from_type(obj_type2);
g_assert_cmpstr(klass->obj_type_name, !=, klass2->obj_type_name);
}
}
}
/*****************************************************************************/
NMTST_DEFINE();
int
main(int argc, char **argv)
{
nmtst_init(&argc, &argv, TRUE);
g_test_add_func("/nm-platform/test_use_symbols", test_use_symbols);
g_test_add_func("/nm-platform/test_nmp_link_mode_all_advertised_modes_bits",
test_nmp_link_mode_all_advertised_modes_bits);
g_test_add_func("/nm-platform/test_nmpclass_consistency", test_nmpclass_consistency);
g_test_add_func("/nm-platform/test_nmp_utils_bridge_vlans_normalize",
test_nmp_utils_bridge_vlans_normalize);
g_test_add_func("/nm-platform/nmp-utils-bridge-vlans-equal",
test_nmp_utils_bridge_normalized_vlans_equal);
return g_test_run();
}