mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-28 21:30:10 +01:00
For GBytes, GEnum, GFlags and others, we need special converters from the
default GObject properties to GVariant.
Previously, those were implemented by providing a special
gprop_to_dbus_fcn hook. But gprop_to_dbus_fcn should move
from NMSettInfoPropertType to NMSettInfoProperty, because it's
usually a per-property meta data, and not a per-property-type meta data.
The difference is whether the meta data can be shared between different
properties (of the same "type).
In these cases, this extra information is indeed part of the type.
We want to have a generic NM_SETT_INFO_PROPERT_TYPE_GPROP() property
(using _nm_setting_property_to_dbus_fcn_gprop()), but then we would like
to distinguish between special cases. So this was fine.
However, I find the approach of providing a gprop_to_dbus_fcn in this
case cumbersome. It makes it harder to understand what happens. Instead,
introduce a new "gprop_type" for the different types that
_nm_setting_property_to_dbus_fcn_gprop() can handle.
This new "gprop_type" is extra data of the property type, so
introduce a new field "typdata_to_dbus".
(cherry picked from commit ac090edd87)
4783 lines
196 KiB
C
4783 lines
196 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2008 - 2017 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "libnm-core-impl/nm-default-libnm-core.h"
|
|
|
|
#include <linux/pkt_sched.h>
|
|
#include <net/if.h>
|
|
|
|
#include "libnm-glib-aux/nm-uuid.h"
|
|
#include "libnm-glib-aux/nm-json-aux.h"
|
|
#include "libnm-base/nm-ethtool-utils-base.h"
|
|
#include "libnm-core-intern/nm-core-internal.h"
|
|
#include "nm-utils.h"
|
|
#include "nm-utils-private.h"
|
|
#include "libnm-core-intern/nm-core-internal.h"
|
|
#include "nm-setting-8021x.h"
|
|
#include "nm-setting-bond.h"
|
|
#include "nm-setting-dcb.h"
|
|
#include "nm-setting-ethtool.h"
|
|
#include "nm-setting-team.h"
|
|
#include "nm-setting-team-port.h"
|
|
#include "nm-setting-tc-config.h"
|
|
#include "nm-setting-dummy.h"
|
|
#include "nm-connection.h"
|
|
#include "nm-simple-connection.h"
|
|
#include "nm-setting-connection.h"
|
|
#include "nm-errors.h"
|
|
#include "libnm-core-intern/nm-keyfile-internal.h"
|
|
|
|
#include "libnm-glib-aux/nm-test-utils.h"
|
|
|
|
#define TEST_CERT_DIR NM_BUILD_SRCDIR "/src/libnm-core-impl/tests/certs"
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* converts @dict to a connection. In this case, @dict must be good, without warnings, so that
|
|
* NM_SETTING_PARSE_FLAGS_STRICT and NM_SETTING_PARSE_FLAGS_BEST_EFFORT yield the exact same results. */
|
|
static NMConnection *
|
|
_connection_new_from_dbus_strict(GVariant *dict, gboolean normalize)
|
|
{
|
|
gs_unref_object NMConnection *con_x_0 = NULL;
|
|
gs_unref_object NMConnection *con_x_s = NULL;
|
|
gs_unref_object NMConnection *con_x_e = NULL;
|
|
gs_unref_object NMConnection *con_n_0 = NULL;
|
|
gs_unref_object NMConnection *con_n_s = NULL;
|
|
gs_unref_object NMConnection *con_n_e = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
guint i;
|
|
|
|
g_assert(g_variant_is_of_type(dict, NM_VARIANT_TYPE_CONNECTION));
|
|
|
|
con_x_0 = _nm_simple_connection_new_from_dbus(dict, NM_SETTING_PARSE_FLAGS_NONE, &error);
|
|
nmtst_assert_success(NM_IS_CONNECTION(con_x_0), error);
|
|
|
|
con_x_s = _nm_simple_connection_new_from_dbus(dict, NM_SETTING_PARSE_FLAGS_STRICT, &error);
|
|
nmtst_assert_success(NM_IS_CONNECTION(con_x_s), error);
|
|
|
|
con_x_e = _nm_simple_connection_new_from_dbus(dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
|
|
nmtst_assert_success(NM_IS_CONNECTION(con_x_e), error);
|
|
|
|
con_n_0 = _nm_simple_connection_new_from_dbus(dict, NM_SETTING_PARSE_FLAGS_NORMALIZE, &error);
|
|
nmtst_assert_success(NM_IS_CONNECTION(con_n_0), error);
|
|
|
|
con_n_s = _nm_simple_connection_new_from_dbus(dict,
|
|
NM_SETTING_PARSE_FLAGS_STRICT
|
|
| NM_SETTING_PARSE_FLAGS_NORMALIZE,
|
|
&error);
|
|
nmtst_assert_success(NM_IS_CONNECTION(con_n_s), error);
|
|
|
|
con_n_e = _nm_simple_connection_new_from_dbus(dict,
|
|
NM_SETTING_PARSE_FLAGS_BEST_EFFORT
|
|
| NM_SETTING_PARSE_FLAGS_NORMALIZE,
|
|
&error);
|
|
nmtst_assert_success(NM_IS_CONNECTION(con_n_e), error);
|
|
|
|
nmtst_assert_connection_verifies(con_x_0);
|
|
nmtst_assert_connection_verifies(con_x_e);
|
|
nmtst_assert_connection_verifies(con_x_s);
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con_n_0);
|
|
nmtst_assert_connection_verifies_without_normalization(con_n_e);
|
|
nmtst_assert_connection_verifies_without_normalization(con_n_s);
|
|
|
|
/* randomly compare some pairs that we created. They must all be equal,
|
|
* after accounting for normalization. */
|
|
for (i = 0; i < 10; i++) {
|
|
NMConnection *cons[] = {con_x_0, con_x_s, con_x_e, con_n_0, con_n_s, con_n_e};
|
|
guint idx_a = (nmtst_get_rand_uint32() % G_N_ELEMENTS(cons));
|
|
guint idx_b = (nmtst_get_rand_uint32() % G_N_ELEMENTS(cons));
|
|
gboolean normalize_a, normalize_b;
|
|
|
|
if (idx_a <= 2 && idx_b <= 2) {
|
|
normalize_a = nmtst_get_rand_bool();
|
|
normalize_b = normalize_a;
|
|
} else if (idx_a > 2 && idx_b > 2) {
|
|
normalize_a = nmtst_get_rand_bool();
|
|
normalize_b = nmtst_get_rand_bool();
|
|
} else {
|
|
normalize_a = (idx_a <= 2) ? TRUE : nmtst_get_rand_bool();
|
|
normalize_b = (idx_b <= 2) ? TRUE : nmtst_get_rand_bool();
|
|
}
|
|
nmtst_assert_connection_equals(cons[idx_a], normalize_a, cons[idx_b], normalize_b);
|
|
}
|
|
|
|
return (normalize) ? g_steal_pointer(&con_x_0) : g_steal_pointer(&con_n_0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nm_meta_setting_types_by_priority(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *arr = NULL;
|
|
int i;
|
|
int j;
|
|
|
|
G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM
|
|
== G_N_ELEMENTS(nm_meta_setting_types_by_priority));
|
|
|
|
G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM == 51);
|
|
|
|
arr = g_ptr_array_new_with_free_func(g_object_unref);
|
|
|
|
for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) {
|
|
const NMMetaSettingType meta_type = nm_meta_setting_types_by_priority[i];
|
|
const NMMetaSettingInfo *setting_info;
|
|
NMSetting * setting;
|
|
|
|
g_assert(_NM_INT_NOT_NEGATIVE(meta_type));
|
|
g_assert(meta_type < _NM_META_SETTING_TYPE_NUM);
|
|
|
|
setting_info = &nm_meta_setting_infos[meta_type];
|
|
g_assert(setting_info);
|
|
_nm_assert_setting_info(setting_info, 0);
|
|
|
|
for (j = 0; j < i; j++)
|
|
g_assert_cmpint(nm_meta_setting_types_by_priority[j], !=, meta_type);
|
|
|
|
setting = g_object_new(setting_info->get_setting_gtype(), NULL);
|
|
g_assert(NM_IS_SETTING(setting));
|
|
|
|
g_ptr_array_add(arr, setting);
|
|
}
|
|
|
|
for (i = 1; i < _NM_META_SETTING_TYPE_NUM; i++) {
|
|
NMSetting *setting = arr->pdata[i];
|
|
|
|
for (j = 0; j < i; j++) {
|
|
NMSetting *other = arr->pdata[j];
|
|
|
|
if (_nmtst_nm_setting_sort(other, setting) >= 0) {
|
|
g_error("sort order for nm_meta_setting_types_by_priority[%d vs %d] is wrong: %s "
|
|
"should be before %s",
|
|
j,
|
|
i,
|
|
nm_setting_get_name(setting),
|
|
nm_setting_get_name(other));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static char *
|
|
_create_random_ipaddr(int addr_family, gboolean as_service)
|
|
{
|
|
char delimiter = as_service ? ':' : '/';
|
|
int num;
|
|
|
|
if (addr_family == AF_UNSPEC)
|
|
addr_family = nmtst_rand_select(AF_INET, AF_INET6);
|
|
|
|
g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
|
|
|
|
if (as_service)
|
|
num = (nmtst_get_rand_uint32() % 1000) + 30000;
|
|
else
|
|
num = addr_family == AF_INET ? 32 : 128;
|
|
|
|
if (addr_family == AF_INET)
|
|
return g_strdup_printf("192.168.%u.%u%c%d",
|
|
nmtst_get_rand_uint32() % 256,
|
|
nmtst_get_rand_uint32() % 256,
|
|
delimiter,
|
|
num);
|
|
else
|
|
return g_strdup_printf("a:b:c::%02x:%02x%c%d",
|
|
nmtst_get_rand_uint32() % 256,
|
|
nmtst_get_rand_uint32() % 256,
|
|
delimiter,
|
|
num);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
compare_blob_data(const char *test, const char *key_path, GBytes *key)
|
|
{
|
|
gs_free char *contents = NULL;
|
|
gsize len = 0;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
|
|
g_assert(key && g_bytes_get_size(key) > 0);
|
|
|
|
success = g_file_get_contents(key_path, &contents, &len, &error);
|
|
nmtst_assert_success(success, error);
|
|
|
|
g_assert_cmpmem(contents, len, g_bytes_get_data(key, NULL), g_bytes_get_size(key));
|
|
}
|
|
|
|
static void
|
|
check_scheme_path(GBytes *value, const char *path)
|
|
{
|
|
const guint8 *p;
|
|
gsize l;
|
|
|
|
g_assert(value);
|
|
|
|
p = g_bytes_get_data(value, &l);
|
|
g_assert_cmpint(l, ==, strlen(path) + NM_STRLEN(NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH) + 1);
|
|
g_assert(memcmp(p,
|
|
NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH,
|
|
strlen(NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH))
|
|
== 0);
|
|
p += strlen(NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
|
|
g_assert(memcmp(p, path, strlen(path)) == 0);
|
|
p += strlen(path);
|
|
g_assert(*p == '\0');
|
|
}
|
|
|
|
static void
|
|
test_private_key_import(const char *path, const char *password, NMSetting8021xCKScheme scheme)
|
|
{
|
|
NMSetting8021x * s_8021x;
|
|
gboolean success;
|
|
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
|
|
NMSetting8021xCKFormat tmp_fmt;
|
|
GError * error = NULL;
|
|
GBytes * tmp_key = NULL, *client_cert = NULL;
|
|
const char * pw;
|
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
g_assert(s_8021x);
|
|
|
|
success = nm_setting_802_1x_set_private_key(s_8021x, path, password, scheme, &format, &error);
|
|
nmtst_assert_success(success, error);
|
|
g_assert(format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
|
|
tmp_fmt = nm_setting_802_1x_get_private_key_format(s_8021x);
|
|
g_assert(tmp_fmt == format);
|
|
|
|
/* Make sure the password is what we expect */
|
|
pw = nm_setting_802_1x_get_private_key_password(s_8021x);
|
|
g_assert(pw != NULL);
|
|
g_assert_cmpstr(pw, ==, password);
|
|
|
|
if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
|
|
tmp_key = nm_setting_802_1x_get_private_key_blob(s_8021x);
|
|
compare_blob_data("private-key-import", path, tmp_key);
|
|
} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
|
|
g_object_get(s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL);
|
|
check_scheme_path(tmp_key, path);
|
|
g_bytes_unref(tmp_key);
|
|
} else
|
|
g_assert_not_reached();
|
|
|
|
/* If it's PKCS#12 ensure the client cert is the same value */
|
|
if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
|
|
g_object_get(s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL);
|
|
g_assert(tmp_key);
|
|
|
|
g_object_get(s_8021x, NM_SETTING_802_1X_CLIENT_CERT, &client_cert, NULL);
|
|
g_assert(client_cert);
|
|
|
|
/* make sure they are the same */
|
|
g_assert(g_bytes_equal(tmp_key, client_cert));
|
|
|
|
g_bytes_unref(tmp_key);
|
|
g_bytes_unref(client_cert);
|
|
}
|
|
|
|
g_object_unref(s_8021x);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_do_test_connection_uuid(NMConnection *con, const char *uuid, const char *expected_uuid)
|
|
{
|
|
NMSettingConnection *s_con;
|
|
gs_free char * uuid_old = NULL;
|
|
gboolean success;
|
|
gboolean is_normalized;
|
|
char uuid_normalized[37];
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con);
|
|
|
|
s_con = NM_SETTING_CONNECTION(nm_connection_get_setting(con, NM_TYPE_SETTING_CONNECTION));
|
|
g_assert(NM_IS_SETTING_CONNECTION(s_con));
|
|
|
|
g_assert(uuid);
|
|
|
|
uuid_old = g_strdup(nm_setting_connection_get_uuid(s_con));
|
|
|
|
g_assert(nm_utils_is_uuid(uuid_old));
|
|
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_UUID, uuid, NULL);
|
|
|
|
g_assert_cmpstr(uuid, ==, nm_setting_connection_get_uuid(s_con));
|
|
|
|
if (nm_streq0(uuid, expected_uuid)) {
|
|
nmtst_assert_connection_verifies_without_normalization(con);
|
|
g_assert(nm_utils_is_uuid(uuid));
|
|
g_assert(nm_uuid_is_valid(uuid));
|
|
g_assert(nm_uuid_is_valid_nm(uuid, &is_normalized, NULL));
|
|
g_assert(!is_normalized);
|
|
} else if (!expected_uuid) {
|
|
gs_free_error GError *error = NULL;
|
|
|
|
success = nm_connection_verify(con, &error);
|
|
nmtst_assert_no_success(success, error);
|
|
g_assert_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
|
|
|
|
g_assert(!nm_utils_is_uuid(uuid));
|
|
g_assert(!nm_uuid_is_valid(uuid));
|
|
g_assert(!nm_uuid_is_valid_nmlegacy(uuid));
|
|
g_assert(!nm_uuid_is_valid_nm(uuid, NULL, NULL));
|
|
} else {
|
|
gs_free_error GError *error = NULL;
|
|
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
|
|
success = nm_connection_verify(con, &error);
|
|
nmtst_assert_success(success, error);
|
|
|
|
if (!nmtst_connection_normalize(con))
|
|
g_assert_not_reached();
|
|
|
|
g_assert_cmpstr(expected_uuid, ==, nm_setting_connection_get_uuid(s_con));
|
|
g_assert(nm_uuid_is_valid(expected_uuid));
|
|
|
|
g_assert(nm_utils_is_uuid(uuid));
|
|
g_assert(nm_uuid_is_valid_nmlegacy(uuid));
|
|
g_assert(nm_uuid_is_valid_nm(uuid, &is_normalized, uuid_normalized));
|
|
|
|
g_assert_cmpstr(expected_uuid, ==, uuid_normalized);
|
|
}
|
|
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_UUID, uuid_old, NULL);
|
|
nmtst_assert_connection_verifies_without_normalization(con);
|
|
|
|
if (expected_uuid && !nm_streq(expected_uuid, uuid))
|
|
_do_test_connection_uuid(con, expected_uuid, expected_uuid);
|
|
}
|
|
|
|
static void
|
|
test_connection_uuid(void)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
|
|
con = nmtst_create_minimal_connection("test-uuid", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
|
|
|
|
nmtst_connection_normalize(con);
|
|
|
|
#define _do_test_connection_uuid_bad(con, uuid) _do_test_connection_uuid((con), "" uuid "", NULL)
|
|
|
|
#define _do_test_connection_uuid_good(con, uuid) \
|
|
_do_test_connection_uuid((con), "" uuid "", "" uuid "")
|
|
|
|
#define _do_test_connection_uuid_norm(con, uuid, expected_uuid) \
|
|
_do_test_connection_uuid((con), "" uuid "", "" expected_uuid "")
|
|
|
|
_do_test_connection_uuid_bad(con, "x1e775e3-a316-4eb2-b4d8-4b0f2bcaea53");
|
|
_do_test_connection_uuid_bad(con, "1e775e3aa3164eb2b4d84b0f2bcaea53abcdabc");
|
|
_do_test_connection_uuid_bad(con, "1e775e3aa3164eb2b4d84b0f2bcaea53abcdabcdd");
|
|
|
|
_do_test_connection_uuid_good(con, "a1e775e3-a316-4eb2-b4d8-4b0f2bcaea53");
|
|
|
|
_do_test_connection_uuid_norm(con,
|
|
"A1E775e3-a316-4eb2-b4d8-4b0f2bcaea53",
|
|
"a1e775e3-a316-4eb2-b4d8-4b0f2bcaea53");
|
|
_do_test_connection_uuid_norm(con,
|
|
"A1E775E3-A316-4EB2-B4D8-4B0F2BCAEA53",
|
|
"a1e775e3-a316-4eb2-b4d8-4b0f2bcaea53");
|
|
_do_test_connection_uuid_norm(con,
|
|
"-1e775e3aa316-4eb2-b4d8-4b0f2bcaea53",
|
|
"bdd73688-5c87-5454-917d-f5c3faed39c0");
|
|
_do_test_connection_uuid_norm(con,
|
|
"----1e775e3aa3164eb2b4d84b0f2bcaea53",
|
|
"8a232814-c6cf-54c9-9384-71a60011d0b2");
|
|
_do_test_connection_uuid_norm(con,
|
|
"1e775e3aa3164eb2b4d84b0f2bcaea53abcdabcd",
|
|
"ae35a4a8-4029-5770-9fa4-d79a672874c3");
|
|
_do_test_connection_uuid_norm(con,
|
|
"1e775e3Aa3164eb2b4d84b0f2bcaea53abcdabcd",
|
|
"ae35a4a8-4029-5770-9fa4-d79a672874c3");
|
|
_do_test_connection_uuid_norm(con,
|
|
"1E775E3AA3164EB2B4D84B0F2BCAEA53ABCDABCD",
|
|
"ae35a4a8-4029-5770-9fa4-d79a672874c3");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_phase2_private_key_import(const char * path,
|
|
const char * password,
|
|
NMSetting8021xCKScheme scheme)
|
|
{
|
|
NMSetting8021x * s_8021x;
|
|
gboolean success;
|
|
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
|
|
NMSetting8021xCKFormat tmp_fmt;
|
|
GError * error = NULL;
|
|
GBytes * tmp_key = NULL, *client_cert = NULL;
|
|
const char * pw;
|
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
g_assert(s_8021x);
|
|
|
|
success =
|
|
nm_setting_802_1x_set_phase2_private_key(s_8021x, path, password, scheme, &format, &error);
|
|
nmtst_assert_success(success, error);
|
|
g_assert(format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
|
|
tmp_fmt = nm_setting_802_1x_get_phase2_private_key_format(s_8021x);
|
|
g_assert(tmp_fmt == format);
|
|
|
|
/* Make sure the password is what we expect */
|
|
pw = nm_setting_802_1x_get_phase2_private_key_password(s_8021x);
|
|
g_assert(pw);
|
|
g_assert_cmpstr(pw, ==, password);
|
|
|
|
if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
|
|
tmp_key = nm_setting_802_1x_get_phase2_private_key_blob(s_8021x);
|
|
compare_blob_data("phase2-private-key-import", path, tmp_key);
|
|
} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
|
|
g_object_get(s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL);
|
|
check_scheme_path(tmp_key, path);
|
|
g_bytes_unref(tmp_key);
|
|
} else
|
|
g_assert_not_reached();
|
|
|
|
/* If it's PKCS#12 ensure the client cert is the same value */
|
|
if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
|
|
g_object_get(s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL);
|
|
g_assert(tmp_key);
|
|
|
|
g_object_get(s_8021x, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &client_cert, NULL);
|
|
g_assert(client_cert);
|
|
|
|
/* make sure they are the same */
|
|
g_assert(g_bytes_equal(tmp_key, client_cert));
|
|
|
|
g_bytes_unref(tmp_key);
|
|
g_bytes_unref(client_cert);
|
|
}
|
|
|
|
g_object_unref(s_8021x);
|
|
}
|
|
|
|
static void
|
|
test_wrong_password_keeps_data(const char *path, const char *password)
|
|
{
|
|
NMSetting8021x * s_8021x;
|
|
gboolean success;
|
|
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
|
|
GError * error = NULL;
|
|
const char * pw;
|
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
g_assert(s_8021x);
|
|
|
|
success = nm_setting_802_1x_set_private_key(s_8021x,
|
|
path,
|
|
password,
|
|
NM_SETTING_802_1X_CK_SCHEME_BLOB,
|
|
&format,
|
|
&error);
|
|
nmtst_assert_success(success, error);
|
|
g_assert(format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
|
|
|
|
/* Now try to set it to something that's not a certificate */
|
|
format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
|
|
success = nm_setting_802_1x_set_private_key(s_8021x,
|
|
"Makefile.am",
|
|
password,
|
|
NM_SETTING_802_1X_CK_SCHEME_BLOB,
|
|
&format,
|
|
&error);
|
|
nmtst_assert_no_success(success, error);
|
|
g_assert(format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
|
|
g_clear_error(&error);
|
|
|
|
/* Make sure the password hasn't changed */
|
|
pw = nm_setting_802_1x_get_private_key_password(s_8021x);
|
|
g_assert(pw);
|
|
g_assert_cmpstr(pw, ==, password);
|
|
|
|
g_object_unref(s_8021x);
|
|
}
|
|
|
|
static void
|
|
test_clear_private_key(const char *path, const char *password)
|
|
{
|
|
NMSetting8021x * s_8021x;
|
|
gboolean success;
|
|
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
|
|
GError * error = NULL;
|
|
const char * pw;
|
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
g_assert(s_8021x);
|
|
|
|
success = nm_setting_802_1x_set_private_key(s_8021x,
|
|
path,
|
|
password,
|
|
NM_SETTING_802_1X_CK_SCHEME_BLOB,
|
|
&format,
|
|
&error);
|
|
nmtst_assert_success(success, error);
|
|
g_assert(format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
|
|
|
|
/* Make sure the password is what we expect */
|
|
pw = nm_setting_802_1x_get_private_key_password(s_8021x);
|
|
g_assert(pw);
|
|
g_assert_cmpstr(pw, ==, password);
|
|
|
|
/* Now clear it */
|
|
success = nm_setting_802_1x_set_private_key(s_8021x,
|
|
NULL,
|
|
NULL,
|
|
NM_SETTING_802_1X_CK_SCHEME_BLOB,
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(success, error);
|
|
|
|
/* Ensure the password is also now clear */
|
|
g_assert(!nm_setting_802_1x_get_private_key_password(s_8021x));
|
|
|
|
g_object_unref(s_8021x);
|
|
}
|
|
|
|
static void
|
|
test_wrong_phase2_password_keeps_data(const char *path, const char *password)
|
|
{
|
|
NMSetting8021x * s_8021x;
|
|
gboolean success;
|
|
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
|
|
GError * error = NULL;
|
|
const char * pw;
|
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
g_assert(s_8021x);
|
|
|
|
success = nm_setting_802_1x_set_phase2_private_key(s_8021x,
|
|
path,
|
|
password,
|
|
NM_SETTING_802_1X_CK_SCHEME_BLOB,
|
|
&format,
|
|
&error);
|
|
nmtst_assert_success(success, error);
|
|
g_assert(format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
|
|
|
|
/* Now try to set it to something that's not a certificate */
|
|
format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
|
|
success = nm_setting_802_1x_set_phase2_private_key(s_8021x,
|
|
"Makefile.am",
|
|
password,
|
|
NM_SETTING_802_1X_CK_SCHEME_BLOB,
|
|
&format,
|
|
&error);
|
|
nmtst_assert_no_success(success, error);
|
|
g_assert(format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
|
|
g_clear_error(&error);
|
|
|
|
/* Make sure the password hasn't changed */
|
|
pw = nm_setting_802_1x_get_phase2_private_key_password(s_8021x);
|
|
g_assert(pw);
|
|
g_assert_cmpstr(pw, ==, password);
|
|
|
|
g_object_unref(s_8021x);
|
|
}
|
|
|
|
static void
|
|
test_clear_phase2_private_key(const char *path, const char *password)
|
|
{
|
|
NMSetting8021x * s_8021x;
|
|
gboolean success;
|
|
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
|
|
GError * error = NULL;
|
|
const char * pw;
|
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
g_assert(s_8021x);
|
|
|
|
success = nm_setting_802_1x_set_phase2_private_key(s_8021x,
|
|
path,
|
|
password,
|
|
NM_SETTING_802_1X_CK_SCHEME_BLOB,
|
|
&format,
|
|
&error);
|
|
nmtst_assert_success(success, error);
|
|
g_assert(format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
|
|
|
|
/* Make sure the password is what we expect */
|
|
pw = nm_setting_802_1x_get_phase2_private_key_password(s_8021x);
|
|
g_assert(pw);
|
|
g_assert_cmpstr(pw, ==, password);
|
|
|
|
/* Now clear it */
|
|
success = nm_setting_802_1x_set_phase2_private_key(s_8021x,
|
|
NULL,
|
|
NULL,
|
|
NM_SETTING_802_1X_CK_SCHEME_BLOB,
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(success, error);
|
|
|
|
/* Ensure the password is also now clear */
|
|
g_assert(!nm_setting_802_1x_get_phase2_private_key_password(s_8021x));
|
|
|
|
g_object_unref(s_8021x);
|
|
}
|
|
|
|
static void
|
|
test_8021x(gconstpointer test_data)
|
|
{
|
|
char **parts, *path, *password;
|
|
|
|
parts = g_strsplit((const char *) test_data, ", ", -1);
|
|
g_assert_cmpint(g_strv_length(parts), ==, 2);
|
|
|
|
path = g_build_filename(TEST_CERT_DIR, parts[0], NULL);
|
|
password = parts[1];
|
|
|
|
/* Test phase1 and phase2 path scheme */
|
|
test_private_key_import(path, password, NM_SETTING_802_1X_CK_SCHEME_PATH);
|
|
test_phase2_private_key_import(path, password, NM_SETTING_802_1X_CK_SCHEME_PATH);
|
|
|
|
/* Test phase1 and phase2 blob scheme */
|
|
test_private_key_import(path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB);
|
|
test_phase2_private_key_import(path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB);
|
|
|
|
/* Test that using a wrong password does not change existing data */
|
|
test_wrong_password_keeps_data(path, password);
|
|
test_wrong_phase2_password_keeps_data(path, password);
|
|
|
|
/* Test clearing the private key */
|
|
test_clear_private_key(path, password);
|
|
test_clear_phase2_private_key(path, password);
|
|
|
|
g_free(path);
|
|
g_strfreev(parts);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
create_bond_connection(NMConnection **con, NMSettingBond **s_bond)
|
|
{
|
|
NMSettingConnection *s_con;
|
|
|
|
g_assert(con);
|
|
g_assert(s_bond);
|
|
|
|
*con = nmtst_create_minimal_connection("bond", NULL, NM_SETTING_BOND_SETTING_NAME, &s_con);
|
|
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "bond0", NULL);
|
|
|
|
*s_bond = (NMSettingBond *) nm_setting_bond_new();
|
|
g_assert(*s_bond);
|
|
|
|
nm_connection_add_setting(*con, NM_SETTING(*s_bond));
|
|
}
|
|
|
|
#define test_verify_options(exp, ...) _test_verify_options(exp, NM_MAKE_STRV(__VA_ARGS__))
|
|
|
|
static void
|
|
_test_verify_options(gboolean expected_result, const char *const *options)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
NMSettingBond * s_bond;
|
|
const char *const * option;
|
|
|
|
g_assert(NM_PTRARRAY_LEN(options) % 2 == 0);
|
|
|
|
create_bond_connection(&con, &s_bond);
|
|
|
|
for (option = options; option[0]; option += 2)
|
|
g_assert(nm_setting_bond_add_option(s_bond, option[0], option[1]));
|
|
|
|
if (expected_result) {
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
} else {
|
|
nmtst_assert_connection_unnormalizable(con,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_bond_verify(void)
|
|
{
|
|
test_verify_options(TRUE, "mode", "3", "arp_interval", "0");
|
|
test_verify_options(FALSE,
|
|
/* arp_interval not supported in balance-alb mode */
|
|
"mode",
|
|
"balance-alb",
|
|
"arp_interval",
|
|
"1",
|
|
"arp_ip_target",
|
|
"1.2.3.4");
|
|
test_verify_options(FALSE,
|
|
/* arp_ip_target requires arp_interval */
|
|
"mode",
|
|
"balance-rr",
|
|
"arp_ip_target",
|
|
"1.2.3.4");
|
|
test_verify_options(TRUE,
|
|
"mode",
|
|
"balance-rr",
|
|
"arp_interval",
|
|
"1",
|
|
"arp_ip_target",
|
|
"1.2.3.4");
|
|
test_verify_options(FALSE,
|
|
/* num_grat_arp, num_unsol_na cannot be different */
|
|
"mode",
|
|
"balance-rr",
|
|
"num_grat_arp",
|
|
"3",
|
|
"num_unsol_na",
|
|
"4");
|
|
test_verify_options(TRUE, "mode", "balance-rr", "num_grat_arp", "5", "num_unsol_na", "5");
|
|
test_verify_options(TRUE, "mode", "active-backup", "primary", "eth0");
|
|
test_verify_options(FALSE,
|
|
/* primary requires mode=active-backup */
|
|
"mode",
|
|
"802.3ad",
|
|
"primary",
|
|
"eth0");
|
|
test_verify_options(TRUE, "mode", "802.3ad", "lacp_rate", "fast");
|
|
test_verify_options(FALSE,
|
|
/* lacp_rate=fast requires mode=802.3ad */
|
|
"mode",
|
|
"balance-rr",
|
|
"lacp_rate",
|
|
"fast");
|
|
test_verify_options(TRUE, "mode", "802.3ad", "ad_actor_system", "ae:00:11:33:44:55");
|
|
test_verify_options(TRUE, "mode", "0", "miimon", "0", "updelay", "0", "downdelay", "0");
|
|
test_verify_options(TRUE, "mode", "0", "downdelay", "0", "updelay", "0");
|
|
test_verify_options(TRUE,
|
|
"mode",
|
|
"0",
|
|
"miimon",
|
|
"100",
|
|
"arp_ip_target",
|
|
"1.1.1.1",
|
|
"arp_interval",
|
|
"200");
|
|
test_verify_options(TRUE,
|
|
"mode",
|
|
"0",
|
|
"downdelay",
|
|
"100",
|
|
"arp_ip_target",
|
|
"1.1.1.1",
|
|
"arp_interval",
|
|
"200");
|
|
}
|
|
|
|
static void
|
|
test_bond_compare_options(gboolean exp_res, const char **opts1, const char **opts2)
|
|
{
|
|
gs_unref_object NMSettingBond *s_bond1 = NULL, *s_bond2 = NULL;
|
|
const char ** p;
|
|
|
|
s_bond1 = (NMSettingBond *) nm_setting_bond_new();
|
|
g_assert(s_bond1);
|
|
s_bond2 = (NMSettingBond *) nm_setting_bond_new();
|
|
g_assert(s_bond2);
|
|
|
|
for (p = opts1; p[0] && p[1]; p += 2)
|
|
g_assert(nm_setting_bond_add_option(s_bond1, p[0], p[1]));
|
|
|
|
for (p = opts2; p[0] && p[1]; p += 2)
|
|
g_assert(nm_setting_bond_add_option(s_bond2, p[0], p[1]));
|
|
|
|
g_assert_cmpint(nm_setting_compare((NMSetting *) s_bond1,
|
|
(NMSetting *) s_bond2,
|
|
NM_SETTING_COMPARE_FLAG_EXACT),
|
|
==,
|
|
exp_res);
|
|
}
|
|
|
|
static void
|
|
test_bond_compare(void)
|
|
{
|
|
test_bond_compare_options(TRUE,
|
|
((const char *[]){"mode", "balance-rr", "miimon", "1", NULL}),
|
|
((const char *[]){"mode", "balance-rr", "miimon", "1", NULL}));
|
|
test_bond_compare_options(FALSE,
|
|
((const char *[]){"mode", "balance-rr", "miimon", "1", NULL}),
|
|
((const char *[]){"mode", "balance-rr", "miimon", "2", NULL}));
|
|
|
|
test_bond_compare_options(FALSE,
|
|
((const char *[]){"miimon", "1", NULL}),
|
|
((const char *[]){"miimon", "1", "updelay", "0", NULL}));
|
|
|
|
test_bond_compare_options(FALSE,
|
|
((const char *[]){"num_grat_arp", "2", NULL}),
|
|
((const char *[]){"num_grat_arp", "1", NULL}));
|
|
test_bond_compare_options(FALSE,
|
|
((const char *[]){"num_grat_arp", "3", NULL}),
|
|
((const char *[]){"num_unsol_na", "3", NULL}));
|
|
test_bond_compare_options(FALSE,
|
|
((const char *[]){"num_grat_arp", "4", NULL}),
|
|
((const char *[]){"num_unsol_na", "4", "num_grat_arp", "4", NULL}));
|
|
|
|
test_bond_compare_options(FALSE,
|
|
((const char *[]){"mode", "balance-rr", "miimon", "100", NULL}),
|
|
((const char *[]){"mode", "balance-rr", NULL}));
|
|
}
|
|
|
|
static void
|
|
test_bond_normalize_options(const char **opts1, const char **opts2)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
NMSettingBond * s_bond;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
const char ** p;
|
|
int num = 0;
|
|
|
|
create_bond_connection(&con, &s_bond);
|
|
|
|
for (p = opts1; p[0] && p[1]; p += 2)
|
|
g_assert(nm_setting_bond_add_option(s_bond, p[0], p[1]));
|
|
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
nmtst_connection_normalize(con);
|
|
success = nm_setting_verify((NMSetting *) s_bond, con, &error);
|
|
nmtst_assert_success(success, error);
|
|
|
|
for (p = opts2; p[0] && p[1]; p += 2) {
|
|
g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, p[0]), ==, p[1]);
|
|
num++;
|
|
}
|
|
|
|
g_assert_cmpint(num, ==, nm_setting_bond_get_num_options(s_bond));
|
|
}
|
|
|
|
static void
|
|
test_bond_normalize(void)
|
|
{
|
|
test_bond_normalize_options(
|
|
((const char *[]){"mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL}),
|
|
((const char *[]){"mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL}));
|
|
test_bond_normalize_options(((const char *[]){"mode", "1", "miimon", "1", NULL}),
|
|
((const char *[]){"mode", "active-backup", "miimon", "1", NULL}));
|
|
test_bond_normalize_options(
|
|
((const char *[]){"mode", "balance-alb", "tlb_dynamic_lb", "1", NULL}),
|
|
((const char *[]){"mode", "balance-alb", "tlb_dynamic_lb", "1", NULL}));
|
|
test_bond_normalize_options(
|
|
((const char *[]){"mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL}),
|
|
((const char *[]){"mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL}));
|
|
test_bond_normalize_options(
|
|
((const char
|
|
*[]){"mode", "balance-rr", "ad_actor_sys_prio", "4", "packets_per_slave", "3", NULL}),
|
|
((const char *[]){"mode", "balance-rr", "packets_per_slave", "3", NULL}));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
#define DCB_FLAGS_ALL \
|
|
(NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING)
|
|
|
|
static void
|
|
test_dcb_flags_valid(void)
|
|
{
|
|
gs_unref_object NMSettingDcb *s_dcb = NULL;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
guint i;
|
|
|
|
s_dcb = (NMSettingDcb *) nm_setting_dcb_new();
|
|
g_assert(s_dcb);
|
|
|
|
g_assert_cmpint(nm_setting_dcb_get_app_fcoe_flags(s_dcb), ==, 0);
|
|
g_assert_cmpint(nm_setting_dcb_get_app_iscsi_flags(s_dcb), ==, 0);
|
|
g_assert_cmpint(nm_setting_dcb_get_app_fip_flags(s_dcb), ==, 0);
|
|
g_assert_cmpint(nm_setting_dcb_get_priority_flow_control_flags(s_dcb), ==, 0);
|
|
g_assert_cmpint(nm_setting_dcb_get_priority_group_flags(s_dcb), ==, 0);
|
|
|
|
g_object_set(G_OBJECT(s_dcb),
|
|
NM_SETTING_DCB_APP_FCOE_FLAGS,
|
|
DCB_FLAGS_ALL,
|
|
NM_SETTING_DCB_APP_ISCSI_FLAGS,
|
|
DCB_FLAGS_ALL,
|
|
NM_SETTING_DCB_APP_FIP_FLAGS,
|
|
DCB_FLAGS_ALL,
|
|
NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS,
|
|
DCB_FLAGS_ALL,
|
|
NM_SETTING_DCB_PRIORITY_GROUP_FLAGS,
|
|
DCB_FLAGS_ALL,
|
|
NULL);
|
|
/* Priority Group Bandwidth must total 100% */
|
|
for (i = 0; i < 7; i++)
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, i, 12);
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 7, 16);
|
|
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error);
|
|
g_assert_no_error(error);
|
|
g_assert(success);
|
|
|
|
g_assert_cmpint(nm_setting_dcb_get_app_fcoe_flags(s_dcb), ==, DCB_FLAGS_ALL);
|
|
g_assert_cmpint(nm_setting_dcb_get_app_iscsi_flags(s_dcb), ==, DCB_FLAGS_ALL);
|
|
g_assert_cmpint(nm_setting_dcb_get_app_fip_flags(s_dcb), ==, DCB_FLAGS_ALL);
|
|
g_assert_cmpint(nm_setting_dcb_get_priority_flow_control_flags(s_dcb), ==, DCB_FLAGS_ALL);
|
|
g_assert_cmpint(nm_setting_dcb_get_priority_group_flags(s_dcb), ==, DCB_FLAGS_ALL);
|
|
}
|
|
|
|
#define TEST_FLAG(p, f, v) \
|
|
{ \
|
|
/* GObject property min/max should ensure the property does not get set to \
|
|
* the invalid value, so we ensure the value we just tried to set is 0 and \
|
|
* that verify is successful since the property never got set. \
|
|
*/ \
|
|
g_object_set(G_OBJECT(s_dcb), p, v, NULL); \
|
|
g_assert_cmpint(f(s_dcb), ==, 0); \
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error); \
|
|
g_assert_no_error(error); \
|
|
g_assert(success); \
|
|
}
|
|
|
|
static void
|
|
test_dcb_flags_invalid(void)
|
|
{
|
|
gs_unref_object NMSettingDcb *s_dcb = NULL;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
|
|
s_dcb = (NMSettingDcb *) nm_setting_dcb_new();
|
|
g_assert(s_dcb);
|
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
|
TEST_FLAG(NM_SETTING_DCB_APP_FCOE_FLAGS, nm_setting_dcb_get_app_fcoe_flags, 0x332523);
|
|
g_test_assert_expected_messages();
|
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
|
TEST_FLAG(NM_SETTING_DCB_APP_ISCSI_FLAGS, nm_setting_dcb_get_app_iscsi_flags, 0xFF);
|
|
g_test_assert_expected_messages();
|
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
|
TEST_FLAG(NM_SETTING_DCB_APP_FIP_FLAGS, nm_setting_dcb_get_app_fip_flags, 0x1111);
|
|
g_test_assert_expected_messages();
|
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
|
TEST_FLAG(NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS,
|
|
nm_setting_dcb_get_priority_flow_control_flags,
|
|
G_MAXUINT32);
|
|
g_test_assert_expected_messages();
|
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
|
TEST_FLAG(
|
|
NM_SETTING_DCB_PRIORITY_GROUP_FLAGS,
|
|
nm_setting_dcb_get_priority_group_flags,
|
|
(NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING)
|
|
+ 1);
|
|
g_test_assert_expected_messages();
|
|
}
|
|
|
|
#define TEST_APP_PRIORITY(lcprop, ucprop, v) \
|
|
{ \
|
|
g_object_set(G_OBJECT(s_dcb), \
|
|
NM_SETTING_DCB_APP_##ucprop##_FLAGS, \
|
|
NM_SETTING_DCB_FLAG_NONE, \
|
|
NULL); \
|
|
\
|
|
g_object_set(G_OBJECT(s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, v, NULL); \
|
|
g_assert_cmpint(nm_setting_dcb_get_app_##lcprop##_priority(s_dcb), ==, v); \
|
|
\
|
|
/* Assert that the setting is invalid while the app is disabled unless v is default */ \
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error); \
|
|
if (v >= 0) { \
|
|
g_assert_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); \
|
|
g_assert(success == FALSE); \
|
|
} else { \
|
|
g_assert_no_error(error); \
|
|
g_assert(success); \
|
|
} \
|
|
g_clear_error(&error); \
|
|
\
|
|
/* Set the enable flag and re-verify, this time it should be valid */ \
|
|
g_object_set(G_OBJECT(s_dcb), \
|
|
NM_SETTING_DCB_APP_##ucprop##_FLAGS, \
|
|
NM_SETTING_DCB_FLAG_ENABLE, \
|
|
NULL); \
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error); \
|
|
g_assert_no_error(error); \
|
|
g_assert(success); \
|
|
\
|
|
g_object_set(G_OBJECT(s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, 0, NULL); \
|
|
}
|
|
|
|
static void
|
|
test_dcb_app_priorities(void)
|
|
{
|
|
gs_unref_object NMSettingDcb *s_dcb = NULL;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
|
|
s_dcb = (NMSettingDcb *) nm_setting_dcb_new();
|
|
g_assert(s_dcb);
|
|
|
|
/* Defaults */
|
|
g_assert_cmpint(nm_setting_dcb_get_app_fcoe_priority(s_dcb), ==, -1);
|
|
g_assert_cmpint(nm_setting_dcb_get_app_iscsi_priority(s_dcb), ==, -1);
|
|
g_assert_cmpint(nm_setting_dcb_get_app_fip_priority(s_dcb), ==, -1);
|
|
|
|
TEST_APP_PRIORITY(fcoe, FCOE, 6);
|
|
TEST_APP_PRIORITY(iscsi, ISCSI, 5);
|
|
TEST_APP_PRIORITY(fip, FIP, 4);
|
|
|
|
TEST_APP_PRIORITY(fcoe, FCOE, -1);
|
|
TEST_APP_PRIORITY(iscsi, ISCSI, -1);
|
|
TEST_APP_PRIORITY(fip, FIP, -1);
|
|
}
|
|
|
|
#define TEST_PRIORITY_VALID(fn, id, val, flagsprop, verify) \
|
|
{ \
|
|
/* Assert that setting the value gets the same value back out */ \
|
|
nm_setting_dcb_set_priority_##fn(s_dcb, id, val); \
|
|
g_assert_cmpint(nm_setting_dcb_get_priority_##fn(s_dcb, id), ==, val); \
|
|
\
|
|
if (verify) { \
|
|
if (val != 0) { \
|
|
/* Assert that verify fails because the flags do not include 'enabled' \
|
|
* and a value has been set. \
|
|
*/ \
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error); \
|
|
g_assert_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); \
|
|
g_assert(success == FALSE); \
|
|
g_clear_error(&error); \
|
|
} \
|
|
\
|
|
/* Assert that adding the 'enabled' flag verifies the setting */ \
|
|
g_object_set(G_OBJECT(s_dcb), \
|
|
NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, \
|
|
NM_SETTING_DCB_FLAG_ENABLE, \
|
|
NULL); \
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error); \
|
|
g_assert_no_error(error); \
|
|
g_assert(success); \
|
|
} \
|
|
\
|
|
/* Reset everything */ \
|
|
g_object_set(G_OBJECT(s_dcb), \
|
|
NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, \
|
|
NM_SETTING_DCB_FLAG_NONE, \
|
|
NULL); \
|
|
nm_setting_dcb_set_priority_##fn(s_dcb, id, 0); \
|
|
}
|
|
|
|
/* If Priority Groups are enabled, PG bandwidth must equal 100% */
|
|
#define SET_VALID_PRIORITY_GROUP_BANDWIDTH \
|
|
{ \
|
|
guint x; \
|
|
for (x = 0; x < 7; x++) \
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, x, 12); \
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 7, 16); \
|
|
}
|
|
|
|
static void
|
|
test_dcb_priorities_valid(void)
|
|
{
|
|
gs_unref_object NMSettingDcb *s_dcb = NULL;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
guint i;
|
|
|
|
s_dcb = (NMSettingDcb *) nm_setting_dcb_new();
|
|
g_assert(s_dcb);
|
|
|
|
for (i = 0; i < 8; i++)
|
|
TEST_PRIORITY_VALID(flow_control, i, TRUE, FLOW_CONTROL, TRUE);
|
|
|
|
SET_VALID_PRIORITY_GROUP_BANDWIDTH
|
|
for (i = 0; i < 8; i++) {
|
|
TEST_PRIORITY_VALID(group_id, i, i, GROUP, TRUE);
|
|
TEST_PRIORITY_VALID(group_id, i, 7 - i, GROUP, TRUE);
|
|
}
|
|
|
|
/* Clear PG bandwidth from earlier tests */
|
|
for (i = 0; i < 8; i++)
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, i, 0);
|
|
|
|
/* Priority Group Bandwidth must add up to 100% if enabled, which requires
|
|
* some dancing for verifying individual values here.
|
|
*/
|
|
for (i = 0; i < 8; i++) {
|
|
guint other = 7 - (i % 8);
|
|
|
|
/* Set another priority group to the remaining bandwidth */
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, other, 100 - i);
|
|
TEST_PRIORITY_VALID(group_bandwidth, i, i, GROUP, TRUE);
|
|
|
|
/* Set another priority group to the remaining bandwidth */
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, other, 100 - (7 - i));
|
|
TEST_PRIORITY_VALID(group_bandwidth, i, 7 - i, GROUP, TRUE);
|
|
|
|
/* Clear remaining bandwidth */
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, other, 0);
|
|
}
|
|
|
|
SET_VALID_PRIORITY_GROUP_BANDWIDTH
|
|
for (i = 0; i < 8; i++) {
|
|
TEST_PRIORITY_VALID(bandwidth, i, i, GROUP, TRUE);
|
|
TEST_PRIORITY_VALID(bandwidth, i, 7 - i, GROUP, TRUE);
|
|
}
|
|
|
|
SET_VALID_PRIORITY_GROUP_BANDWIDTH
|
|
for (i = 0; i < 8; i++)
|
|
TEST_PRIORITY_VALID(strict_bandwidth, i, TRUE, GROUP, TRUE);
|
|
|
|
SET_VALID_PRIORITY_GROUP_BANDWIDTH
|
|
for (i = 0; i < 8; i++) {
|
|
TEST_PRIORITY_VALID(traffic_class, i, i, GROUP, TRUE);
|
|
TEST_PRIORITY_VALID(traffic_class, i, 7 - i, GROUP, TRUE);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_dcb_bandwidth_sums(void)
|
|
{
|
|
gs_unref_object NMSettingDcb *s_dcb = NULL;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
|
|
s_dcb = (NMSettingDcb *) nm_setting_dcb_new();
|
|
g_assert(s_dcb);
|
|
|
|
/* Assert that setting the value gets the same value back out */
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 0, 9);
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 1, 10);
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 2, 11);
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 3, 12);
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 4, 13);
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 5, 14);
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 6, 15);
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 7, 16);
|
|
|
|
/* Assert verify success when sums total 100% */
|
|
g_object_set(G_OBJECT(s_dcb),
|
|
NM_SETTING_DCB_PRIORITY_GROUP_FLAGS,
|
|
NM_SETTING_DCB_FLAG_ENABLE,
|
|
NULL);
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error);
|
|
g_assert_no_error(error);
|
|
g_assert(success);
|
|
|
|
/* Assert verify fails when sums do not total 100% */
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, 4, 20);
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error);
|
|
g_assert_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
|
|
g_assert(success == FALSE);
|
|
g_clear_error(&error);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nm_json(void)
|
|
{
|
|
g_assert(NM_IN_SET(WITH_JANSSON, 0, 1));
|
|
|
|
#if WITH_JANSSON
|
|
g_assert(nm_json_vt());
|
|
#else
|
|
g_assert(!nm_json_vt());
|
|
#endif
|
|
|
|
#if WITH_JANSSON != defined(JANSSON_SONAME)
|
|
#error "WITH_JANSON and JANSSON_SONAME are defined inconsistently."
|
|
#endif
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_test_team_config_sync(const char *team_config,
|
|
int notify_peer_count,
|
|
int notify_peers_interval,
|
|
int mcast_rejoin_count,
|
|
int mcast_rejoin_interval,
|
|
char * runner,
|
|
char * runner_hwaddr_policy, /* activebackup */
|
|
GPtrArray * runner_tx_hash, /* lacp, loadbalance */
|
|
char * runner_tx_balancer, /* lacp, loadbalance */
|
|
int runner_tx_balancer_interval, /* lacp, loadbalance */
|
|
gboolean runner_active, /* lacp */
|
|
gboolean runner_fast_rate, /* lacp */
|
|
int runner_sys_prio, /* lacp */
|
|
int runner_min_ports, /* lacp */
|
|
char * runner_agg_select_policy, /* lacp */
|
|
GPtrArray * link_watchers)
|
|
{
|
|
gs_unref_object NMSettingTeam *s_team = NULL;
|
|
guint i, j;
|
|
gboolean found;
|
|
|
|
if (!nm_json_vt()) {
|
|
g_test_skip("team test requires JSON validation");
|
|
return;
|
|
}
|
|
|
|
s_team = (NMSettingTeam *) nm_setting_team_new();
|
|
g_assert(s_team);
|
|
|
|
g_object_set(s_team, NM_SETTING_TEAM_CONFIG, team_config, NULL);
|
|
g_assert_cmpint(nm_setting_team_get_notify_peers_count(s_team), ==, notify_peer_count);
|
|
g_assert_cmpint(nm_setting_team_get_notify_peers_interval(s_team), ==, notify_peers_interval);
|
|
g_assert_cmpint(nm_setting_team_get_mcast_rejoin_count(s_team), ==, mcast_rejoin_count);
|
|
g_assert_cmpint(nm_setting_team_get_mcast_rejoin_interval(s_team), ==, mcast_rejoin_interval);
|
|
g_assert_cmpint(nm_setting_team_get_runner_tx_balancer_interval(s_team),
|
|
==,
|
|
runner_tx_balancer_interval);
|
|
g_assert_cmpint(nm_setting_team_get_runner_active(s_team), ==, runner_active);
|
|
g_assert_cmpint(nm_setting_team_get_runner_fast_rate(s_team), ==, runner_fast_rate);
|
|
g_assert_cmpint(nm_setting_team_get_runner_sys_prio(s_team), ==, runner_sys_prio);
|
|
g_assert_cmpint(nm_setting_team_get_runner_min_ports(s_team), ==, runner_min_ports);
|
|
g_assert_cmpstr(nm_setting_team_get_runner(s_team), ==, runner);
|
|
g_assert_cmpstr(nm_setting_team_get_runner_hwaddr_policy(s_team), ==, runner_hwaddr_policy);
|
|
g_assert_cmpstr(nm_setting_team_get_runner_tx_balancer(s_team), ==, runner_tx_balancer);
|
|
g_assert_cmpstr(nm_setting_team_get_runner_agg_select_policy(s_team),
|
|
==,
|
|
runner_agg_select_policy);
|
|
|
|
if (runner_tx_hash) {
|
|
g_assert_cmpint(runner_tx_hash->len, ==, nm_setting_team_get_num_runner_tx_hash(s_team));
|
|
for (i = 0; i < runner_tx_hash->len; i++) {
|
|
found = FALSE;
|
|
for (j = 0; j < nm_setting_team_get_num_runner_tx_hash(s_team); j++) {
|
|
if (nm_streq0(nm_setting_team_get_runner_tx_hash(s_team, j),
|
|
runner_tx_hash->pdata[i])) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
g_assert(found);
|
|
}
|
|
}
|
|
|
|
if (link_watchers) {
|
|
g_assert_cmpint(link_watchers->len, ==, nm_setting_team_get_num_link_watchers(s_team));
|
|
for (i = 0; i < link_watchers->len; i++) {
|
|
found = FALSE;
|
|
for (j = 0; j < nm_setting_team_get_num_link_watchers(s_team); j++) {
|
|
if (nm_team_link_watcher_equal(link_watchers->pdata[i],
|
|
nm_setting_team_get_link_watcher(s_team, j))) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
g_assert(found);
|
|
}
|
|
}
|
|
|
|
g_assert(nm_setting_verify((NMSetting *) s_team, NULL, NULL));
|
|
}
|
|
|
|
static void
|
|
test_runner_roundrobin_sync_from_config(void)
|
|
{
|
|
_test_team_config_sync("",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
test_runner_broadcast_sync_from_config(void)
|
|
{
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"broadcast\"}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NM_SETTING_TEAM_RUNNER_BROADCAST,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
test_runner_random_sync_from_config(void)
|
|
{
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"random\"}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NM_SETTING_TEAM_RUNNER_RANDOM,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
test_runner_activebackup_sync_from_config(void)
|
|
{
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"activebackup\"}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
test_runner_loadbalance_sync_from_config(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *tx_hash = NULL;
|
|
|
|
tx_hash = g_ptr_array_new_with_free_func(g_free);
|
|
g_ptr_array_add(tx_hash, g_strdup("eth"));
|
|
g_ptr_array_add(tx_hash, g_strdup("ipv4"));
|
|
g_ptr_array_add(tx_hash, g_strdup("ipv6"));
|
|
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"loadbalance\"}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL);
|
|
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"loadbalance\", "
|
|
"\"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
|
|
NULL,
|
|
tx_hash,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL);
|
|
|
|
_test_team_config_sync(
|
|
"{\"runner\": {\"name\": \"loadbalance\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"], "
|
|
"\"tx_balancer\": {\"name\": \"basic\", \"balancing_interval\": 30}}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
|
|
NULL,
|
|
tx_hash,
|
|
"basic",
|
|
30,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
test_runner_lacp_sync_from_config(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *tx_hash = NULL;
|
|
|
|
tx_hash = g_ptr_array_new_with_free_func(g_free);
|
|
g_ptr_array_add(tx_hash, g_strdup("eth"));
|
|
g_ptr_array_add(tx_hash, g_strdup("ipv4"));
|
|
g_ptr_array_add(tx_hash, g_strdup("ipv6"));
|
|
|
|
_test_team_config_sync(
|
|
"{\"runner\": {\"name\": \"lacp\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NM_SETTING_TEAM_RUNNER_LACP,
|
|
NULL,
|
|
tx_hash,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL);
|
|
|
|
_test_team_config_sync(
|
|
"{\"runner\": {\"name\": \"lacp\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"], "
|
|
"\"active\": false, \"fast_rate\": true, \"sys_prio\": 10, \"min_ports\": 5, "
|
|
"\"agg_select_policy\": \"port_config\"}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NM_SETTING_TEAM_RUNNER_LACP,
|
|
NULL,
|
|
tx_hash,
|
|
NULL,
|
|
-1,
|
|
FALSE,
|
|
TRUE,
|
|
10,
|
|
5,
|
|
"port_config",
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
test_watcher_ethtool_sync_from_config(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
|
|
|
link_watchers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_team_link_watcher_unref);
|
|
g_ptr_array_add(link_watchers, nm_team_link_watcher_new_ethtool(0, 0, NULL));
|
|
_test_team_config_sync("{\"link_watch\": {\"name\": \"ethtool\"}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
link_watchers);
|
|
}
|
|
|
|
static void
|
|
test_watcher_nsna_ping_sync_from_config(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
|
|
|
link_watchers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_team_link_watcher_unref);
|
|
g_ptr_array_add(link_watchers,
|
|
nm_team_link_watcher_new_nsna_ping(0, 0, 3, "target.host", NULL));
|
|
_test_team_config_sync(
|
|
"{\"link_watch\": {\"name\": \"nsna_ping\", \"target_host\": \"target.host\"}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
link_watchers);
|
|
}
|
|
|
|
static void
|
|
test_watcher_arp_ping_sync_from_config(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
|
|
|
link_watchers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_team_link_watcher_unref);
|
|
g_ptr_array_add(
|
|
link_watchers,
|
|
nm_team_link_watcher_new_arp_ping(0, 0, 3, "target.host", "source.host", 0, NULL));
|
|
_test_team_config_sync(
|
|
"{\"link_watch\": {\"name\": \"arp_ping\", \"target_host\": \"target.host\", "
|
|
"\"source_host\": \"source.host\"}}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
link_watchers);
|
|
}
|
|
|
|
static void
|
|
test_multiple_watchers_sync_from_config(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
|
|
|
link_watchers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_team_link_watcher_unref);
|
|
g_ptr_array_add(link_watchers, nm_team_link_watcher_new_ethtool(2, 4, NULL));
|
|
g_ptr_array_add(link_watchers,
|
|
nm_team_link_watcher_new_nsna_ping(3, 6, 9, "target.host", NULL));
|
|
g_ptr_array_add(
|
|
link_watchers,
|
|
nm_team_link_watcher_new_arp_ping(5,
|
|
10,
|
|
15,
|
|
"target.host",
|
|
"source.host",
|
|
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE
|
|
| NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE
|
|
| NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS,
|
|
NULL));
|
|
_test_team_config_sync(
|
|
"{\"link_watch\": ["
|
|
"{\"name\": \"ethtool\", \"delay_up\": 2, \"delay_down\": 4}, "
|
|
"{\"name\": \"arp_ping\", \"init_wait\": 5, \"interval\": 10, \"missed_max\": 15, "
|
|
"\"target_host\": \"target.host\", \"source_host\": \"source.host\", "
|
|
"\"validate_active\": true, \"validate_inactive\": true, \"send_always\": true}, "
|
|
"{\"name\": \"nsna_ping\", \"init_wait\": 3, \"interval\": 6, \"missed_max\": 9, "
|
|
"\"target_host\": \"target.host\"}]}",
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
TRUE,
|
|
FALSE,
|
|
-1,
|
|
-1,
|
|
NULL,
|
|
link_watchers);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_test_team_port_config_sync(const char *team_port_config,
|
|
int queue_id,
|
|
int prio,
|
|
gboolean sticky,
|
|
int lacp_prio,
|
|
int lacp_key,
|
|
GPtrArray * link_watchers)
|
|
{
|
|
gs_unref_object NMSettingTeamPort *s_team_port = NULL;
|
|
guint i, j;
|
|
gboolean found;
|
|
|
|
if (!nm_json_vt()) {
|
|
g_test_skip("team test requires JSON validation");
|
|
return;
|
|
}
|
|
|
|
s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new();
|
|
g_assert(s_team_port);
|
|
|
|
g_object_set(s_team_port, NM_SETTING_TEAM_CONFIG, team_port_config, NULL);
|
|
g_assert(nm_setting_team_port_get_queue_id(s_team_port) == queue_id);
|
|
g_assert(nm_setting_team_port_get_prio(s_team_port) == prio);
|
|
g_assert(nm_setting_team_port_get_sticky(s_team_port) == sticky);
|
|
g_assert(nm_setting_team_port_get_lacp_prio(s_team_port) == lacp_prio);
|
|
g_assert(nm_setting_team_port_get_lacp_key(s_team_port) == lacp_key);
|
|
|
|
if (link_watchers) {
|
|
g_assert(link_watchers->len == nm_setting_team_port_get_num_link_watchers(s_team_port));
|
|
for (i = 0; i < link_watchers->len; i++) {
|
|
found = FALSE;
|
|
for (j = 0; j < nm_setting_team_port_get_num_link_watchers(s_team_port); j++) {
|
|
if (nm_team_link_watcher_equal(
|
|
link_watchers->pdata[i],
|
|
nm_setting_team_port_get_link_watcher(s_team_port, j))) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
g_assert(found);
|
|
}
|
|
}
|
|
|
|
g_assert(nm_setting_verify((NMSetting *) s_team_port, NULL, NULL));
|
|
}
|
|
|
|
static void
|
|
test_team_port_default(void)
|
|
{
|
|
_test_team_port_config_sync("", -1, 0, FALSE, -1, -1, NULL);
|
|
}
|
|
|
|
static void
|
|
test_team_port_queue_id(void)
|
|
{
|
|
_test_team_port_config_sync("{\"queue_id\": 3}", 3, 0, FALSE, -1, -1, NULL);
|
|
_test_team_port_config_sync("{\"queue_id\": 0}", 0, 0, FALSE, -1, -1, NULL);
|
|
}
|
|
|
|
static void
|
|
test_team_port_prio(void)
|
|
{
|
|
_test_team_port_config_sync("{\"prio\": 6}", -1, 6, FALSE, -1, -1, NULL);
|
|
_test_team_port_config_sync("{\"prio\": 0}", -1, 0, FALSE, -1, -1, NULL);
|
|
}
|
|
|
|
static void
|
|
test_team_port_sticky(void)
|
|
{
|
|
_test_team_port_config_sync("{\"sticky\": true}", -1, 0, TRUE, -1, -1, NULL);
|
|
_test_team_port_config_sync("{\"sticky\": false}", -1, 0, FALSE, -1, -1, NULL);
|
|
}
|
|
|
|
static void
|
|
test_team_port_lacp_prio(void)
|
|
{
|
|
_test_team_port_config_sync("{\"lacp_prio\": 9}", -1, 0, FALSE, 9, -1, NULL);
|
|
_test_team_port_config_sync("{\"lacp_prio\": 0}", -1, 0, FALSE, 0, -1, NULL);
|
|
}
|
|
|
|
static void
|
|
test_team_port_lacp_key(void)
|
|
{
|
|
_test_team_port_config_sync("{\"lacp_key\": 12}", -1, 0, FALSE, -1, 12, NULL);
|
|
_test_team_port_config_sync("{\"lacp_key\": 0}", -1, 0, FALSE, -1, 0, NULL);
|
|
}
|
|
|
|
static void
|
|
test_team_port_full_config(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
|
|
|
link_watchers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_team_link_watcher_unref);
|
|
g_ptr_array_add(
|
|
link_watchers,
|
|
nm_team_link_watcher_new_arp_ping(0,
|
|
3,
|
|
3,
|
|
"1.2.3.2",
|
|
"1.2.3.1",
|
|
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE,
|
|
NULL));
|
|
g_ptr_array_add(
|
|
link_watchers,
|
|
nm_team_link_watcher_new_arp_ping(1,
|
|
1,
|
|
0,
|
|
"1.2.3.4",
|
|
"1.2.3.1",
|
|
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS,
|
|
NULL));
|
|
|
|
_test_team_port_config_sync(
|
|
"{\"queue_id\": 10, \"prio\": 20, \"sticky\": true, \"lacp_prio\": 30, "
|
|
"\"lacp_key\": 40, \"link_watch\": ["
|
|
"{\"name\": \"arp_ping\", \"interval\": 3, \"target_host\": \"1.2.3.2\", "
|
|
"\"source_host\": \"1.2.3.1\", \"validate_inactive\": true}, "
|
|
"{\"name\": \"arp_ping\", \"init_wait\": 1, \"interval\": 1, "
|
|
"\"target_host\": \"1.2.3.4\", \"source_host\": \"1.2.3.1\", "
|
|
"\"send_always\": true}]}",
|
|
10,
|
|
20,
|
|
true,
|
|
30,
|
|
40,
|
|
NULL);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_check_team_setting(NMSetting *setting)
|
|
{
|
|
gs_unref_object NMSetting *setting2 = NULL;
|
|
gs_unref_object NMSetting *setting_clone = NULL;
|
|
gboolean is_port = NM_IS_SETTING_TEAM_PORT(setting);
|
|
gs_unref_variant GVariant *variant2 = NULL;
|
|
gs_unref_variant GVariant *variant3 = NULL;
|
|
|
|
g_assert(NM_IS_SETTING_TEAM(setting) || is_port);
|
|
|
|
setting2 = g_object_new(G_OBJECT_TYPE(setting),
|
|
is_port ? NM_SETTING_TEAM_PORT_CONFIG : NM_SETTING_TEAM_CONFIG,
|
|
is_port ? nm_setting_team_port_get_config(NM_SETTING_TEAM_PORT(setting))
|
|
: nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
NULL);
|
|
|
|
if (nm_json_vt())
|
|
nmtst_assert_setting_is_equal(setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT);
|
|
|
|
g_clear_object(&setting2);
|
|
|
|
nmtst_assert_setting_dbus_roundtrip(setting);
|
|
|
|
/* OK, now parse the setting only from the D-Bus variant, but removing the JSON config.
|
|
* For that, we have to "drop" the JSON and we do that by resetting the property.
|
|
* This causes JSON to be regenerated and it's in a normalized form that will compare
|
|
* equal. */
|
|
setting_clone = nm_setting_duplicate(setting);
|
|
setting = setting_clone;
|
|
if (is_port) {
|
|
g_object_set(setting,
|
|
NM_SETTING_TEAM_PORT_STICKY,
|
|
nm_setting_team_port_get_sticky(NM_SETTING_TEAM_PORT(setting)),
|
|
NULL);
|
|
} else {
|
|
g_object_set(setting,
|
|
NM_SETTING_TEAM_RUNNER_SYS_PRIO,
|
|
nm_setting_team_get_runner_sys_prio(NM_SETTING_TEAM(setting)),
|
|
NULL);
|
|
}
|
|
variant2 = _nm_setting_to_dbus(setting, NULL, NM_CONNECTION_SERIALIZE_ALL, NULL);
|
|
variant3 = nm_utils_gvariant_vardict_filter_drop_one(variant2, "config");
|
|
setting2 = nmtst_assert_setting_dbus_new(G_OBJECT_TYPE(setting), variant3);
|
|
nmtst_assert_setting_is_equal(setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT);
|
|
}
|
|
|
|
static void
|
|
test_team_setting(void)
|
|
{
|
|
gs_unref_variant GVariant *variant = nmtst_variant_from_string(
|
|
G_VARIANT_TYPE_VARDICT,
|
|
"{'config': <'{\"link_watch\": {\"name\": \"ethtool\"}}'>, 'interface-name': <'nm-team'>, "
|
|
"'link-watchers': <[{'name': <'ethtool'>}]>}");
|
|
gs_free_error GError *error = NULL;
|
|
gs_unref_object NMSetting * setting = NULL;
|
|
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher1 =
|
|
nm_team_link_watcher_new_nsna_ping(1, 3, 4, "bbb", NULL);
|
|
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher2 =
|
|
nm_team_link_watcher_new_arp_ping2(1, 3, 4, -1, "ccc", "ddd", 0, NULL);
|
|
|
|
g_assert(watcher1);
|
|
g_assert(watcher2);
|
|
|
|
setting = _nm_setting_new_from_dbus(NM_TYPE_SETTING_TEAM,
|
|
variant,
|
|
NULL,
|
|
NM_SETTING_PARSE_FLAGS_STRICT,
|
|
&error);
|
|
nmtst_assert_success(setting, error);
|
|
_check_team_setting(setting);
|
|
|
|
g_assert_cmpstr(nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
==,
|
|
"{\"link_watch\": {\"name\": \"ethtool\"}}");
|
|
g_assert_cmpint(nm_setting_team_get_num_link_watchers(NM_SETTING_TEAM(setting)), ==, 1);
|
|
|
|
g_object_set(setting, NM_SETTING_TEAM_RUNNER_SYS_PRIO, (int) 10, NULL);
|
|
|
|
_check_team_setting(setting);
|
|
g_assert_cmpint(nm_setting_team_get_num_link_watchers(NM_SETTING_TEAM(setting)), ==, 1);
|
|
g_assert_cmpstr(
|
|
nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
==,
|
|
"{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"ethtool\" } }");
|
|
|
|
nm_setting_team_remove_link_watcher(NM_SETTING_TEAM(setting), 0);
|
|
|
|
_check_team_setting(setting);
|
|
g_assert_cmpint(nm_setting_team_get_num_link_watchers(NM_SETTING_TEAM(setting)), ==, 0);
|
|
g_assert_cmpstr(nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
==,
|
|
"{ \"runner\": { \"sys_prio\": 10 } }");
|
|
|
|
nm_setting_team_add_link_watcher(NM_SETTING_TEAM(setting), watcher1);
|
|
_check_team_setting(setting);
|
|
g_assert_cmpstr(
|
|
nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
==,
|
|
"{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"nsna_ping\", "
|
|
"\"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, \"target_host\": \"bbb\" } }");
|
|
|
|
nm_setting_team_add_link_watcher(NM_SETTING_TEAM(setting), watcher2);
|
|
_check_team_setting(setting);
|
|
g_assert_cmpstr(
|
|
nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
==,
|
|
"{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": [ { \"name\": \"nsna_ping\", "
|
|
"\"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, \"target_host\": \"bbb\" }, { "
|
|
"\"name\": \"arp_ping\", \"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, "
|
|
"\"source_host\": \"ddd\", \"target_host\": \"ccc\" } ] }");
|
|
|
|
nm_setting_team_remove_link_watcher(NM_SETTING_TEAM(setting), 0);
|
|
nm_setting_team_remove_link_watcher(NM_SETTING_TEAM(setting), 0);
|
|
g_object_set(setting, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, (int) 5, NULL);
|
|
g_assert_cmpstr(
|
|
nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
==,
|
|
"{ \"runner\": { \"tx_balancer\": { \"balancing_interval\": 5 }, \"sys_prio\": 10 } }");
|
|
|
|
g_object_set(setting, NM_SETTING_TEAM_RUNNER, NULL, NULL);
|
|
_check_team_setting(setting);
|
|
g_assert_cmpstr(
|
|
nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
==,
|
|
"{ \"runner\": { \"tx_balancer\": { \"balancing_interval\": 5 }, \"sys_prio\": 10 } }");
|
|
|
|
g_object_set(setting,
|
|
NM_SETTING_TEAM_CONFIG,
|
|
"{ \"runner\": { \"tx_hash\": [ \"eth\", \"l3\" ] } }",
|
|
NULL);
|
|
_check_team_setting(setting);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_setting_ethtool_set_feature(NMSettingEthtool *s_ethtool, const char *opt_name, NMTernary value)
|
|
{
|
|
g_assert(NM_IS_SETTING_ETHTOOL(s_ethtool));
|
|
|
|
if (nmtst_get_rand_bool()) {
|
|
nm_setting_ethtool_set_feature(s_ethtool, opt_name, value);
|
|
return;
|
|
}
|
|
|
|
if (value == NM_TERNARY_DEFAULT) {
|
|
nm_setting_option_set(NM_SETTING(s_ethtool), opt_name, NULL);
|
|
return;
|
|
}
|
|
|
|
if (nmtst_get_rand_bool())
|
|
nm_setting_option_set_boolean(NM_SETTING(s_ethtool), opt_name, value);
|
|
else
|
|
nm_setting_option_set(NM_SETTING(s_ethtool), opt_name, g_variant_new_boolean(value));
|
|
}
|
|
|
|
static NMTernary
|
|
_setting_ethtool_get_feature(NMSettingEthtool *s_ethtool, const char *opt_name)
|
|
{
|
|
GVariant *v;
|
|
gboolean b;
|
|
|
|
switch (nmtst_get_rand_uint32() % 3) {
|
|
case 0:
|
|
return nm_setting_ethtool_get_feature(s_ethtool, opt_name);
|
|
case 1:
|
|
if (!nm_setting_option_get_boolean(NM_SETTING(s_ethtool), opt_name, &b))
|
|
return NM_TERNARY_DEFAULT;
|
|
return b;
|
|
default:
|
|
v = nm_setting_option_get(NM_SETTING(s_ethtool), opt_name);
|
|
if (!v || !g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN))
|
|
return NM_TERNARY_DEFAULT;
|
|
return g_variant_get_boolean(v);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_ethtool_features(void)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
gs_unref_object NMConnection *con3 = NULL;
|
|
gs_unref_variant GVariant *variant = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
|
NMSettingConnection * s_con;
|
|
NMSettingEthtool * s_ethtool;
|
|
NMSettingEthtool * s_ethtool2;
|
|
NMSettingEthtool * s_ethtool3;
|
|
|
|
con = nmtst_create_minimal_connection("ethtool-1", NULL, NM_SETTING_WIRED_SETTING_NAME, &s_con);
|
|
s_ethtool = NM_SETTING_ETHTOOL(nm_setting_ethtool_new());
|
|
nm_connection_add_setting(con, NM_SETTING(s_ethtool));
|
|
|
|
_setting_ethtool_set_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX, NM_TERNARY_TRUE);
|
|
_setting_ethtool_set_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_LRO, NM_TERNARY_FALSE);
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX),
|
|
==,
|
|
NM_TERNARY_TRUE);
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_LRO),
|
|
==,
|
|
NM_TERNARY_FALSE);
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_SG),
|
|
==,
|
|
NM_TERNARY_DEFAULT);
|
|
|
|
nmtst_connection_normalize(con);
|
|
|
|
variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL);
|
|
|
|
con2 = nm_simple_connection_new_from_dbus(variant, &error);
|
|
nmtst_assert_success(con2, error);
|
|
|
|
s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL));
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_RX),
|
|
==,
|
|
NM_TERNARY_TRUE);
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_LRO),
|
|
==,
|
|
NM_TERNARY_FALSE);
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_SG),
|
|
==,
|
|
NM_TERNARY_DEFAULT);
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
|
|
|
nmtst_assert_connection_equals(con, FALSE, con2, FALSE);
|
|
|
|
keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
|
nmtst_assert_success(keyfile, error);
|
|
|
|
con3 = nm_keyfile_read(keyfile,
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(con3, error);
|
|
|
|
nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id");
|
|
nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid");
|
|
|
|
nmtst_connection_normalize(con3);
|
|
|
|
nmtst_assert_connection_equals(con, FALSE, con3, FALSE);
|
|
|
|
s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL));
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_RX),
|
|
==,
|
|
NM_TERNARY_TRUE);
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_LRO),
|
|
==,
|
|
NM_TERNARY_FALSE);
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_SG),
|
|
==,
|
|
NM_TERNARY_DEFAULT);
|
|
}
|
|
|
|
static void
|
|
test_ethtool_coalesce(void)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
gs_unref_object NMConnection *con3 = NULL;
|
|
gs_unref_variant GVariant *variant = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
|
NMSettingConnection * s_con;
|
|
NMSettingEthtool * s_ethtool;
|
|
NMSettingEthtool * s_ethtool2;
|
|
NMSettingEthtool * s_ethtool3;
|
|
guint32 u32;
|
|
|
|
con = nmtst_create_minimal_connection("ethtool-coalesce",
|
|
NULL,
|
|
NM_SETTING_WIRED_SETTING_NAME,
|
|
&s_con);
|
|
s_ethtool = NM_SETTING_ETHTOOL(nm_setting_ethtool_new());
|
|
nm_connection_add_setting(con, NM_SETTING(s_ethtool));
|
|
|
|
nm_setting_option_set_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, 4);
|
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
&u32));
|
|
g_assert_cmpuint(u32, ==, 4);
|
|
|
|
nmtst_connection_normalize(con);
|
|
|
|
variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL);
|
|
|
|
con2 = nm_simple_connection_new_from_dbus(variant, &error);
|
|
nmtst_assert_success(con2, error);
|
|
|
|
s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL));
|
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool2),
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
&u32));
|
|
g_assert_cmpuint(u32, ==, 4);
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
|
|
|
nmtst_assert_connection_equals(con, FALSE, con2, FALSE);
|
|
|
|
keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
|
nmtst_assert_success(keyfile, error);
|
|
|
|
con3 = nm_keyfile_read(keyfile,
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(con3, error);
|
|
|
|
nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id");
|
|
nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid");
|
|
|
|
nmtst_connection_normalize(con3);
|
|
|
|
nmtst_assert_connection_equals(con, FALSE, con3, FALSE);
|
|
|
|
s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL));
|
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool3),
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
&u32));
|
|
g_assert_cmpuint(u32, ==, 4);
|
|
|
|
nm_setting_option_set(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, NULL);
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
NULL));
|
|
|
|
nm_setting_option_set_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES, 8);
|
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES,
|
|
&u32));
|
|
g_assert_cmpuint(u32, ==, 8);
|
|
|
|
nm_setting_option_clear_by_name(NM_SETTING(s_ethtool), nm_ethtool_optname_is_coalesce);
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
NULL));
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES,
|
|
NULL));
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS,
|
|
NULL));
|
|
}
|
|
|
|
static void
|
|
test_ethtool_ring(void)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
gs_unref_object NMConnection *con3 = NULL;
|
|
gs_unref_variant GVariant *variant = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
|
NMSettingConnection * s_con;
|
|
NMSettingEthtool * s_ethtool;
|
|
NMSettingEthtool * s_ethtool2;
|
|
NMSettingEthtool * s_ethtool3;
|
|
guint32 out_value;
|
|
|
|
con = nmtst_create_minimal_connection("ethtool-ring",
|
|
NULL,
|
|
NM_SETTING_WIRED_SETTING_NAME,
|
|
&s_con);
|
|
s_ethtool = NM_SETTING_ETHTOOL(nm_setting_ethtool_new());
|
|
nm_connection_add_setting(con, NM_SETTING(s_ethtool));
|
|
|
|
nm_setting_option_set_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_RX_JUMBO, 4);
|
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
&out_value));
|
|
g_assert_cmpuint(out_value, ==, 4);
|
|
|
|
nmtst_connection_normalize(con);
|
|
|
|
variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL);
|
|
|
|
con2 = nm_simple_connection_new_from_dbus(variant, &error);
|
|
nmtst_assert_success(con2, error);
|
|
|
|
s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL));
|
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool2),
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
&out_value));
|
|
g_assert_cmpuint(out_value, ==, 4);
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
|
|
|
nmtst_assert_connection_equals(con, FALSE, con2, FALSE);
|
|
|
|
keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
|
nmtst_assert_success(keyfile, error);
|
|
|
|
con3 = nm_keyfile_read(keyfile,
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(con3, error);
|
|
|
|
nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id");
|
|
nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid");
|
|
|
|
nmtst_connection_normalize(con3);
|
|
|
|
nmtst_assert_connection_equals(con, FALSE, con3, FALSE);
|
|
|
|
s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL));
|
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool3),
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
&out_value));
|
|
g_assert_cmpuint(out_value, ==, 4);
|
|
|
|
nm_setting_option_set(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_RX_JUMBO, NULL);
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
NULL));
|
|
|
|
nm_setting_option_set_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_RX_JUMBO, 8);
|
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
&out_value));
|
|
g_assert_cmpuint(out_value, ==, 8);
|
|
|
|
nm_setting_option_clear_by_name(NM_SETTING(s_ethtool), nm_ethtool_optname_is_ring);
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
NULL));
|
|
g_assert_false(
|
|
nm_setting_option_get_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_RX, NULL));
|
|
g_assert_false(
|
|
nm_setting_option_get_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_TX, NULL));
|
|
}
|
|
|
|
static void
|
|
test_ethtool_pause(void)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
gs_unref_object NMConnection *con3 = NULL;
|
|
gs_unref_variant GVariant *variant = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
|
NMSettingConnection * s_con;
|
|
NMSettingEthtool * s_ethtool;
|
|
NMSettingEthtool * s_ethtool2;
|
|
NMSettingEthtool * s_ethtool3;
|
|
gboolean out_value;
|
|
|
|
con = nmtst_create_minimal_connection("ethtool-pause",
|
|
NULL,
|
|
NM_SETTING_WIRED_SETTING_NAME,
|
|
&s_con);
|
|
s_ethtool = NM_SETTING_ETHTOOL(nm_setting_ethtool_new());
|
|
nm_connection_add_setting(con, NM_SETTING(s_ethtool));
|
|
|
|
nm_setting_option_set_boolean(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG, FALSE);
|
|
nm_setting_option_set_boolean(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_PAUSE_RX, TRUE);
|
|
nm_setting_option_set_boolean(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_PAUSE_TX, TRUE);
|
|
|
|
g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG,
|
|
&out_value));
|
|
g_assert_true(!out_value);
|
|
g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_PAUSE_RX,
|
|
&out_value));
|
|
g_assert_true(out_value);
|
|
g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool),
|
|
NM_ETHTOOL_OPTNAME_PAUSE_TX,
|
|
&out_value));
|
|
g_assert_true(out_value);
|
|
|
|
nmtst_connection_normalize(con);
|
|
|
|
variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL);
|
|
|
|
con2 = nm_simple_connection_new_from_dbus(variant, &error);
|
|
nmtst_assert_success(con2, error);
|
|
|
|
s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL));
|
|
|
|
g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool2),
|
|
NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG,
|
|
&out_value));
|
|
g_assert_true(!out_value);
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
|
|
|
nmtst_assert_connection_equals(con, FALSE, con2, FALSE);
|
|
|
|
con2 = nm_simple_connection_new_from_dbus(variant, &error);
|
|
nmtst_assert_success(con2, error);
|
|
|
|
keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
|
nmtst_assert_success(keyfile, error);
|
|
|
|
con3 = nm_keyfile_read(keyfile,
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(con3, error);
|
|
|
|
nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id");
|
|
nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid");
|
|
|
|
nmtst_connection_normalize(con3);
|
|
|
|
nmtst_assert_connection_equals(con, FALSE, con3, FALSE);
|
|
|
|
s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL));
|
|
|
|
g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool3),
|
|
NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG,
|
|
&out_value));
|
|
g_assert_true(!out_value);
|
|
g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool3),
|
|
NM_ETHTOOL_OPTNAME_PAUSE_RX,
|
|
&out_value));
|
|
g_assert_true(out_value);
|
|
g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool3),
|
|
NM_ETHTOOL_OPTNAME_PAUSE_TX,
|
|
&out_value));
|
|
g_assert_true(out_value);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_sriov_vf(void)
|
|
{
|
|
NMSriovVF *vf1, *vf2;
|
|
GError * error = NULL;
|
|
char * str;
|
|
|
|
vf1 = nm_sriov_vf_new(1);
|
|
nm_sriov_vf_set_attribute(vf1,
|
|
NM_SRIOV_VF_ATTRIBUTE_MAC,
|
|
g_variant_new_string("00:11:22:33:44:55"));
|
|
nm_sriov_vf_set_attribute(vf1, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, g_variant_new_boolean(TRUE));
|
|
nm_sriov_vf_set_attribute(vf1, NM_SRIOV_VF_ATTRIBUTE_TRUST, g_variant_new_boolean(FALSE));
|
|
nm_sriov_vf_set_attribute(vf1, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE, g_variant_new_uint32(100));
|
|
nm_sriov_vf_set_attribute(vf1, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE, g_variant_new_uint32(500));
|
|
|
|
str = nm_utils_sriov_vf_to_str(vf1, FALSE, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_cmpstr(
|
|
str,
|
|
==,
|
|
"1 mac=00:11:22:33:44:55 max-tx-rate=500 min-tx-rate=100 spoof-check=true trust=false");
|
|
g_free(str);
|
|
|
|
vf2 = nm_utils_sriov_vf_from_str(" 1 mac=00:11:22:33:44:55 max-tx-rate=500 min-tx-rate=100",
|
|
&error);
|
|
nmtst_assert_success(vf2, error);
|
|
nm_sriov_vf_set_attribute(vf2, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, g_variant_new_boolean(FALSE));
|
|
nm_sriov_vf_set_attribute(vf2, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, g_variant_new_boolean(TRUE));
|
|
nm_sriov_vf_set_attribute(vf2, NM_SRIOV_VF_ATTRIBUTE_TRUST, g_variant_new_boolean(TRUE));
|
|
nm_sriov_vf_set_attribute(vf2, NM_SRIOV_VF_ATTRIBUTE_TRUST, NULL);
|
|
nm_sriov_vf_set_attribute(vf2, NM_SRIOV_VF_ATTRIBUTE_TRUST, g_variant_new_boolean(FALSE));
|
|
|
|
g_assert(nm_sriov_vf_equal(vf1, vf2));
|
|
|
|
nm_sriov_vf_unref(vf1);
|
|
nm_sriov_vf_unref(vf2);
|
|
}
|
|
|
|
static void
|
|
test_sriov_vf_dup(void)
|
|
{
|
|
NMSriovVF *vf1, *vf2;
|
|
|
|
vf1 = nm_sriov_vf_new(1);
|
|
nm_sriov_vf_set_attribute(vf1, NM_SRIOV_VF_ATTRIBUTE_MAC, g_variant_new_string("foobar"));
|
|
nm_sriov_vf_set_attribute(vf1, NM_SRIOV_VF_ATTRIBUTE_TRUST, g_variant_new_boolean(FALSE));
|
|
nm_sriov_vf_set_attribute(vf1, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE, g_variant_new_uint32(10));
|
|
nm_sriov_vf_set_attribute(vf1, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE, g_variant_new_uint32(1000));
|
|
nm_sriov_vf_add_vlan(vf1, 80);
|
|
nm_sriov_vf_set_vlan_qos(vf1, 80, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
|
|
|
|
vf2 = nm_sriov_vf_dup(vf1);
|
|
g_assert(nm_sriov_vf_equal(vf1, vf2));
|
|
|
|
nm_sriov_vf_unref(vf1);
|
|
nm_sriov_vf_unref(vf2);
|
|
}
|
|
|
|
static void
|
|
test_sriov_vf_vlan(void)
|
|
{
|
|
NMSriovVF * vf;
|
|
const guint * vlan_ids;
|
|
guint num;
|
|
GError * error = NULL;
|
|
gs_free char *str = NULL;
|
|
|
|
vf = nm_sriov_vf_new(19);
|
|
nm_sriov_vf_set_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_MAC, g_variant_new_string("00:11:22"));
|
|
g_assert(nm_sriov_vf_add_vlan(vf, 80));
|
|
g_assert(!nm_sriov_vf_add_vlan(vf, 80));
|
|
g_assert(nm_sriov_vf_add_vlan(vf, 82));
|
|
g_assert(nm_sriov_vf_add_vlan(vf, 83));
|
|
g_assert(nm_sriov_vf_add_vlan(vf, 81));
|
|
g_assert(!nm_sriov_vf_remove_vlan(vf, 100));
|
|
g_assert(nm_sriov_vf_remove_vlan(vf, 82));
|
|
nm_sriov_vf_set_vlan_qos(vf, 81, 0xabba);
|
|
nm_sriov_vf_set_vlan_protocol(vf, 81, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
|
|
|
|
vlan_ids = nm_sriov_vf_get_vlan_ids(vf, &num);
|
|
g_assert(vlan_ids);
|
|
g_assert_cmpint(num, ==, 3);
|
|
g_assert_cmpint(vlan_ids[0], ==, 80);
|
|
g_assert_cmpint(vlan_ids[1], ==, 81);
|
|
g_assert_cmpint(vlan_ids[2], ==, 83);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_qos(vf, 80), ==, 0x0);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_protocol(vf, 80), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_qos(vf, 81), ==, 0xabba);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_protocol(vf, 81), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
|
|
|
|
nm_sriov_vf_unref(vf);
|
|
|
|
vf = nm_utils_sriov_vf_from_str("20 spoof-check=false vlans=85.0.q;4000.0x20.ad;81.10;83",
|
|
&error);
|
|
nmtst_assert_success(vf, error);
|
|
vlan_ids = nm_sriov_vf_get_vlan_ids(vf, &num);
|
|
g_assert(vlan_ids);
|
|
g_assert_cmpint(num, ==, 4);
|
|
g_assert_cmpint(vlan_ids[0], ==, 81);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_qos(vf, 81), ==, 10);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_protocol(vf, 81), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
|
|
g_assert_cmpint(vlan_ids[1], ==, 83);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_qos(vf, 83), ==, 0);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_protocol(vf, 83), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
|
|
g_assert_cmpint(vlan_ids[2], ==, 85);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_qos(vf, 85), ==, 0);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_protocol(vf, 85), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
|
|
g_assert_cmpint(vlan_ids[3], ==, 4000);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_qos(vf, 4000), ==, 0x20);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_protocol(vf, 4000), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
|
|
|
|
str = nm_utils_sriov_vf_to_str(vf, FALSE, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "20 spoof-check=false vlans=81.10;83;85;4000.32.ad");
|
|
|
|
nm_sriov_vf_unref(vf);
|
|
}
|
|
|
|
static void
|
|
test_sriov_setting(void)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
NMSettingConnection * s_con;
|
|
NMSettingSriov * s_sriov = NULL;
|
|
NMSriovVF * vf1, *vf2, *vf3;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
|
|
con = nm_simple_connection_new();
|
|
|
|
s_con = (NMSettingConnection *) nm_setting_connection_new();
|
|
nm_connection_add_setting(con, NM_SETTING(s_con));
|
|
|
|
g_object_set(s_con,
|
|
NM_SETTING_CONNECTION_ID,
|
|
"Test SR-IOV connection",
|
|
NM_SETTING_CONNECTION_UUID,
|
|
nm_uuid_generate_random_str_a(),
|
|
NM_SETTING_CONNECTION_AUTOCONNECT,
|
|
TRUE,
|
|
NM_SETTING_CONNECTION_INTERFACE_NAME,
|
|
"eth0",
|
|
NM_SETTING_CONNECTION_TYPE,
|
|
NM_SETTING_WIRED_SETTING_NAME,
|
|
NULL);
|
|
|
|
nm_connection_add_setting(con, nm_setting_wired_new());
|
|
|
|
s_sriov = (NMSettingSriov *) nm_setting_sriov_new();
|
|
nm_connection_add_setting(con, NM_SETTING(s_sriov));
|
|
|
|
g_object_set(s_sriov, NM_SETTING_SRIOV_TOTAL_VFS, 16, NULL);
|
|
nm_setting_sriov_add_vf(s_sriov, (vf1 = nm_sriov_vf_new(0)));
|
|
nm_setting_sriov_add_vf(s_sriov, (vf2 = nm_sriov_vf_new(4)));
|
|
nm_setting_sriov_add_vf(s_sriov, (vf3 = nm_sriov_vf_new(10)));
|
|
g_assert(nm_setting_sriov_remove_vf_by_index(s_sriov, 4));
|
|
nm_sriov_vf_unref(vf2);
|
|
nm_setting_sriov_add_vf(s_sriov, (vf2 = nm_sriov_vf_new(2)));
|
|
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
nmtst_connection_normalize(con);
|
|
success = nm_setting_verify((NMSetting *) s_sriov, con, &error);
|
|
nmtst_assert_success(success, error);
|
|
|
|
g_assert_cmpint(nm_setting_sriov_get_num_vfs(s_sriov), ==, 3);
|
|
g_assert_cmpint(nm_sriov_vf_get_index(nm_setting_sriov_get_vf(s_sriov, 0)), ==, 0);
|
|
g_assert_cmpint(nm_sriov_vf_get_index(nm_setting_sriov_get_vf(s_sriov, 1)), ==, 2);
|
|
g_assert_cmpint(nm_sriov_vf_get_index(nm_setting_sriov_get_vf(s_sriov, 2)), ==, 10);
|
|
|
|
nm_sriov_vf_unref(vf1);
|
|
nm_sriov_vf_unref(vf2);
|
|
nm_sriov_vf_unref(vf3);
|
|
}
|
|
|
|
typedef struct {
|
|
guint id;
|
|
guint qos;
|
|
bool proto_ad;
|
|
} VlanData;
|
|
|
|
static void
|
|
_test_sriov_parse_vlan_one(const char *string, gboolean exp_res, VlanData *data, guint data_length)
|
|
{
|
|
NMSriovVF * vf;
|
|
gboolean res;
|
|
guint i, num_vlans;
|
|
const guint *vlan_ids;
|
|
|
|
vf = nm_sriov_vf_new(1);
|
|
g_assert(vf);
|
|
|
|
res = _nm_sriov_vf_parse_vlans(vf, string, NULL);
|
|
g_assert_cmpint(res, ==, exp_res);
|
|
|
|
if (exp_res) {
|
|
vlan_ids = nm_sriov_vf_get_vlan_ids(vf, &num_vlans);
|
|
g_assert_cmpint(num_vlans, ==, data_length);
|
|
for (i = 0; i < num_vlans; i++) {
|
|
g_assert_cmpint(vlan_ids[i], ==, data[i].id);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_qos(vf, vlan_ids[i]), ==, data[i].qos);
|
|
g_assert_cmpint(nm_sriov_vf_get_vlan_protocol(vf, vlan_ids[i]),
|
|
==,
|
|
data[i].proto_ad ? NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD
|
|
: NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
|
|
}
|
|
}
|
|
|
|
nm_sriov_vf_unref(vf);
|
|
}
|
|
|
|
#define test_sriov_parse_vlan_one(string, result, ...) \
|
|
{ \
|
|
VlanData _data[] = {__VA_ARGS__}; \
|
|
guint _length = G_N_ELEMENTS(_data); \
|
|
\
|
|
_test_sriov_parse_vlan_one(string, result, _data, _length); \
|
|
}
|
|
|
|
static void
|
|
test_sriov_parse_vlans(void)
|
|
{
|
|
test_sriov_parse_vlan_one("", FALSE, {});
|
|
test_sriov_parse_vlan_one("1", TRUE, {1, 0, 0});
|
|
test_sriov_parse_vlan_one("1;2", TRUE, {1, 0, 0}, {2, 0, 0});
|
|
test_sriov_parse_vlan_one("4095;;2", TRUE, {2, 0, 0}, {4095, 0, 0});
|
|
test_sriov_parse_vlan_one("1 2", FALSE, {});
|
|
test_sriov_parse_vlan_one("4096", FALSE, {});
|
|
test_sriov_parse_vlan_one("1.10", TRUE, {1, 10, 0});
|
|
test_sriov_parse_vlan_one("1.20.ad", TRUE, {1, 20, 1});
|
|
test_sriov_parse_vlan_one("1.21.q", TRUE, {1, 21, 0});
|
|
test_sriov_parse_vlan_one("9.20.foo", FALSE, {});
|
|
test_sriov_parse_vlan_one("1.20.ad.12", FALSE, {});
|
|
test_sriov_parse_vlan_one("1;1.10", FALSE, {});
|
|
test_sriov_parse_vlan_one("1..1;2", FALSE, {});
|
|
test_sriov_parse_vlan_one("1..ad;2", FALSE, {});
|
|
test_sriov_parse_vlan_one("1.2.ad;2.0.q;5;3", TRUE, {1, 2, 1}, {2, 0, 0}, {3, 0, 0}, {5, 0, 0});
|
|
}
|
|
|
|
static void
|
|
test_bridge_vlans(void)
|
|
{
|
|
NMBridgeVlan *v1, *v2;
|
|
GError * error = NULL;
|
|
guint16 vid_start, vid_end;
|
|
char * str;
|
|
|
|
v1 = nm_bridge_vlan_from_str("1 foobar", &error);
|
|
nmtst_assert_no_success(v1, error);
|
|
g_clear_error(&error);
|
|
|
|
v1 = nm_bridge_vlan_from_str("4095", &error);
|
|
nmtst_assert_no_success(v1, error);
|
|
g_clear_error(&error);
|
|
|
|
/* test ranges */
|
|
v1 = nm_bridge_vlan_from_str("2-1000 untagged", &error);
|
|
nmtst_assert_success(v1, error);
|
|
g_assert_cmpint(nm_bridge_vlan_get_vid_range(v1, &vid_start, &vid_end), ==, TRUE);
|
|
g_assert_cmpuint(vid_start, ==, 2);
|
|
g_assert_cmpuint(vid_end, ==, 1000);
|
|
g_assert_cmpint(nm_bridge_vlan_is_pvid(v1), ==, FALSE);
|
|
g_assert_cmpint(nm_bridge_vlan_is_untagged(v1), ==, TRUE);
|
|
nm_bridge_vlan_unref(v1);
|
|
|
|
/* test comparison (1) */
|
|
v1 = nm_bridge_vlan_from_str("10 untagged", &error);
|
|
nmtst_assert_success(v1, error);
|
|
|
|
g_assert_cmpint(nm_bridge_vlan_get_vid_range(v1, &vid_start, &vid_end), ==, FALSE);
|
|
g_assert_cmpuint(vid_start, ==, 10);
|
|
g_assert_cmpuint(vid_end, ==, 10);
|
|
g_assert_cmpint(nm_bridge_vlan_is_sealed(v1), ==, FALSE);
|
|
g_assert_cmpint(nm_bridge_vlan_is_pvid(v1), ==, FALSE);
|
|
g_assert_cmpint(nm_bridge_vlan_is_untagged(v1), ==, TRUE);
|
|
|
|
nm_bridge_vlan_set_pvid(v1, TRUE);
|
|
nm_bridge_vlan_set_untagged(v1, FALSE);
|
|
nm_bridge_vlan_seal(v1);
|
|
|
|
g_assert_cmpint(nm_bridge_vlan_is_sealed(v1), ==, TRUE);
|
|
g_assert_cmpint(nm_bridge_vlan_is_pvid(v1), ==, TRUE);
|
|
g_assert_cmpint(nm_bridge_vlan_is_untagged(v1), ==, FALSE);
|
|
|
|
str = nm_bridge_vlan_to_str(v1, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "10 pvid");
|
|
nm_clear_g_free(&str);
|
|
|
|
v2 = nm_bridge_vlan_from_str(" 10 pvid ", &error);
|
|
nmtst_assert_success(v2, error);
|
|
|
|
g_assert_cmpint(nm_bridge_vlan_cmp(v1, v2), ==, 0);
|
|
|
|
nm_bridge_vlan_unref(v1);
|
|
nm_bridge_vlan_unref(v2);
|
|
|
|
/* test comparison (2) */
|
|
v1 = nm_bridge_vlan_from_str("10", &error);
|
|
nmtst_assert_success(v1, error);
|
|
v2 = nm_bridge_vlan_from_str("20", &error);
|
|
nmtst_assert_success(v2, error);
|
|
|
|
g_assert_cmpint(nm_bridge_vlan_cmp(v1, v2), <, 0);
|
|
|
|
nm_bridge_vlan_unref(v1);
|
|
nm_bridge_vlan_unref(v2);
|
|
}
|
|
|
|
static void
|
|
create_bridge_connection(NMConnection **con, NMSettingBridge **s_bridge)
|
|
{
|
|
NMSettingConnection *s_con;
|
|
|
|
g_assert(con);
|
|
g_assert(s_bridge);
|
|
|
|
*con = nmtst_create_minimal_connection("bridge", NULL, NM_SETTING_BOND_SETTING_NAME, &s_con);
|
|
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "bridge0", NULL);
|
|
|
|
*s_bridge = (NMSettingBridge *) nm_setting_bridge_new();
|
|
g_assert(*s_bridge);
|
|
|
|
nm_connection_add_setting(*con, NM_SETTING(*s_bridge));
|
|
}
|
|
|
|
#define test_verify_options_bridge(exp, ...) \
|
|
_test_verify_options_bridge(exp, NM_MAKE_STRV(__VA_ARGS__))
|
|
|
|
static void
|
|
_test_verify_options_bridge(gboolean expected_result, const char *const *options)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
NMSettingBridge * s_bridge;
|
|
const char *const * option;
|
|
|
|
g_assert(NM_PTRARRAY_LEN(options) % 2 == 0);
|
|
|
|
create_bridge_connection(&con, &s_bridge);
|
|
|
|
for (option = options; option[0]; option += 2) {
|
|
const char *option_key = option[0];
|
|
const char *option_val = option[1];
|
|
GParamSpec *pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(s_bridge), option_key);
|
|
|
|
g_assert(pspec);
|
|
g_assert(option_val);
|
|
|
|
switch (G_PARAM_SPEC_VALUE_TYPE(pspec)) {
|
|
case G_TYPE_UINT:
|
|
{
|
|
guint uvalue;
|
|
|
|
uvalue = _nm_utils_ascii_str_to_uint64(option_val, 10, 0, G_MAXUINT, -1);
|
|
g_assert(errno == 0);
|
|
g_object_set(s_bridge, option_key, uvalue, NULL);
|
|
} break;
|
|
case G_TYPE_BOOLEAN:
|
|
{
|
|
int bvalue;
|
|
|
|
bvalue = _nm_utils_ascii_str_to_bool(option_val, -1);
|
|
g_assert(bvalue != -1);
|
|
g_object_set(s_bridge, option_key, bvalue, NULL);
|
|
} break;
|
|
case G_TYPE_STRING:
|
|
g_object_set(s_bridge, option_key, option_val, NULL);
|
|
break;
|
|
default:
|
|
g_assert_not_reached();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (expected_result)
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
else {
|
|
nmtst_assert_connection_unnormalizable(con,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_bridge_verify(void)
|
|
{
|
|
/* group-address */
|
|
test_verify_options_bridge(FALSE, "group-address", "nonsense");
|
|
test_verify_options_bridge(FALSE, "group-address", "FF:FF:FF:FF:FF:FF");
|
|
test_verify_options_bridge(FALSE, "group-address", "01:02:03:04:05:06");
|
|
test_verify_options_bridge(TRUE, "group-address", "01:80:C2:00:00:00");
|
|
test_verify_options_bridge(FALSE, "group-address", "01:80:C2:00:00:02");
|
|
test_verify_options_bridge(FALSE, "group-address", "01:80:C2:00:00:03");
|
|
test_verify_options_bridge(TRUE, "group-address", "01:80:C2:00:00:00");
|
|
test_verify_options_bridge(TRUE, "group-address", "01:80:C2:00:00:0A");
|
|
/* vlan-protocol */
|
|
test_verify_options_bridge(FALSE, "vlan-protocol", "nonsense124");
|
|
test_verify_options_bridge(FALSE, "vlan-protocol", "802.11");
|
|
test_verify_options_bridge(FALSE, "vlan-protocol", "802.1Q1");
|
|
test_verify_options_bridge(TRUE, "vlan-protocol", "802.1Q");
|
|
test_verify_options_bridge(TRUE, "vlan-protocol", "802.1ad");
|
|
/* multicast-router */
|
|
test_verify_options_bridge(FALSE, "multicast-router", "nonsense");
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "no", "multicast-router", "auto");
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "no", "multicast-router", "enabled");
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "no", "multicast-router", "disabled");
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "yes", "multicast-router", "enabled");
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "yes", "multicast-router", "auto");
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "yes", "multicast-router", "disabled");
|
|
/* multicast-hash-max */
|
|
test_verify_options_bridge(TRUE, "multicast-hash-max", "1024");
|
|
test_verify_options_bridge(TRUE, "multicast-hash-max", "8192");
|
|
test_verify_options_bridge(FALSE, "multicast-hash-max", "3");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_tc_config_qdisc(void)
|
|
{
|
|
NMTCQdisc *qdisc1, *qdisc2;
|
|
char * str;
|
|
GError * error = NULL;
|
|
GVariant * variant;
|
|
|
|
qdisc1 = nm_tc_qdisc_new("fq_codel", TC_H_ROOT, &error);
|
|
nmtst_assert_success(qdisc1, error);
|
|
|
|
qdisc2 = nm_tc_qdisc_new("fq_codel", TC_H_ROOT, &error);
|
|
nmtst_assert_success(qdisc2, error);
|
|
|
|
g_assert(nm_tc_qdisc_equal(qdisc1, qdisc2));
|
|
|
|
nm_tc_qdisc_unref(qdisc2);
|
|
qdisc2 = nm_tc_qdisc_dup(qdisc1);
|
|
|
|
g_assert(nm_tc_qdisc_equal(qdisc1, qdisc2));
|
|
|
|
g_assert_cmpstr(nm_tc_qdisc_get_kind(qdisc1), ==, "fq_codel");
|
|
g_assert(nm_tc_qdisc_get_handle(qdisc1) == TC_H_UNSPEC);
|
|
g_assert(nm_tc_qdisc_get_parent(qdisc1) == TC_H_ROOT);
|
|
|
|
str = nm_utils_tc_qdisc_to_str(qdisc1, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "root fq_codel");
|
|
g_free(str);
|
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
qdisc1 = nm_tc_qdisc_new("ingress", TC_H_INGRESS, &error);
|
|
nmtst_assert_success(qdisc1, error);
|
|
|
|
g_assert(!nm_tc_qdisc_equal(qdisc1, qdisc2));
|
|
|
|
str = nm_utils_tc_qdisc_to_str(qdisc1, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "ingress");
|
|
g_free(str);
|
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
qdisc1 = nm_utils_tc_qdisc_from_str("narodil sa kristus pan", &error);
|
|
nmtst_assert_no_success(qdisc1, error);
|
|
g_clear_error(&error);
|
|
|
|
qdisc1 = nm_utils_tc_qdisc_from_str("handle 1234 parent fff1:1 pfifo_fast", &error);
|
|
nmtst_assert_success(qdisc1, error);
|
|
|
|
g_assert_cmpstr(nm_tc_qdisc_get_kind(qdisc1), ==, "pfifo_fast");
|
|
g_assert(nm_tc_qdisc_get_handle(qdisc1) == TC_H_MAKE(0x1234u << 16, 0x0000u));
|
|
g_assert(nm_tc_qdisc_get_parent(qdisc1) == TC_H_MAKE(0xfff1u << 16, 0x0001u));
|
|
|
|
str = nm_utils_tc_qdisc_to_str(qdisc1, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "parent fff1:1 handle 1234: pfifo_fast");
|
|
g_free(str);
|
|
|
|
nm_tc_qdisc_unref(qdisc2);
|
|
str = nm_utils_tc_qdisc_to_str(qdisc1, &error);
|
|
nmtst_assert_success(str, error);
|
|
qdisc2 = nm_utils_tc_qdisc_from_str(str, &error);
|
|
nmtst_assert_success(qdisc2, error);
|
|
g_free(str);
|
|
|
|
g_assert(nm_tc_qdisc_equal(qdisc1, qdisc2));
|
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
nm_tc_qdisc_unref(qdisc2);
|
|
|
|
qdisc1 = nm_utils_tc_qdisc_from_str("clsact", &error);
|
|
nmtst_assert_success(qdisc1, error);
|
|
str = nm_utils_tc_qdisc_to_str(qdisc1, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "clsact");
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
g_free(str);
|
|
|
|
#define CHECK_ATTRIBUTE(qdisc, name, vtype, type, value) \
|
|
variant = nm_tc_qdisc_get_attribute(qdisc, name); \
|
|
g_assert(variant); \
|
|
g_assert(g_variant_is_of_type(variant, vtype)); \
|
|
g_assert_cmpint(g_variant_get_##type(variant), ==, value);
|
|
|
|
qdisc1 = nm_utils_tc_qdisc_from_str("handle 1235 root sfq perturb 10 quantum 1480 "
|
|
"limit 9000 flows 1024 divisor 500 depth 12",
|
|
&error);
|
|
nmtst_assert_success(qdisc1, error);
|
|
|
|
g_assert_cmpstr(nm_tc_qdisc_get_kind(qdisc1), ==, "sfq");
|
|
g_assert(nm_tc_qdisc_get_handle(qdisc1) == TC_H_MAKE(0x1235u << 16, 0x0000u));
|
|
g_assert(nm_tc_qdisc_get_parent(qdisc1) == TC_H_ROOT);
|
|
CHECK_ATTRIBUTE(qdisc1, "perturb", G_VARIANT_TYPE_INT32, int32, 10);
|
|
CHECK_ATTRIBUTE(qdisc1, "quantum", G_VARIANT_TYPE_UINT32, uint32, 1480);
|
|
CHECK_ATTRIBUTE(qdisc1, "limit", G_VARIANT_TYPE_UINT32, uint32, 9000);
|
|
CHECK_ATTRIBUTE(qdisc1, "flows", G_VARIANT_TYPE_UINT32, uint32, 1024);
|
|
CHECK_ATTRIBUTE(qdisc1, "divisor", G_VARIANT_TYPE_UINT32, uint32, 500);
|
|
CHECK_ATTRIBUTE(qdisc1, "depth", G_VARIANT_TYPE_UINT32, uint32, 12);
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
|
|
qdisc1 = nm_utils_tc_qdisc_from_str("handle 1235 root tbf rate 1000000 burst 5000 limit 10000",
|
|
&error);
|
|
nmtst_assert_success(qdisc1, error);
|
|
|
|
g_assert_cmpstr(nm_tc_qdisc_get_kind(qdisc1), ==, "tbf");
|
|
g_assert(nm_tc_qdisc_get_handle(qdisc1) == TC_H_MAKE(0x1235u << 16, 0x0000u));
|
|
g_assert(nm_tc_qdisc_get_parent(qdisc1) == TC_H_ROOT);
|
|
CHECK_ATTRIBUTE(qdisc1, "rate", G_VARIANT_TYPE_UINT64, uint64, 1000000);
|
|
CHECK_ATTRIBUTE(qdisc1, "burst", G_VARIANT_TYPE_UINT32, uint32, 5000);
|
|
CHECK_ATTRIBUTE(qdisc1, "limit", G_VARIANT_TYPE_UINT32, uint32, 10000);
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
|
|
#undef CHECK_ATTRIBUTE
|
|
}
|
|
|
|
static void
|
|
test_tc_config_action(void)
|
|
{
|
|
NMTCAction *action1, *action2;
|
|
char * str;
|
|
GError * error = NULL;
|
|
|
|
action1 = nm_tc_action_new("drop", &error);
|
|
nmtst_assert_success(action1, error);
|
|
action2 = nm_tc_action_new("drop", &error);
|
|
nmtst_assert_success(action2, error);
|
|
|
|
g_assert(nm_tc_action_equal(action1, action2));
|
|
g_assert_cmpstr(nm_tc_action_get_kind(action1), ==, "drop");
|
|
|
|
nm_tc_action_unref(action1);
|
|
action1 = nm_tc_action_new("simple", &error);
|
|
nmtst_assert_success(action1, error);
|
|
nm_tc_action_set_attribute(action1, "sdata", g_variant_new_bytestring("Hello"));
|
|
|
|
g_assert(!nm_tc_action_equal(action1, action2));
|
|
|
|
str = nm_utils_tc_action_to_str(action1, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "simple sdata Hello");
|
|
g_free(str);
|
|
|
|
str = nm_utils_tc_action_to_str(action2, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "drop");
|
|
g_free(str);
|
|
|
|
nm_tc_action_unref(action2);
|
|
action2 = nm_tc_action_dup(action1);
|
|
|
|
g_assert(nm_tc_action_equal(action1, action2));
|
|
|
|
nm_tc_action_unref(action1);
|
|
action1 = nm_utils_tc_action_from_str("narodil sa kristus pan", &error);
|
|
nmtst_assert_no_success(action1, error);
|
|
g_clear_error(&error);
|
|
|
|
action1 = nm_utils_tc_action_from_str("simple sdata Hello", &error);
|
|
nmtst_assert_success(action1, error);
|
|
|
|
g_assert_cmpstr(nm_tc_action_get_kind(action1), ==, "simple");
|
|
g_assert_cmpstr(g_variant_get_bytestring(nm_tc_action_get_attribute(action1, "sdata")),
|
|
==,
|
|
"Hello");
|
|
|
|
nm_tc_action_unref(action1);
|
|
nm_tc_action_unref(action2);
|
|
}
|
|
|
|
static void
|
|
test_tc_config_tfilter_matchall_sdata(void)
|
|
{
|
|
NMTCAction * action1;
|
|
NMTCTfilter *tfilter1, *tfilter2;
|
|
char * str;
|
|
GError * error = NULL;
|
|
|
|
tfilter1 = nm_tc_tfilter_new("matchall", TC_H_MAKE(0x1234u << 16, 0x0000u), &error);
|
|
nmtst_assert_success(tfilter1, error);
|
|
|
|
tfilter2 = nm_tc_tfilter_new("matchall", TC_H_MAKE(0x1234u << 16, 0x0000u), &error);
|
|
nmtst_assert_success(tfilter2, error);
|
|
|
|
g_assert(nm_tc_tfilter_equal(tfilter1, tfilter2));
|
|
|
|
action1 = nm_tc_action_new("simple", &error);
|
|
nmtst_assert_success(action1, error);
|
|
nm_tc_action_set_attribute(action1, "sdata", g_variant_new_bytestring("Hello"));
|
|
nm_tc_tfilter_set_action(tfilter1, action1);
|
|
nm_tc_action_unref(action1);
|
|
|
|
g_assert(!nm_tc_tfilter_equal(tfilter1, tfilter2));
|
|
|
|
str = nm_utils_tc_tfilter_to_str(tfilter1, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "parent 1234: matchall action simple sdata Hello");
|
|
g_free(str);
|
|
|
|
nm_tc_tfilter_unref(tfilter2);
|
|
tfilter2 = nm_tc_tfilter_dup(tfilter1);
|
|
|
|
g_assert(nm_tc_tfilter_equal(tfilter1, tfilter2));
|
|
|
|
nm_tc_tfilter_unref(tfilter1);
|
|
tfilter1 = nm_utils_tc_tfilter_from_str("narodil sa kristus pan", &error);
|
|
nmtst_assert_no_success(tfilter1, error);
|
|
g_clear_error(&error);
|
|
|
|
str = nm_utils_tc_tfilter_to_str(tfilter2, &error);
|
|
nmtst_assert_success(str, error);
|
|
tfilter1 = nm_utils_tc_tfilter_from_str(str, &error);
|
|
nmtst_assert_success(tfilter1, error);
|
|
g_free(str);
|
|
|
|
g_assert(nm_tc_tfilter_equal(tfilter1, tfilter2));
|
|
|
|
nm_tc_tfilter_unref(tfilter1);
|
|
nm_tc_tfilter_unref(tfilter2);
|
|
}
|
|
|
|
static void
|
|
test_tc_config_tfilter_matchall_mirred(void)
|
|
{
|
|
NMTCAction * action;
|
|
NMTCTfilter * tfilter1;
|
|
GError * error = NULL;
|
|
gs_strfreev char **attr_names = NULL;
|
|
gs_free char * str;
|
|
GVariant * variant;
|
|
|
|
tfilter1 =
|
|
nm_utils_tc_tfilter_from_str("parent ffff: matchall action mirred ingress mirror dev eth0",
|
|
&error);
|
|
nmtst_assert_success(tfilter1, error);
|
|
g_assert_cmpint(nm_tc_tfilter_get_parent(tfilter1), ==, TC_H_MAKE(0xffff << 16, 0));
|
|
g_assert_cmpstr(nm_tc_tfilter_get_kind(tfilter1), ==, "matchall");
|
|
|
|
action = nm_tc_tfilter_get_action(tfilter1);
|
|
nm_assert(action);
|
|
g_assert_cmpstr(nm_tc_action_get_kind(action), ==, "mirred");
|
|
attr_names = nm_tc_action_get_attribute_names(action);
|
|
g_assert(attr_names);
|
|
g_assert_cmpint(g_strv_length(attr_names), ==, 3);
|
|
|
|
variant = nm_tc_action_get_attribute(action, "ingress");
|
|
g_assert(variant);
|
|
g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN));
|
|
g_assert(g_variant_get_boolean(variant));
|
|
|
|
variant = nm_tc_action_get_attribute(action, "mirror");
|
|
g_assert(variant);
|
|
g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN));
|
|
g_assert(g_variant_get_boolean(variant));
|
|
|
|
variant = nm_tc_action_get_attribute(action, "dev");
|
|
g_assert(variant);
|
|
g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING));
|
|
g_assert_cmpstr(g_variant_get_string(variant, NULL), ==, "eth0");
|
|
|
|
str = nm_utils_tc_tfilter_to_str(tfilter1, &error);
|
|
nmtst_assert_success(str, error);
|
|
g_assert_cmpstr(str, ==, "parent ffff: matchall action mirred dev eth0 ingress mirror");
|
|
|
|
nm_tc_tfilter_unref(tfilter1);
|
|
}
|
|
|
|
static void
|
|
test_tc_config_setting_valid(void)
|
|
{
|
|
gs_unref_object NMSettingTCConfig *s_tc = NULL;
|
|
NMTCQdisc * qdisc1, *qdisc2;
|
|
GError * error = NULL;
|
|
|
|
s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new();
|
|
|
|
qdisc1 = nm_tc_qdisc_new("fq_codel", TC_H_ROOT, &error);
|
|
nmtst_assert_success(qdisc1, error);
|
|
|
|
qdisc2 = nm_tc_qdisc_new("pfifo_fast", TC_H_MAKE(0xfff1u << 16, 0x0001u), &error);
|
|
nmtst_assert_success(qdisc2, error);
|
|
nm_tc_qdisc_set_handle(qdisc2, TC_H_MAKE(0x1234u << 16, 0x0000u));
|
|
|
|
g_assert(nm_setting_tc_config_get_num_qdiscs(s_tc) == 0);
|
|
g_assert(nm_setting_tc_config_add_qdisc(s_tc, qdisc1) == TRUE);
|
|
g_assert(nm_setting_tc_config_get_num_qdiscs(s_tc) == 1);
|
|
g_assert(nm_setting_tc_config_get_qdisc(s_tc, 0) != NULL);
|
|
g_assert(nm_setting_tc_config_remove_qdisc_by_value(s_tc, qdisc2) == FALSE);
|
|
g_assert(nm_setting_tc_config_add_qdisc(s_tc, qdisc2) == TRUE);
|
|
g_assert(nm_setting_tc_config_get_num_qdiscs(s_tc) == 2);
|
|
g_assert(nm_setting_tc_config_remove_qdisc_by_value(s_tc, qdisc1) == TRUE);
|
|
g_assert(nm_setting_tc_config_get_num_qdiscs(s_tc) == 1);
|
|
nm_setting_tc_config_clear_qdiscs(s_tc);
|
|
g_assert(nm_setting_tc_config_get_num_qdiscs(s_tc) == 0);
|
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
nm_tc_qdisc_unref(qdisc2);
|
|
}
|
|
|
|
static void
|
|
test_tc_config_setting_duplicates(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *qdiscs = NULL;
|
|
gs_unref_ptrarray GPtrArray *tfilters = NULL;
|
|
NMSettingConnection * s_con;
|
|
NMConnection * con;
|
|
NMSetting * s_tc;
|
|
NMTCQdisc * qdisc;
|
|
NMTCTfilter * tfilter;
|
|
GError * error = NULL;
|
|
|
|
con = nmtst_create_minimal_connection("dummy", NULL, NM_SETTING_DUMMY_SETTING_NAME, &s_con);
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "dummy1", NULL);
|
|
|
|
s_tc = nm_setting_tc_config_new();
|
|
nm_connection_add_setting(con, s_tc);
|
|
qdiscs = g_ptr_array_new_with_free_func((GDestroyNotify) nm_tc_qdisc_unref);
|
|
tfilters = g_ptr_array_new_with_free_func((GDestroyNotify) nm_tc_tfilter_unref);
|
|
|
|
/* 1. add duplicate qdiscs */
|
|
qdisc = nm_utils_tc_qdisc_from_str("handle 1234 parent fff1:1 pfifo_fast", &error);
|
|
nmtst_assert_success(qdisc, error);
|
|
g_ptr_array_add(qdiscs, qdisc);
|
|
|
|
qdisc = nm_utils_tc_qdisc_from_str("handle 1234 parent fff1:1 pfifo_fast", &error);
|
|
nmtst_assert_success(qdisc, error);
|
|
g_ptr_array_add(qdiscs, qdisc);
|
|
|
|
g_object_set(s_tc, NM_SETTING_TC_CONFIG_QDISCS, qdiscs, NULL);
|
|
nmtst_assert_connection_unnormalizable(con,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY);
|
|
|
|
/* 2. make qdiscs unique */
|
|
g_ptr_array_remove_index(qdiscs, 0);
|
|
g_object_set(s_tc, NM_SETTING_TC_CONFIG_QDISCS, qdiscs, NULL);
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
|
|
/* 3. add duplicate filters */
|
|
tfilter =
|
|
nm_utils_tc_tfilter_from_str("parent 1234: matchall action simple sdata Hello", &error);
|
|
nmtst_assert_success(tfilter, error);
|
|
g_ptr_array_add(tfilters, tfilter);
|
|
|
|
tfilter =
|
|
nm_utils_tc_tfilter_from_str("parent 1234: matchall action simple sdata Hello", &error);
|
|
nmtst_assert_success(tfilter, error);
|
|
g_ptr_array_add(tfilters, tfilter);
|
|
|
|
g_object_set(s_tc, NM_SETTING_TC_CONFIG_TFILTERS, tfilters, NULL);
|
|
nmtst_assert_connection_unnormalizable(con,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY);
|
|
|
|
/* 4. make filters unique */
|
|
g_ptr_array_remove_index(tfilters, 0);
|
|
g_object_set(s_tc, NM_SETTING_TC_CONFIG_TFILTERS, tfilters, NULL);
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
}
|
|
|
|
static void
|
|
test_tc_config_dbus(void)
|
|
{
|
|
NMConnection *connection1, *connection2;
|
|
NMSetting * s_tc;
|
|
NMTCQdisc * qdisc1, *qdisc2;
|
|
NMTCTfilter * tfilter1, *tfilter2;
|
|
NMTCAction * action;
|
|
GVariant * dbus, *tc_dbus, *var1, *var2;
|
|
GError * error = NULL;
|
|
gboolean success;
|
|
|
|
connection1 =
|
|
nmtst_create_minimal_connection("dummy", NULL, NM_SETTING_DUMMY_SETTING_NAME, NULL);
|
|
|
|
s_tc = nm_setting_tc_config_new();
|
|
|
|
qdisc1 = nm_tc_qdisc_new("fq_codel", TC_H_ROOT, &error);
|
|
nmtst_assert_success(qdisc1, error);
|
|
nm_tc_qdisc_set_handle(qdisc1, TC_H_MAKE(0x1234u << 16, 0x0000u));
|
|
nm_setting_tc_config_add_qdisc(NM_SETTING_TC_CONFIG(s_tc), qdisc1);
|
|
|
|
qdisc2 = nm_tc_qdisc_new("ingress", TC_H_INGRESS, &error);
|
|
nmtst_assert_success(qdisc2, error);
|
|
nm_tc_qdisc_set_handle(qdisc2, TC_H_MAKE(TC_H_INGRESS, 0u));
|
|
nm_setting_tc_config_add_qdisc(NM_SETTING_TC_CONFIG(s_tc), qdisc2);
|
|
|
|
tfilter1 = nm_tc_tfilter_new("matchall", TC_H_MAKE(0x1234u << 16, 0x0000u), &error);
|
|
nmtst_assert_success(tfilter1, error);
|
|
action = nm_tc_action_new("drop", &error);
|
|
nmtst_assert_success(action, error);
|
|
nm_tc_tfilter_set_action(tfilter1, action);
|
|
nm_tc_action_unref(action);
|
|
nm_setting_tc_config_add_tfilter(NM_SETTING_TC_CONFIG(s_tc), tfilter1);
|
|
nm_tc_tfilter_unref(tfilter1);
|
|
|
|
tfilter2 = nm_tc_tfilter_new("matchall", TC_H_MAKE(TC_H_INGRESS, 0u), &error);
|
|
nmtst_assert_success(tfilter2, error);
|
|
action = nm_tc_action_new("simple", &error);
|
|
nmtst_assert_success(action, error);
|
|
nm_tc_action_set_attribute(action, "sdata", g_variant_new_bytestring("Hello"));
|
|
nm_tc_tfilter_set_action(tfilter2, action);
|
|
nm_tc_action_unref(action);
|
|
nm_setting_tc_config_add_tfilter(NM_SETTING_TC_CONFIG(s_tc), tfilter2);
|
|
nm_tc_tfilter_unref(tfilter2);
|
|
|
|
nm_connection_add_setting(connection1, s_tc);
|
|
|
|
dbus = nm_connection_to_dbus(connection1, NM_CONNECTION_SERIALIZE_ALL);
|
|
|
|
tc_dbus = g_variant_lookup_value(dbus, "tc", G_VARIANT_TYPE_VARDICT);
|
|
g_assert(tc_dbus);
|
|
|
|
var1 = g_variant_lookup_value(tc_dbus, "qdiscs", G_VARIANT_TYPE("aa{sv}"));
|
|
var2 = g_variant_new_parsed("[{'kind': <'fq_codel'>,"
|
|
" 'handle': <uint32 0x12340000>,"
|
|
" 'parent': <uint32 0xffffffff>},"
|
|
" {'kind': <'ingress'>,"
|
|
" 'handle': <uint32 0xffff0000>,"
|
|
" 'parent': <uint32 0xfffffff1>}]");
|
|
g_assert(g_variant_equal(var1, var2));
|
|
g_variant_unref(var1);
|
|
g_variant_unref(var2);
|
|
|
|
var1 = g_variant_lookup_value(tc_dbus, "tfilters", G_VARIANT_TYPE("aa{sv}"));
|
|
var2 = g_variant_new_parsed("[{'kind': <'matchall'>,"
|
|
" 'handle': <uint32 0>,"
|
|
" 'parent': <uint32 0x12340000>,"
|
|
" 'action': <{'kind': <'drop'>}>},"
|
|
" {'kind': <'matchall'>,"
|
|
" 'handle': <uint32 0>,"
|
|
" 'parent': <uint32 0xffff0000>,"
|
|
" 'action': <{'kind': <'simple'>,"
|
|
" 'sdata': <b'Hello'>}>}]");
|
|
g_variant_unref(var1);
|
|
g_variant_unref(var2);
|
|
|
|
g_variant_unref(tc_dbus);
|
|
|
|
connection2 = nm_simple_connection_new();
|
|
success = nm_connection_replace_settings(connection2, dbus, &error);
|
|
nmtst_assert_success(success, error);
|
|
|
|
g_assert(nm_connection_diff(connection1, connection2, NM_SETTING_COMPARE_FLAG_EXACT, NULL));
|
|
|
|
g_variant_unref(dbus);
|
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
nm_tc_qdisc_unref(qdisc2);
|
|
|
|
g_object_unref(connection1);
|
|
g_object_unref(connection2);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_rndt_wired_add_s390_options(NMSettingWired *s_wired, char **out_keyfile_entries)
|
|
{
|
|
gsize n_opts;
|
|
gsize i, j;
|
|
const char *const * option_names;
|
|
gs_free const char **opt_keys = NULL;
|
|
gs_strfreev char ** opt_vals = NULL;
|
|
gs_free bool * opt_found = NULL;
|
|
GString * keyfile_entries;
|
|
nm_auto_free_gstring GString *str_tmp = NULL;
|
|
|
|
option_names = nm_setting_wired_get_valid_s390_options(nmtst_get_rand_bool() ? NULL : s_wired);
|
|
|
|
n_opts = NM_PTRARRAY_LEN(option_names);
|
|
opt_keys = g_new(const char *, (n_opts + 1));
|
|
nmtst_rand_perm(NULL, opt_keys, option_names, sizeof(const char *), n_opts);
|
|
n_opts = nmtst_get_rand_uint32() % (n_opts + 1);
|
|
opt_keys[n_opts] = NULL;
|
|
|
|
opt_vals = g_new0(char *, n_opts + 1);
|
|
opt_found = g_new0(bool, n_opts + 1);
|
|
for (i = 0; i < n_opts; i++) {
|
|
if (nm_streq(opt_keys[i], "bridge_role"))
|
|
opt_vals[i] = g_strdup(nmtst_rand_select_str("primary", "secondary", "none"));
|
|
else {
|
|
guint p = nmtst_get_rand_uint32() % 1000;
|
|
if (p < 200)
|
|
opt_vals[i] = nm_strdup_int(i);
|
|
else {
|
|
opt_vals[i] = g_strdup_printf("%s%s%s%s-%zu",
|
|
((p % 5) % 2) ? "\n" : "",
|
|
((p % 7) % 2) ? "\t" : "",
|
|
((p % 11) % 2) ? "x" : "",
|
|
((p % 13) % 2) ? "=" : "",
|
|
i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nmtst_get_rand_bool()) {
|
|
gs_unref_hashtable GHashTable *hash = NULL;
|
|
|
|
hash = g_hash_table_new(nm_str_hash, g_str_equal);
|
|
for (i = 0; i < n_opts; i++)
|
|
g_hash_table_insert(hash, (char *) opt_keys[i], opt_vals[i]);
|
|
g_object_set(s_wired, NM_SETTING_WIRED_S390_OPTIONS, hash, NULL);
|
|
} else {
|
|
_nm_setting_wired_clear_s390_options(s_wired);
|
|
for (i = 0; i < n_opts; i++) {
|
|
if (!nm_setting_wired_add_s390_option(s_wired, opt_keys[i], opt_vals[i]))
|
|
g_assert_not_reached();
|
|
}
|
|
}
|
|
|
|
g_assert_cmpint(nm_setting_wired_get_num_s390_options(s_wired), ==, n_opts);
|
|
|
|
keyfile_entries = g_string_new(NULL);
|
|
str_tmp = g_string_new(NULL);
|
|
if (n_opts > 0)
|
|
g_string_append_printf(keyfile_entries, "[ethernet-s390-options]\n");
|
|
for (i = 0; i < n_opts; i++) {
|
|
gssize idx;
|
|
const char *k, *v;
|
|
|
|
nm_setting_wired_get_s390_option(s_wired, i, &k, &v);
|
|
g_assert(k);
|
|
g_assert(v);
|
|
|
|
idx = nm_utils_strv_find_first((char **) opt_keys, n_opts, k);
|
|
g_assert(idx >= 0);
|
|
g_assert(!opt_found[idx]);
|
|
opt_found[idx] = TRUE;
|
|
g_assert_cmpstr(opt_keys[idx], ==, k);
|
|
g_assert_cmpstr(opt_vals[idx], ==, v);
|
|
|
|
g_string_truncate(str_tmp, 0);
|
|
for (j = 0; v[j] != '\0'; j++) {
|
|
if (v[j] == '\n')
|
|
g_string_append(str_tmp, "\\n");
|
|
else if (v[j] == '\t')
|
|
g_string_append(str_tmp, "\\t");
|
|
else
|
|
g_string_append_c(str_tmp, v[j]);
|
|
}
|
|
|
|
g_string_append_printf(keyfile_entries, "%s=%s\n", k, str_tmp->str);
|
|
}
|
|
for (i = 0; i < n_opts; i++)
|
|
g_assert(opt_found[i]);
|
|
if (n_opts > 0)
|
|
g_string_append_printf(keyfile_entries, "\n");
|
|
*out_keyfile_entries = g_string_free(keyfile_entries, FALSE);
|
|
}
|
|
|
|
static GPtrArray *
|
|
_rndt_wg_peers_create(void)
|
|
{
|
|
GPtrArray *wg_peers;
|
|
guint i, n;
|
|
|
|
wg_peers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_wireguard_peer_unref);
|
|
|
|
n = nmtst_get_rand_uint32() % 10;
|
|
for (i = 0; i < n; i++) {
|
|
NMWireGuardPeer *peer;
|
|
guint8 public_key_buf[NM_WIREGUARD_PUBLIC_KEY_LEN];
|
|
guint8 preshared_key_buf[NM_WIREGUARD_SYMMETRIC_KEY_LEN];
|
|
gs_free char * public_key = NULL;
|
|
gs_free char * preshared_key = NULL;
|
|
gs_free char * s_endpoint = NULL;
|
|
guint i_aip, n_aip;
|
|
|
|
/* we don't bother to create a valid curve25519 public key. Of course, libnm cannot
|
|
* check whether the public key is bogus or not. Hence, for our purpose a random
|
|
* bogus key is good enough. */
|
|
public_key = g_base64_encode(nmtst_rand_buf(NULL, public_key_buf, sizeof(public_key_buf)),
|
|
sizeof(public_key_buf));
|
|
|
|
preshared_key =
|
|
g_base64_encode(nmtst_rand_buf(NULL, preshared_key_buf, sizeof(preshared_key_buf)),
|
|
sizeof(preshared_key_buf));
|
|
|
|
s_endpoint = _create_random_ipaddr(AF_UNSPEC, TRUE);
|
|
|
|
peer = nm_wireguard_peer_new();
|
|
if (!nm_wireguard_peer_set_public_key(peer, public_key, TRUE))
|
|
g_assert_not_reached();
|
|
|
|
if (!nm_wireguard_peer_set_preshared_key(peer,
|
|
nmtst_rand_select(NULL, preshared_key),
|
|
TRUE))
|
|
g_assert_not_reached();
|
|
|
|
nm_wireguard_peer_set_preshared_key_flags(
|
|
peer,
|
|
nmtst_rand_select(NM_SETTING_SECRET_FLAG_NONE,
|
|
NM_SETTING_SECRET_FLAG_NOT_SAVED,
|
|
NM_SETTING_SECRET_FLAG_AGENT_OWNED));
|
|
|
|
nm_wireguard_peer_set_persistent_keepalive(
|
|
peer,
|
|
nmtst_rand_select((guint32) 0, nmtst_get_rand_uint32()));
|
|
|
|
if (!nm_wireguard_peer_set_endpoint(peer, nmtst_rand_select(s_endpoint, NULL), TRUE))
|
|
g_assert_not_reached();
|
|
|
|
n_aip = nmtst_rand_select(0, nmtst_get_rand_uint32() % 10);
|
|
for (i_aip = 0; i_aip < n_aip; i_aip++) {
|
|
gs_free char *aip = NULL;
|
|
|
|
aip = _create_random_ipaddr(AF_UNSPEC, FALSE);
|
|
if (!nm_wireguard_peer_append_allowed_ip(peer, aip, FALSE))
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
g_assert(nm_wireguard_peer_is_valid(peer, TRUE, TRUE, NULL));
|
|
|
|
nm_wireguard_peer_seal(peer);
|
|
g_ptr_array_add(wg_peers, peer);
|
|
}
|
|
|
|
return wg_peers;
|
|
}
|
|
|
|
static const char *
|
|
_rndt_wg_peers_to_keyfile(GPtrArray *wg_peers, gboolean strict, char **out_str)
|
|
{
|
|
nm_auto_free_gstring GString *gstr = NULL;
|
|
nm_auto_free_gstring GString *gstr_aip = NULL;
|
|
guint i, j;
|
|
|
|
g_assert(wg_peers);
|
|
g_assert(out_str && !*out_str);
|
|
|
|
nm_gstring_prepare(&gstr);
|
|
for (i = 0; i < wg_peers->len; i++) {
|
|
const NMWireGuardPeer *peer = wg_peers->pdata[i];
|
|
gs_free char * s_endpoint = NULL;
|
|
gs_free char * s_preshared_key = NULL;
|
|
gs_free char * s_preshared_key_flags = NULL;
|
|
gs_free char * s_persistent_keepalive = NULL;
|
|
gs_free char * s_allowed_ips = NULL;
|
|
|
|
if (nm_wireguard_peer_get_endpoint(peer))
|
|
s_endpoint = g_strdup_printf("endpoint=%s\n", nm_wireguard_peer_get_endpoint(peer));
|
|
else if (!strict)
|
|
s_endpoint = g_strdup_printf("endpoint=\n");
|
|
|
|
if (nm_wireguard_peer_get_preshared_key(peer) || !strict) {
|
|
if (nm_wireguard_peer_get_preshared_key_flags(peer) == NM_SETTING_SECRET_FLAG_NONE)
|
|
s_preshared_key = g_strdup_printf("preshared-key=%s\n",
|
|
nm_wireguard_peer_get_preshared_key(peer) ?: "");
|
|
}
|
|
|
|
if (nm_wireguard_peer_get_preshared_key_flags(peer) != NM_SETTING_SECRET_FLAG_NOT_REQUIRED
|
|
|| !strict)
|
|
s_preshared_key_flags =
|
|
g_strdup_printf("preshared-key-flags=%d\n",
|
|
(int) nm_wireguard_peer_get_preshared_key_flags(peer));
|
|
|
|
if (nm_wireguard_peer_get_persistent_keepalive(peer) != 0 || !strict)
|
|
s_persistent_keepalive =
|
|
g_strdup_printf("persistent-keepalive=%u\n",
|
|
nm_wireguard_peer_get_persistent_keepalive(peer));
|
|
|
|
if (nm_wireguard_peer_get_allowed_ips_len(peer) > 0 || !strict) {
|
|
nm_gstring_prepare(&gstr_aip);
|
|
for (j = 0; j < nm_wireguard_peer_get_allowed_ips_len(peer); j++)
|
|
g_string_append_printf(gstr_aip,
|
|
"%s;",
|
|
nm_wireguard_peer_get_allowed_ip(peer, j, NULL));
|
|
s_allowed_ips = g_strdup_printf("allowed-ips=%s\n", gstr_aip->str);
|
|
}
|
|
|
|
if (!s_endpoint && !s_preshared_key && !s_preshared_key_flags && !s_persistent_keepalive
|
|
&& !s_allowed_ips)
|
|
s_endpoint = g_strdup_printf("endpoint=\n");
|
|
|
|
g_string_append_printf(gstr,
|
|
"\n"
|
|
"[wireguard-peer.%s]\n"
|
|
"%s" /* endpoint */
|
|
"%s" /* preshared-key */
|
|
"%s" /* preshared-key-flags */
|
|
"%s" /* persistent-keepalive */
|
|
"%s" /* allowed-ips */
|
|
"",
|
|
nm_wireguard_peer_get_public_key(peer),
|
|
s_endpoint ?: "",
|
|
s_preshared_key ?: "",
|
|
s_preshared_key_flags ?: "",
|
|
s_persistent_keepalive ?: "",
|
|
s_allowed_ips ?: "");
|
|
}
|
|
|
|
return (*out_str = g_string_free(g_steal_pointer(&gstr), FALSE));
|
|
}
|
|
|
|
static void
|
|
_rndt_wg_peers_assert_equal(NMSettingWireGuard *s_wg,
|
|
GPtrArray * peers,
|
|
gboolean consider_persistent_secrets,
|
|
gboolean consider_all_secrets,
|
|
gboolean expect_no_secrets)
|
|
{
|
|
guint i;
|
|
|
|
g_assert(NM_IS_SETTING_WIREGUARD(s_wg));
|
|
g_assert(peers);
|
|
|
|
g_assert_cmpint(peers->len, ==, nm_setting_wireguard_get_peers_len(s_wg));
|
|
|
|
for (i = 0; i < peers->len; i++) {
|
|
const NMWireGuardPeer *a = peers->pdata[i];
|
|
const NMWireGuardPeer *b = nm_setting_wireguard_get_peer(s_wg, i);
|
|
gboolean consider_secrets;
|
|
|
|
g_assert(a);
|
|
g_assert(b);
|
|
|
|
g_assert_cmpint(nm_wireguard_peer_cmp(a, b, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS), ==, 0);
|
|
|
|
if (consider_all_secrets || !nm_wireguard_peer_get_preshared_key(a))
|
|
consider_secrets = TRUE;
|
|
else if (nm_wireguard_peer_get_preshared_key(b))
|
|
consider_secrets = TRUE;
|
|
else if (consider_persistent_secrets
|
|
&& nm_wireguard_peer_get_preshared_key_flags(b) == NM_SETTING_SECRET_FLAG_NONE)
|
|
consider_secrets = TRUE;
|
|
else
|
|
consider_secrets = FALSE;
|
|
|
|
if (consider_secrets) {
|
|
g_assert_cmpstr(nm_wireguard_peer_get_preshared_key(a),
|
|
==,
|
|
nm_wireguard_peer_get_preshared_key(b));
|
|
g_assert_cmpint(nm_wireguard_peer_cmp(a, b, NM_SETTING_COMPARE_FLAG_EXACT), ==, 0);
|
|
}
|
|
|
|
if (expect_no_secrets)
|
|
g_assert_cmpstr(nm_wireguard_peer_get_preshared_key(b), ==, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_rndt_wg_peers_fix_secrets(NMSettingWireGuard *s_wg, GPtrArray *peers)
|
|
{
|
|
guint i;
|
|
|
|
g_assert(NM_IS_SETTING_WIREGUARD(s_wg));
|
|
g_assert(peers);
|
|
|
|
g_assert_cmpint(peers->len, ==, nm_setting_wireguard_get_peers_len(s_wg));
|
|
|
|
for (i = 0; i < peers->len; i++) {
|
|
const NMWireGuardPeer *a = peers->pdata[i];
|
|
const NMWireGuardPeer *b = nm_setting_wireguard_get_peer(s_wg, i);
|
|
nm_auto_unref_wgpeer NMWireGuardPeer *b_clone = NULL;
|
|
|
|
g_assert(a);
|
|
g_assert(b);
|
|
|
|
g_assert_cmpint(nm_wireguard_peer_get_preshared_key_flags(a),
|
|
==,
|
|
nm_wireguard_peer_get_preshared_key_flags(b));
|
|
g_assert_cmpint(nm_wireguard_peer_cmp(a, b, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS), ==, 0);
|
|
|
|
if (!nm_streq0(nm_wireguard_peer_get_preshared_key(a),
|
|
nm_wireguard_peer_get_preshared_key(b))) {
|
|
g_assert_cmpstr(nm_wireguard_peer_get_preshared_key(a), !=, NULL);
|
|
g_assert_cmpstr(nm_wireguard_peer_get_preshared_key(b), ==, NULL);
|
|
g_assert(NM_IN_SET(nm_wireguard_peer_get_preshared_key_flags(a),
|
|
NM_SETTING_SECRET_FLAG_AGENT_OWNED,
|
|
NM_SETTING_SECRET_FLAG_NOT_SAVED));
|
|
b_clone = nm_wireguard_peer_new_clone(b, TRUE);
|
|
if (!nm_wireguard_peer_set_preshared_key(b_clone,
|
|
nm_wireguard_peer_get_preshared_key(a),
|
|
TRUE))
|
|
g_assert_not_reached();
|
|
nm_setting_wireguard_set_peer(s_wg, b_clone, i);
|
|
b = nm_setting_wireguard_get_peer(s_wg, i);
|
|
g_assert(b == b_clone);
|
|
} else {
|
|
if (nm_wireguard_peer_get_preshared_key(a)) {
|
|
g_assert(NM_IN_SET(nm_wireguard_peer_get_preshared_key_flags(a),
|
|
NM_SETTING_SECRET_FLAG_NONE,
|
|
NM_SETTING_SECRET_FLAG_NOT_REQUIRED));
|
|
} else {
|
|
g_assert(NM_IN_SET(nm_wireguard_peer_get_preshared_key_flags(a),
|
|
NM_SETTING_SECRET_FLAG_AGENT_OWNED,
|
|
NM_SETTING_SECRET_FLAG_NONE,
|
|
NM_SETTING_SECRET_FLAG_NOT_SAVED,
|
|
NM_SETTING_SECRET_FLAG_NOT_REQUIRED));
|
|
}
|
|
}
|
|
|
|
g_assert_cmpstr(nm_wireguard_peer_get_preshared_key(a),
|
|
==,
|
|
nm_wireguard_peer_get_preshared_key(b));
|
|
g_assert_cmpint(nm_wireguard_peer_cmp(a, b, NM_SETTING_COMPARE_FLAG_EXACT), ==, 0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_roundtrip_conversion(gconstpointer test_data)
|
|
{
|
|
const int MODE = GPOINTER_TO_INT(test_data);
|
|
const char *ID = nm_sprintf_bufa(100, "roundtrip-conversion-%d", MODE);
|
|
const char *UUID = "63376701-b61e-4318-bf7e-664a1c1eeaab";
|
|
const char *INTERFACE_NAME = nm_sprintf_bufa(100, "ifname%d", MODE);
|
|
guint32 ETH_MTU = nmtst_rand_select((guint32) 0u, nmtst_get_rand_uint32());
|
|
const char *WG_PRIVATE_KEY =
|
|
nmtst_get_rand_bool() ? "yGXGK+5bVnxSJUejH4vbpXbq+ZtaG4NB8IHRK/aVtE0=" : NULL;
|
|
const NMSettingSecretFlags WG_PRIVATE_KEY_FLAGS =
|
|
nmtst_rand_select(NM_SETTING_SECRET_FLAG_NONE,
|
|
NM_SETTING_SECRET_FLAG_NOT_SAVED,
|
|
NM_SETTING_SECRET_FLAG_AGENT_OWNED);
|
|
const guint WG_LISTEN_PORT = nmtst_rand_select(0u, nmtst_get_rand_uint32() % 0x10000);
|
|
const guint WG_FWMARK = nmtst_rand_select(0u, nmtst_get_rand_uint32());
|
|
gs_unref_ptrarray GPtrArray *kf_data_arr = g_ptr_array_new_with_free_func(g_free);
|
|
gs_unref_ptrarray GPtrArray * wg_peers = NULL;
|
|
const NMConnectionSerializationFlags dbus_serialization_flags[] = {
|
|
NM_CONNECTION_SERIALIZE_ALL,
|
|
NM_CONNECTION_SERIALIZE_WITH_NON_SECRET,
|
|
NM_CONNECTION_SERIALIZE_WITH_SECRETS,
|
|
};
|
|
guint dbus_serialization_flags_idx;
|
|
gs_unref_object NMConnection *con = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
gs_free char * tmp_str = NULL;
|
|
guint kf_data_idx;
|
|
NMSettingConnection * s_con = NULL;
|
|
NMSettingWired * s_eth = NULL;
|
|
NMSettingWireGuard * s_wg = NULL;
|
|
union {
|
|
struct {
|
|
NMSettingIPConfig *s_6;
|
|
NMSettingIPConfig *s_4;
|
|
};
|
|
NMSettingIPConfig *s_x[2];
|
|
} s_ip;
|
|
int is_ipv4;
|
|
guint i;
|
|
gboolean success;
|
|
gs_free char *s390_keyfile_entries = NULL;
|
|
|
|
switch (MODE) {
|
|
case 0:
|
|
con = nmtst_create_minimal_connection(ID, UUID, NM_SETTING_WIRED_SETTING_NAME, &s_con);
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, INTERFACE_NAME, NULL);
|
|
nmtst_connection_normalize(con);
|
|
|
|
s_eth = NM_SETTING_WIRED(nm_connection_get_setting(con, NM_TYPE_SETTING_WIRED));
|
|
g_assert(NM_IS_SETTING_WIRED(s_eth));
|
|
|
|
g_object_set(s_eth, NM_SETTING_WIRED_MTU, ETH_MTU, NULL);
|
|
|
|
_rndt_wired_add_s390_options(s_eth, &s390_keyfile_entries);
|
|
|
|
g_ptr_array_add(
|
|
kf_data_arr,
|
|
g_strdup_printf("[connection]\n"
|
|
"id=%s\n"
|
|
"uuid=%s\n"
|
|
"type=ethernet\n"
|
|
"interface-name=%s\n"
|
|
"permissions=\n"
|
|
"\n"
|
|
"[ethernet]\n"
|
|
"mac-address-blacklist=\n"
|
|
"%s" /* mtu */
|
|
"\n"
|
|
"%s" /* [ethernet-s390-options] */
|
|
"[ipv4]\n"
|
|
"dns-search=\n"
|
|
"method=auto\n"
|
|
"\n"
|
|
"[ipv6]\n"
|
|
"addr-gen-mode=stable-privacy\n"
|
|
"dns-search=\n"
|
|
"method=auto\n"
|
|
"\n"
|
|
"[proxy]\n"
|
|
"",
|
|
ID,
|
|
UUID,
|
|
INTERFACE_NAME,
|
|
(ETH_MTU != 0) ? nm_sprintf_bufa(100, "mtu=%u\n", ETH_MTU) : "",
|
|
s390_keyfile_entries));
|
|
|
|
g_ptr_array_add(
|
|
kf_data_arr,
|
|
g_strdup_printf("[connection]\n"
|
|
"id=%s\n"
|
|
"uuid=%s\n"
|
|
"type=ethernet\n"
|
|
"interface-name=%s\n"
|
|
"permissions=\n"
|
|
"\n"
|
|
"[ethernet]\n"
|
|
"mac-address-blacklist=\n"
|
|
"%s" /* mtu */
|
|
"\n"
|
|
"%s" /* [ethernet-s390-options] */
|
|
"[ipv4]\n"
|
|
"dns-search=\n"
|
|
"method=auto\n"
|
|
"\n"
|
|
"[ipv6]\n"
|
|
"addr-gen-mode=stable-privacy\n"
|
|
"dns-search=\n"
|
|
"method=auto\n"
|
|
"",
|
|
ID,
|
|
UUID,
|
|
INTERFACE_NAME,
|
|
(ETH_MTU != 0) ? nm_sprintf_bufa(100, "mtu=%d\n", (int) ETH_MTU) : "",
|
|
s390_keyfile_entries));
|
|
|
|
break;
|
|
|
|
case 1:
|
|
con = nmtst_create_minimal_connection(ID, UUID, "wireguard", &s_con);
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, INTERFACE_NAME, NULL);
|
|
nmtst_connection_normalize(con);
|
|
|
|
s_wg = NM_SETTING_WIREGUARD(nm_connection_get_setting(con, NM_TYPE_SETTING_WIREGUARD));
|
|
|
|
g_ptr_array_add(kf_data_arr,
|
|
g_strdup_printf("[connection]\n"
|
|
"id=%s\n"
|
|
"uuid=%s\n"
|
|
"type=wireguard\n"
|
|
"interface-name=%s\n"
|
|
"permissions=\n"
|
|
"\n"
|
|
"[wireguard]\n"
|
|
"\n"
|
|
"[ipv4]\n"
|
|
"dns-search=\n"
|
|
"method=disabled\n"
|
|
"\n"
|
|
"[ipv6]\n"
|
|
"addr-gen-mode=stable-privacy\n"
|
|
"dns-search=\n"
|
|
"method=ignore\n"
|
|
"\n"
|
|
"[proxy]\n"
|
|
"",
|
|
ID,
|
|
UUID,
|
|
INTERFACE_NAME));
|
|
break;
|
|
|
|
case 2:
|
|
con = nmtst_create_minimal_connection(ID, UUID, "wireguard", &s_con);
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, INTERFACE_NAME, NULL);
|
|
nmtst_connection_normalize(con);
|
|
|
|
s_wg = NM_SETTING_WIREGUARD(nm_connection_get_setting(con, NM_TYPE_SETTING_WIREGUARD));
|
|
g_object_set(s_wg,
|
|
NM_SETTING_WIREGUARD_PRIVATE_KEY,
|
|
WG_PRIVATE_KEY,
|
|
NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS,
|
|
WG_PRIVATE_KEY_FLAGS,
|
|
NM_SETTING_WIREGUARD_LISTEN_PORT,
|
|
WG_LISTEN_PORT,
|
|
NM_SETTING_WIREGUARD_FWMARK,
|
|
WG_FWMARK,
|
|
NULL);
|
|
|
|
wg_peers = _rndt_wg_peers_create();
|
|
|
|
for (i = 0; i < wg_peers->len; i++)
|
|
nm_setting_wireguard_append_peer(s_wg, wg_peers->pdata[i]);
|
|
|
|
nm_clear_g_free(&tmp_str);
|
|
|
|
g_ptr_array_add(
|
|
kf_data_arr,
|
|
g_strdup_printf(
|
|
"[connection]\n"
|
|
"id=%s\n"
|
|
"uuid=%s\n"
|
|
"type=wireguard\n"
|
|
"interface-name=%s\n"
|
|
"permissions=\n"
|
|
"\n"
|
|
"[wireguard]\n"
|
|
"%s" /* fwmark */
|
|
"%s" /* listen-port */
|
|
"%s" /* private-key-flags */
|
|
"%s" /* private-key */
|
|
"%s" /* [wireguard-peers*] */
|
|
"\n"
|
|
"[ipv4]\n"
|
|
"dns-search=\n"
|
|
"method=disabled\n"
|
|
"\n"
|
|
"[ipv6]\n"
|
|
"addr-gen-mode=stable-privacy\n"
|
|
"dns-search=\n"
|
|
"method=ignore\n"
|
|
"\n"
|
|
"[proxy]\n"
|
|
"",
|
|
ID,
|
|
UUID,
|
|
INTERFACE_NAME,
|
|
((WG_FWMARK != 0) ? nm_sprintf_bufa(100, "fwmark=%u\n", WG_FWMARK) : ""),
|
|
((WG_LISTEN_PORT != 0) ? nm_sprintf_bufa(100, "listen-port=%u\n", WG_LISTEN_PORT)
|
|
: ""),
|
|
((WG_PRIVATE_KEY_FLAGS != NM_SETTING_SECRET_FLAG_NONE)
|
|
? nm_sprintf_bufa(100, "private-key-flags=%u\n", (guint) WG_PRIVATE_KEY_FLAGS)
|
|
: ""),
|
|
((WG_PRIVATE_KEY && WG_PRIVATE_KEY_FLAGS == NM_SETTING_SECRET_FLAG_NONE)
|
|
? nm_sprintf_bufa(100, "private-key=%s\n", WG_PRIVATE_KEY)
|
|
: ""),
|
|
_rndt_wg_peers_to_keyfile(wg_peers, TRUE, &tmp_str)));
|
|
|
|
_rndt_wg_peers_assert_equal(s_wg, wg_peers, TRUE, TRUE, FALSE);
|
|
break;
|
|
|
|
case 3:
|
|
con = nmtst_create_minimal_connection(ID, UUID, NM_SETTING_WIRED_SETTING_NAME, &s_con);
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, INTERFACE_NAME, NULL);
|
|
nmtst_connection_normalize(con);
|
|
|
|
s_eth = NM_SETTING_WIRED(nm_connection_get_setting(con, NM_TYPE_SETTING_WIRED));
|
|
g_assert(NM_IS_SETTING_WIRED(s_eth));
|
|
|
|
g_object_set(s_eth, NM_SETTING_WIRED_MTU, ETH_MTU, NULL);
|
|
|
|
s_ip.s_4 = NM_SETTING_IP_CONFIG(nm_connection_get_setting(con, NM_TYPE_SETTING_IP4_CONFIG));
|
|
g_assert(NM_IS_SETTING_IP4_CONFIG(s_ip.s_4));
|
|
|
|
s_ip.s_6 = NM_SETTING_IP_CONFIG(nm_connection_get_setting(con, NM_TYPE_SETTING_IP6_CONFIG));
|
|
g_assert(NM_IS_SETTING_IP6_CONFIG(s_ip.s_6));
|
|
|
|
for (is_ipv4 = 0; is_ipv4 < 2; is_ipv4++) {
|
|
g_assert(NM_IS_SETTING_IP_CONFIG(s_ip.s_x[is_ipv4]));
|
|
for (i = 0; i < 3; i++) {
|
|
char addrstr[NM_UTILS_INET_ADDRSTRLEN];
|
|
|
|
nm_auto_unref_ip_routing_rule NMIPRoutingRule *rr = NULL;
|
|
|
|
rr = nm_ip_routing_rule_new(is_ipv4 ? AF_INET : AF_INET6);
|
|
nm_ip_routing_rule_set_priority(rr, i + 1);
|
|
if (i > 0) {
|
|
if (is_ipv4)
|
|
nm_sprintf_buf(addrstr, "192.168.%u.0", i);
|
|
else
|
|
nm_sprintf_buf(addrstr, "1:2:3:%x::", 10 + i);
|
|
nm_ip_routing_rule_set_from(rr, addrstr, is_ipv4 ? 24 + i : 64 + i);
|
|
}
|
|
nm_ip_routing_rule_set_table(rr, 1000 + i);
|
|
|
|
success = nm_ip_routing_rule_validate(rr, &error);
|
|
nmtst_assert_success(success, error);
|
|
|
|
nm_setting_ip_config_add_routing_rule(s_ip.s_x[is_ipv4], rr);
|
|
}
|
|
}
|
|
|
|
g_ptr_array_add(
|
|
kf_data_arr,
|
|
g_strdup_printf("[connection]\n"
|
|
"id=%s\n"
|
|
"uuid=%s\n"
|
|
"type=ethernet\n"
|
|
"interface-name=%s\n"
|
|
"permissions=\n"
|
|
"\n"
|
|
"[ethernet]\n"
|
|
"mac-address-blacklist=\n"
|
|
"%s" /* mtu */
|
|
"\n"
|
|
"[ipv4]\n"
|
|
"dns-search=\n"
|
|
"method=auto\n"
|
|
"routing-rule1=priority 1 from 0.0.0.0/0 table 1000\n"
|
|
"routing-rule2=priority 2 from 192.168.1.0/25 table 1001\n"
|
|
"routing-rule3=priority 3 from 192.168.2.0/26 table 1002\n"
|
|
"\n"
|
|
"[ipv6]\n"
|
|
"addr-gen-mode=stable-privacy\n"
|
|
"dns-search=\n"
|
|
"method=auto\n"
|
|
"routing-rule1=priority 1 from ::/0 table 1000\n"
|
|
"routing-rule2=priority 2 from 1:2:3:b::/65 table 1001\n"
|
|
"routing-rule3=priority 3 from 1:2:3:c::/66 table 1002\n"
|
|
"\n"
|
|
"[proxy]\n"
|
|
"",
|
|
ID,
|
|
UUID,
|
|
INTERFACE_NAME,
|
|
(ETH_MTU != 0) ? nm_sprintf_bufa(100, "mtu=%u\n", ETH_MTU) : ""));
|
|
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
/* the first kf_data_arr entry is special: it is the exact result of what we expect
|
|
* when converting @con to keyfile. Write @con to keyfile and compare the expected result
|
|
* literally. */
|
|
{
|
|
nm_auto_unref_keyfile GKeyFile *kf = NULL;
|
|
|
|
kf = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
|
nmtst_assert_success(kf, error);
|
|
|
|
/* the first kf_data_arr entry is special: it must be what the writer would
|
|
* produce again. */
|
|
nmtst_keyfile_assert_data(kf, kf_data_arr->pdata[0], -1);
|
|
}
|
|
|
|
/* check that reading any of kf_data_arr yields the same result that we expect. */
|
|
for (kf_data_idx = 0; kf_data_idx < kf_data_arr->len; kf_data_idx++) {
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
NMSettingWireGuard * s_wg2 = NULL;
|
|
NMSettingWired * s_eth2 = NULL;
|
|
|
|
con2 = nmtst_create_connection_from_keyfile(kf_data_arr->pdata[kf_data_idx],
|
|
"/no/where/file.nmconnection");
|
|
|
|
switch (MODE) {
|
|
case 0:
|
|
s_eth2 = NM_SETTING_WIRED(nm_connection_get_setting(con2, NM_TYPE_SETTING_WIRED));
|
|
g_assert(NM_IS_SETTING_WIRED(s_eth2));
|
|
|
|
if (ETH_MTU > (guint32) G_MAXINT && kf_data_idx == 1) {
|
|
/* older versions wrote values > 2^21 as signed integers, but the reader would
|
|
* always reject such negative values for G_TYPE_UINT.
|
|
*
|
|
* The test case kf_data_idx #1 still writes the values in the old style.
|
|
* The behavior was fixed, but such values are still rejected as invalid.
|
|
*
|
|
* Patch the setting so that the comparison below succeeds are usual. */
|
|
g_assert_cmpint(nm_setting_wired_get_mtu(s_eth2), ==, 0);
|
|
g_object_set(s_eth2, NM_SETTING_WIRED_MTU, ETH_MTU, NULL);
|
|
}
|
|
|
|
g_assert_cmpint(nm_setting_wired_get_mtu(s_eth), ==, ETH_MTU);
|
|
g_assert_cmpint(nm_setting_wired_get_mtu(s_eth2), ==, ETH_MTU);
|
|
|
|
g_assert_cmpint(nm_setting_wired_get_num_s390_options(s_eth2),
|
|
==,
|
|
nm_setting_wired_get_num_s390_options(s_eth));
|
|
|
|
break;
|
|
|
|
case 1:
|
|
s_wg2 =
|
|
NM_SETTING_WIREGUARD(nm_connection_get_setting(con2, NM_TYPE_SETTING_WIREGUARD));
|
|
g_assert(NM_IS_SETTING_WIREGUARD(s_wg2));
|
|
|
|
g_assert_cmpstr(nm_setting_wireguard_get_private_key(s_wg), ==, NULL);
|
|
g_assert_cmpstr(nm_setting_wireguard_get_private_key(s_wg2), ==, NULL);
|
|
break;
|
|
|
|
case 2:
|
|
s_wg2 =
|
|
NM_SETTING_WIREGUARD(nm_connection_get_setting(con2, NM_TYPE_SETTING_WIREGUARD));
|
|
g_assert(NM_IS_SETTING_WIREGUARD(s_wg2));
|
|
|
|
/* the private key was lost due to the secret-flags. Patch it. */
|
|
if (WG_PRIVATE_KEY_FLAGS != NM_SETTING_SECRET_FLAG_NONE) {
|
|
g_assert_cmpstr(nm_setting_wireguard_get_private_key(s_wg2), ==, NULL);
|
|
g_object_set(s_wg2, NM_SETTING_WIREGUARD_PRIVATE_KEY, WG_PRIVATE_KEY, NULL);
|
|
}
|
|
|
|
g_assert_cmpstr(nm_setting_wireguard_get_private_key(s_wg), ==, WG_PRIVATE_KEY);
|
|
g_assert_cmpstr(nm_setting_wireguard_get_private_key(s_wg2), ==, WG_PRIVATE_KEY);
|
|
|
|
_rndt_wg_peers_assert_equal(s_wg2, wg_peers, TRUE, FALSE, FALSE);
|
|
_rndt_wg_peers_fix_secrets(s_wg2, wg_peers);
|
|
_rndt_wg_peers_assert_equal(s_wg2, wg_peers, TRUE, TRUE, FALSE);
|
|
break;
|
|
}
|
|
|
|
nmtst_assert_connection_equals(con, nmtst_get_rand_bool(), con2, nmtst_get_rand_bool());
|
|
}
|
|
|
|
for (dbus_serialization_flags_idx = 0;
|
|
dbus_serialization_flags_idx < G_N_ELEMENTS(dbus_serialization_flags);
|
|
dbus_serialization_flags_idx++) {
|
|
NMConnectionSerializationFlags flag =
|
|
dbus_serialization_flags[dbus_serialization_flags_idx];
|
|
gs_unref_variant GVariant *con_var = NULL;
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
NMSettingWireGuard * s_wg2 = NULL;
|
|
|
|
con_var = nm_connection_to_dbus(con, flag);
|
|
g_assert(g_variant_is_of_type(con_var, NM_VARIANT_TYPE_CONNECTION));
|
|
g_assert(g_variant_is_floating(con_var));
|
|
g_variant_ref_sink(con_var);
|
|
|
|
if (flag == NM_CONNECTION_SERIALIZE_ALL) {
|
|
con2 = _connection_new_from_dbus_strict(con_var, TRUE);
|
|
nmtst_assert_connection_equals(con, nmtst_get_rand_bool(), con2, nmtst_get_rand_bool());
|
|
|
|
{
|
|
nm_auto_unref_keyfile GKeyFile *kf = NULL;
|
|
|
|
kf = nm_keyfile_write(con2, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
|
nmtst_assert_success(kf, error);
|
|
nmtst_keyfile_assert_data(kf, kf_data_arr->pdata[0], -1);
|
|
}
|
|
}
|
|
|
|
switch (MODE) {
|
|
case 2:
|
|
if (flag == NM_CONNECTION_SERIALIZE_ALL) {
|
|
s_wg2 = NM_SETTING_WIREGUARD(
|
|
nm_connection_get_setting(con2, NM_TYPE_SETTING_WIREGUARD));
|
|
|
|
if (flag == NM_CONNECTION_SERIALIZE_ALL)
|
|
_rndt_wg_peers_assert_equal(s_wg2, wg_peers, TRUE, TRUE, FALSE);
|
|
else if (flag == NM_CONNECTION_SERIALIZE_WITH_NON_SECRET)
|
|
_rndt_wg_peers_assert_equal(s_wg2, wg_peers, FALSE, FALSE, TRUE);
|
|
else
|
|
g_assert_not_reached();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static NMIPRoutingRule *
|
|
_rr_from_str_get_impl(const char *str, const char *const *aliases)
|
|
{
|
|
nm_auto_unref_ip_routing_rule NMIPRoutingRule *rr = NULL;
|
|
gs_free_error GError * error = NULL;
|
|
gboolean vbool;
|
|
int addr_family;
|
|
int i;
|
|
NMIPRoutingRuleAsStringFlags to_string_flags;
|
|
|
|
rr = nm_ip_routing_rule_from_string(str,
|
|
NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE,
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(rr, error);
|
|
|
|
addr_family = nm_ip_routing_rule_get_addr_family(rr);
|
|
g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
|
|
|
|
if (addr_family == AF_INET)
|
|
to_string_flags = NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET;
|
|
else
|
|
to_string_flags = NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET6;
|
|
|
|
for (i = 0; TRUE; i++) {
|
|
nm_auto_unref_ip_routing_rule NMIPRoutingRule *rr2 = NULL;
|
|
gs_free char * str1 = NULL;
|
|
gs_unref_variant GVariant *variant1 = NULL;
|
|
const char * cstr1;
|
|
|
|
switch (i) {
|
|
case 0:
|
|
rr2 = nm_ip_routing_rule_ref(rr);
|
|
break;
|
|
|
|
case 1:
|
|
rr2 = nm_ip_routing_rule_from_string(
|
|
str,
|
|
NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE
|
|
| (nmtst_get_rand_bool() ? to_string_flags
|
|
: NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE),
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(rr, error);
|
|
break;
|
|
|
|
case 2:
|
|
str1 = nm_ip_routing_rule_to_string(
|
|
rr,
|
|
NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE
|
|
| (nmtst_get_rand_bool() ? to_string_flags
|
|
: NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE),
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(str1 && str1[0], error);
|
|
|
|
g_assert_cmpstr(str, ==, str1);
|
|
|
|
rr2 = nm_ip_routing_rule_from_string(
|
|
str1,
|
|
NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE
|
|
| (nmtst_get_rand_bool() ? to_string_flags
|
|
: NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE),
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(rr, error);
|
|
break;
|
|
|
|
case 3:
|
|
variant1 = nm_ip_routing_rule_to_dbus(rr);
|
|
g_assert(variant1);
|
|
g_assert(g_variant_is_floating(variant1));
|
|
g_assert(g_variant_is_of_type(variant1, G_VARIANT_TYPE_VARDICT));
|
|
|
|
rr2 = nm_ip_routing_rule_from_dbus(variant1, TRUE, &error);
|
|
nmtst_assert_success(rr, error);
|
|
break;
|
|
|
|
default:
|
|
if (!aliases || !aliases[0])
|
|
goto done;
|
|
cstr1 = (aliases++)[0];
|
|
rr2 = nm_ip_routing_rule_from_string(
|
|
cstr1,
|
|
NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE
|
|
| (nmtst_get_rand_bool() ? to_string_flags
|
|
: NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE),
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(rr, error);
|
|
break;
|
|
}
|
|
|
|
g_assert(rr2);
|
|
vbool = nm_ip_routing_rule_validate(rr, &error);
|
|
nmtst_assert_success(vbool, error);
|
|
vbool = nm_ip_routing_rule_validate(rr2, &error);
|
|
nmtst_assert_success(vbool, error);
|
|
|
|
g_assert_cmpint(nm_ip_routing_rule_cmp(rr, rr2), ==, 0);
|
|
g_assert_cmpint(nm_ip_routing_rule_cmp(rr2, rr), ==, 0);
|
|
}
|
|
|
|
done:
|
|
return g_steal_pointer(&rr);
|
|
}
|
|
#define _rr_from_str_get(a, ...) _rr_from_str_get_impl(a, &(NM_MAKE_STRV(NULL, ##__VA_ARGS__))[1])
|
|
|
|
#define _rr_from_str(...) \
|
|
G_STMT_START \
|
|
{ \
|
|
nm_auto_unref_ip_routing_rule NMIPRoutingRule *_rr = NULL; \
|
|
\
|
|
_rr = _rr_from_str_get(__VA_ARGS__); \
|
|
g_assert(_rr); \
|
|
} \
|
|
G_STMT_END
|
|
|
|
static void
|
|
test_routing_rule(gconstpointer test_data)
|
|
{
|
|
nm_auto_unref_ip_routing_rule NMIPRoutingRule *rr1 = NULL;
|
|
gboolean success;
|
|
char ifname_buf[16];
|
|
|
|
_rr_from_str("priority 5 from 0.0.0.0 table 1", " from 0.0.0.0 priority 5 lookup 1 ");
|
|
_rr_from_str("priority 5 from 0.0.0.0/0 table 4");
|
|
_rr_from_str("priority 5 to 0.0.0.0 table 6");
|
|
_rr_from_str("priority 5 to 0.0.0.0 table 254", "priority 5 to 0.0.0.0/32");
|
|
_rr_from_str("priority 5 from 1.2.3.4 table 15",
|
|
"priority 5 from 1.2.3.4/32 table 0xF ",
|
|
"priority 5 from 1.2.3.4/32 to 0.0.0.0/0 lookup 15 ");
|
|
_rr_from_str("priority 5 from 1.2.3.4 to 0.0.0.0 table 8");
|
|
_rr_from_str("priority 5 to a:b:c:: tos 0x16 table 25",
|
|
"priority 5 to a:b:c::/128 table 0x19 tos 16",
|
|
"priority 5 to a:b:c::/128 lookup 0x19 dsfield 16",
|
|
"priority 5 to a:b:c::/128 lookup 0x19 dsfield 16 fwmark 0/0x00",
|
|
"priority 5 to a:b:c:: from all lookup 0x19 dsfield 16 fwmark 0x0/0");
|
|
_rr_from_str("priority 5 from :: fwmark 0 table 25",
|
|
"priority 5 from ::/128 to all table 0x19 fwmark 0/0xFFFFFFFF",
|
|
"priority 5 from :: to ::/0 table 0x19 fwmark 0x00/4294967295");
|
|
_rr_from_str("priority 5 from :: iif aab table 25");
|
|
_rr_from_str("priority 5 from :: iif aab oif er table 25",
|
|
"priority 5 from :: table 0x19 dev aab oif er");
|
|
_rr_from_str("priority 5 from :: iif a\\\\303b table 25");
|
|
_rr_from_str("priority 5 to 0.0.0.0 sport 10 table 6",
|
|
"priority 5 to 0.0.0.0 sport 10-10 table 6");
|
|
_rr_from_str("priority 5 not to 0.0.0.0 dport 10-133 table 6",
|
|
"not priority 5 to 0.0.0.0 dport 10-133 table 6",
|
|
"not priority 5 not to 0.0.0.0 dport 10-133 table 6",
|
|
"priority 5 to 0.0.0.0 not dport 10-133 not table 6",
|
|
"priority 5 to 0.0.0.0 not dport 10-\\ 133 not table 6");
|
|
_rr_from_str("priority 5 to 0.0.0.0 ipproto 10 sport 10 table 6");
|
|
|
|
rr1 = _rr_from_str_get("priority 5 from :: iif aab table 25");
|
|
g_assert_cmpstr(nm_ip_routing_rule_get_iifname(rr1), ==, "aab");
|
|
success = nm_ip_routing_rule_get_xifname_bin(rr1, FALSE, ifname_buf);
|
|
g_assert(!success);
|
|
success = nm_ip_routing_rule_get_xifname_bin(rr1, TRUE, ifname_buf);
|
|
g_assert_cmpstr(ifname_buf, ==, "aab");
|
|
g_assert(success);
|
|
nm_clear_pointer(&rr1, nm_ip_routing_rule_unref);
|
|
|
|
rr1 = _rr_from_str_get("priority 5 from :: iif a\\\\303\\\\261xb table 254");
|
|
g_assert_cmpstr(nm_ip_routing_rule_get_iifname(rr1), ==, "a\\303\\261xb");
|
|
success = nm_ip_routing_rule_get_xifname_bin(rr1, FALSE, ifname_buf);
|
|
g_assert(!success);
|
|
success = nm_ip_routing_rule_get_xifname_bin(rr1, TRUE, ifname_buf);
|
|
g_assert_cmpstr(ifname_buf, ==, "a\303\261xb");
|
|
g_assert(success);
|
|
nm_clear_pointer(&rr1, nm_ip_routing_rule_unref);
|
|
|
|
rr1 = _rr_from_str_get("priority 5 from :: oif \\\\101=\\\\303\\\\261xb table 7");
|
|
g_assert_cmpstr(nm_ip_routing_rule_get_oifname(rr1), ==, "\\101=\\303\\261xb");
|
|
success = nm_ip_routing_rule_get_xifname_bin(rr1, FALSE, ifname_buf);
|
|
g_assert_cmpstr(ifname_buf, ==, "A=\303\261xb");
|
|
g_assert(success);
|
|
success = nm_ip_routing_rule_get_xifname_bin(rr1, TRUE, ifname_buf);
|
|
g_assert(!success);
|
|
nm_clear_pointer(&rr1, nm_ip_routing_rule_unref);
|
|
|
|
rr1 = _rr_from_str_get("priority 5 to 0.0.0.0 tos 0x10 table 7");
|
|
g_assert_cmpstr(NULL, ==, nm_ip_routing_rule_get_from(rr1));
|
|
g_assert(!nm_ip_routing_rule_get_from_bin(rr1));
|
|
g_assert_cmpint(0, ==, nm_ip_routing_rule_get_from_len(rr1));
|
|
g_assert_cmpstr("0.0.0.0", ==, nm_ip_routing_rule_get_to(rr1));
|
|
g_assert(nm_ip_addr_is_null(AF_INET, nm_ip_routing_rule_get_to_bin(rr1)));
|
|
g_assert_cmpint(32, ==, nm_ip_routing_rule_get_to_len(rr1));
|
|
g_assert_cmpint(7, ==, nm_ip_routing_rule_get_table(rr1));
|
|
g_assert_cmpint(0x10, ==, nm_ip_routing_rule_get_tos(rr1));
|
|
nm_clear_pointer(&rr1, nm_ip_routing_rule_unref);
|
|
|
|
rr1 = _rr_from_str_get("priority 5 from :: iif a\\\\303\\\\261,x;b table 254",
|
|
"priority 5 from :: iif a\\\\303\\\\261,x;b table 254");
|
|
g_assert_cmpstr(nm_ip_routing_rule_get_iifname(rr1), ==, "a\\303\\261,x;b");
|
|
success = nm_ip_routing_rule_get_xifname_bin(rr1, FALSE, ifname_buf);
|
|
g_assert(!success);
|
|
success = nm_ip_routing_rule_get_xifname_bin(rr1, TRUE, ifname_buf);
|
|
g_assert_cmpstr(ifname_buf, ==, "a\303\261,x;b");
|
|
g_assert(success);
|
|
nm_clear_pointer(&rr1, nm_ip_routing_rule_unref);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_parse_tc_handle(void)
|
|
{
|
|
#define _parse_tc_handle(str, exp) \
|
|
G_STMT_START \
|
|
{ \
|
|
gs_free_error GError *_error = NULL; \
|
|
GError ** _perror = nmtst_get_rand_bool() ? &_error : NULL; \
|
|
guint32 _v; \
|
|
const guint32 _v_exp = (exp); \
|
|
\
|
|
_v = _nm_utils_parse_tc_handle("" str "", _perror); \
|
|
\
|
|
if (_v != _v_exp) \
|
|
g_error("%s:%d: \"%s\" gave %08x but %08x expected.", \
|
|
__FILE__, \
|
|
__LINE__, \
|
|
"" str "", \
|
|
_v, \
|
|
_v_exp); \
|
|
\
|
|
if (_v == TC_H_UNSPEC) \
|
|
g_assert(!_perror || *_perror); \
|
|
else \
|
|
g_assert(!_perror || !*_perror); \
|
|
} \
|
|
G_STMT_END
|
|
|
|
#define _parse_tc_handle_inval(str) _parse_tc_handle(str, TC_H_UNSPEC)
|
|
#define _parse_tc_handle_valid(str, maj, min) \
|
|
_parse_tc_handle(str, TC_H_MAKE(((guint32) (maj)) << 16, ((guint16) (min))))
|
|
|
|
_parse_tc_handle_inval("");
|
|
_parse_tc_handle_inval(" ");
|
|
_parse_tc_handle_inval(" \n");
|
|
_parse_tc_handle_valid("1", 1, 0);
|
|
_parse_tc_handle_valid(" 1 ", 1, 0);
|
|
_parse_tc_handle_valid("1:", 1, 0);
|
|
_parse_tc_handle_valid("1: ", 1, 0);
|
|
_parse_tc_handle_valid("1:0", 1, 0);
|
|
_parse_tc_handle_valid("1 :0", 1, 0);
|
|
_parse_tc_handle_valid("1 \t\n\f\r:0", 1, 0);
|
|
_parse_tc_handle_inval("1 \t\n\f\r\v:0");
|
|
_parse_tc_handle_valid(" 1 : 0 ", 1, 0);
|
|
_parse_tc_handle_inval(" \t\v\n1: 0");
|
|
_parse_tc_handle_valid("1:2", 1, 2);
|
|
_parse_tc_handle_valid("01:02", 1, 2);
|
|
_parse_tc_handle_inval("0x01:0x02");
|
|
_parse_tc_handle_valid(" 01: 02", 1, 2);
|
|
_parse_tc_handle_valid("019: 020", 0x19, 0x20);
|
|
_parse_tc_handle_valid("FFFF: 020", 0xFFFF, 0x20);
|
|
_parse_tc_handle_valid("FfFF: ffff", 0xFFFF, 0xFFFF);
|
|
_parse_tc_handle_valid("FFFF", 0xFFFF, 0);
|
|
_parse_tc_handle_inval("0xFFFF");
|
|
_parse_tc_handle_inval("10000");
|
|
_parse_tc_handle_valid("\t\n\f\r FFFF", 0xFFFF, 0);
|
|
_parse_tc_handle_inval("\t\n\f\r \vFFFF");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_empty_setting(void)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
NMSettingBluetooth * s_bt;
|
|
NMSettingGsm * s_gsm;
|
|
nm_auto_unref_keyfile GKeyFile *kf = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
|
|
con = nmtst_create_minimal_connection("bt-empty-gsm",
|
|
"dca3192a-f2dc-48eb-b806-d0ff788f122c",
|
|
NM_SETTING_BLUETOOTH_SETTING_NAME,
|
|
NULL);
|
|
|
|
s_bt = _nm_connection_get_setting(con, NM_TYPE_SETTING_BLUETOOTH);
|
|
g_object_set(s_bt,
|
|
NM_SETTING_BLUETOOTH_TYPE,
|
|
"dun",
|
|
NM_SETTING_BLUETOOTH_BDADDR,
|
|
"aa:bb:cc:dd:ee:ff",
|
|
NULL);
|
|
|
|
s_gsm = NM_SETTING_GSM(nm_setting_gsm_new());
|
|
nm_connection_add_setting(con, NM_SETTING(s_gsm));
|
|
|
|
nmtst_connection_normalize(con);
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con);
|
|
|
|
kf = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
|
nmtst_assert_success(kf, error);
|
|
|
|
g_assert(g_key_file_has_group(kf, "gsm"));
|
|
g_assert_cmpint(nmtst_keyfile_get_num_keys(kf, "gsm"), ==, 0);
|
|
|
|
con2 = nm_keyfile_read(kf,
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
nmtst_assert_success(con2, error);
|
|
|
|
g_assert(nm_connection_get_setting(con2, NM_TYPE_SETTING_GSM));
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static guint
|
|
_PROP_IDX_PACK(NMMetaSettingType meta_type, guint idx)
|
|
{
|
|
return (((guint) meta_type) & 0xFFu) | (idx << 8);
|
|
}
|
|
|
|
static const char *
|
|
_PROP_IDX_OWNER(GHashTable *h_property_types, const NMSettInfoPropertType *property_type)
|
|
{
|
|
const NMSettInfoSetting *sett_info_settings = nmtst_sett_info_settings();
|
|
const NMSettInfoSetting *sis;
|
|
const NMMetaSettingInfo *msi;
|
|
GArray * arr;
|
|
guint idx;
|
|
NMMetaSettingType meta_type;
|
|
guint prop_idx;
|
|
char sbuf[300];
|
|
|
|
g_assert(h_property_types);
|
|
g_assert(property_type);
|
|
|
|
arr = g_hash_table_lookup(h_property_types, property_type);
|
|
|
|
g_assert(arr);
|
|
g_assert(arr->len > 0);
|
|
|
|
idx = g_array_index(arr, guint, 0);
|
|
|
|
meta_type = (idx & 0xFFu);
|
|
prop_idx = idx >> 8;
|
|
|
|
g_assert(meta_type < _NM_META_SETTING_TYPE_NUM);
|
|
|
|
sis = &sett_info_settings[meta_type];
|
|
msi = &nm_meta_setting_infos[meta_type];
|
|
|
|
g_assert(prop_idx < sis->property_infos_len);
|
|
|
|
nm_sprintf_buf(sbuf, "%s.%s", msi->setting_name, sis->property_infos[prop_idx].name);
|
|
|
|
return g_intern_string(sbuf);
|
|
}
|
|
|
|
static void
|
|
test_setting_metadata(void)
|
|
{
|
|
const NMSettInfoSetting *sett_info_settings = nmtst_sett_info_settings();
|
|
NMMetaSettingType meta_type;
|
|
gs_unref_hashtable GHashTable *h_property_types = NULL;
|
|
|
|
G_STATIC_ASSERT(_NM_META_SETTING_TYPE_NUM == NM_META_SETTING_TYPE_UNKNOWN);
|
|
|
|
h_property_types =
|
|
g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) g_array_unref);
|
|
|
|
for (meta_type = 0; meta_type < _NM_META_SETTING_TYPE_NUM; meta_type++) {
|
|
const NMMetaSettingInfo *msi = &nm_meta_setting_infos[meta_type];
|
|
nm_auto_unref_gtypeclass NMSettingClass *klass = NULL;
|
|
GType gtype;
|
|
|
|
g_assert(msi->setting_name);
|
|
g_assert(msi->get_setting_gtype);
|
|
g_assert(msi->meta_type == meta_type);
|
|
g_assert(msi->setting_priority >= NM_SETTING_PRIORITY_CONNECTION);
|
|
g_assert(msi->setting_priority <= NM_SETTING_PRIORITY_USER);
|
|
|
|
if (meta_type > 0)
|
|
g_assert_cmpint(
|
|
strcmp(nm_meta_setting_infos[meta_type - 1].setting_name, msi->setting_name),
|
|
<,
|
|
0);
|
|
|
|
gtype = msi->get_setting_gtype();
|
|
|
|
g_assert(g_type_is_a(gtype, NM_TYPE_SETTING));
|
|
g_assert(gtype != NM_TYPE_SETTING);
|
|
|
|
klass = g_type_class_ref(gtype);
|
|
g_assert(klass);
|
|
g_assert(NM_IS_SETTING_CLASS(klass));
|
|
|
|
g_assert(msi == klass->setting_info);
|
|
}
|
|
|
|
g_assert(sett_info_settings);
|
|
|
|
for (meta_type = 0; meta_type < _NM_META_SETTING_TYPE_NUM; meta_type++) {
|
|
const NMSettInfoSetting *sis = &sett_info_settings[meta_type];
|
|
const NMMetaSettingInfo *msi = &nm_meta_setting_infos[meta_type];
|
|
gs_unref_hashtable GHashTable *h_properties = NULL;
|
|
GType gtype;
|
|
gs_unref_object NMSetting *setting = NULL;
|
|
guint prop_idx;
|
|
gs_free GParamSpec **property_specs = NULL;
|
|
guint n_property_specs;
|
|
|
|
g_assert(sis);
|
|
|
|
g_assert(NM_IS_SETTING_CLASS(sis->setting_class));
|
|
|
|
gtype = msi->get_setting_gtype();
|
|
|
|
g_assert(G_TYPE_FROM_CLASS(sis->setting_class) == gtype);
|
|
|
|
setting = g_object_new(gtype, NULL);
|
|
|
|
g_assert(NM_IS_SETTING(setting));
|
|
|
|
g_assert_cmpint(sis->property_infos_len, >, 0);
|
|
g_assert(sis->property_infos);
|
|
|
|
h_properties = g_hash_table_new(nm_str_hash, g_str_equal);
|
|
|
|
for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) {
|
|
const NMSettInfoProperty *sip = &sis->property_infos[prop_idx];
|
|
GArray * property_types_data;
|
|
guint prop_idx_val;
|
|
|
|
g_assert(sip->name);
|
|
|
|
if (prop_idx > 0)
|
|
g_assert_cmpint(strcmp(sis->property_infos[prop_idx - 1].name, sip->name), <, 0);
|
|
|
|
g_assert(sip->property_type);
|
|
g_assert(sip->property_type->dbus_type);
|
|
g_assert(g_variant_type_string_is_valid((const char *) sip->property_type->dbus_type));
|
|
|
|
if (!sip->property_type->to_dbus_fcn) {
|
|
/* it's allowed to have no to_dbus_fcn(), to ignore a property. But such
|
|
* properties must not have a param_spec and no gprop_to_dbus_fcn. */
|
|
g_assert(!sip->param_spec);
|
|
g_assert(!sip->property_type->gprop_to_dbus_fcn);
|
|
} else if (sip->property_type->to_dbus_fcn == _nm_setting_property_to_dbus_fcn_gprop) {
|
|
g_assert(sip->param_spec);
|
|
switch (sip->property_type->typdata_to_dbus.gprop_type) {
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_BYTES:
|
|
g_assert(sip->param_spec->value_type == G_TYPE_BYTES);
|
|
goto check_done;
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_ENUM:
|
|
g_assert(g_type_is_a (sip->param_spec->value_type, G_TYPE_ENUM));
|
|
goto check_done;
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_FLAGS:
|
|
g_assert(g_type_is_a (sip->param_spec->value_type, G_TYPE_FLAGS));
|
|
goto check_done;
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_DEFAULT:
|
|
goto check_done;
|
|
}
|
|
g_assert_not_reached();
|
|
check_done:;
|
|
}
|
|
|
|
g_assert(!sip->property_type->from_dbus_fcn
|
|
|| !sip->property_type->gprop_from_dbus_fcn);
|
|
|
|
if (!g_hash_table_insert(h_properties, (char *) sip->name, sip->param_spec))
|
|
g_assert_not_reached();
|
|
|
|
property_types_data = g_hash_table_lookup(h_property_types, sip->property_type);
|
|
if (!property_types_data) {
|
|
property_types_data = g_array_new(FALSE, FALSE, sizeof(guint));
|
|
if (!g_hash_table_insert(h_property_types,
|
|
(gpointer) sip->property_type,
|
|
property_types_data))
|
|
g_assert_not_reached();
|
|
}
|
|
prop_idx_val = _PROP_IDX_PACK(meta_type, prop_idx);
|
|
g_array_append_val(property_types_data, prop_idx_val);
|
|
|
|
if (sip->param_spec) {
|
|
nm_auto_unset_gvalue GValue val = G_VALUE_INIT;
|
|
|
|
g_assert_cmpstr(sip->name, ==, sip->param_spec->name);
|
|
|
|
g_value_init(&val, sip->param_spec->value_type);
|
|
g_object_get_property(G_OBJECT(setting), sip->name, &val);
|
|
|
|
if (sip->param_spec->value_type == G_TYPE_STRING) {
|
|
const char *default_value;
|
|
|
|
default_value = ((const GParamSpecString *) sip->param_spec)->default_value;
|
|
if (default_value) {
|
|
/* having a string property with a default != NULL is really ugly. They
|
|
* should be best avoided... */
|
|
if (meta_type == NM_META_SETTING_TYPE_DCB
|
|
&& nm_streq(sip->name, NM_SETTING_DCB_APP_FCOE_MODE)) {
|
|
/* Whitelist the properties that have a non-NULL default value. */
|
|
g_assert_cmpstr(default_value, ==, NM_SETTING_DCB_FCOE_MODE_FABRIC);
|
|
} else
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
if (nm_streq(sip->name, NM_SETTING_NAME))
|
|
g_assert_cmpstr(g_value_get_string(&val), ==, msi->setting_name);
|
|
else
|
|
g_assert_cmpstr(g_value_get_string(&val), ==, default_value);
|
|
}
|
|
|
|
if (NM_FLAGS_HAS(sip->param_spec->flags, NM_SETTING_PARAM_TO_DBUS_IGNORE_FLAGS))
|
|
g_assert(sip->property_type->to_dbus_fcn);
|
|
}
|
|
}
|
|
|
|
/* check that all GObject based properties are tracked by the settings. */
|
|
property_specs =
|
|
g_object_class_list_properties(G_OBJECT_CLASS(sis->setting_class), &n_property_specs);
|
|
g_assert(property_specs);
|
|
g_assert_cmpint(n_property_specs, >, 0);
|
|
for (prop_idx = 0; prop_idx < n_property_specs; prop_idx++) {
|
|
const GParamSpec *pip = property_specs[prop_idx];
|
|
|
|
g_assert(g_hash_table_lookup(h_properties, pip->name) == pip);
|
|
}
|
|
|
|
/* check that property_infos_sorted is as expected. */
|
|
if (sis->property_infos_sorted) {
|
|
gs_unref_hashtable GHashTable *h = g_hash_table_new(nm_direct_hash, NULL);
|
|
|
|
/* property_infos_sorted is only implemented for [connection] type */
|
|
g_assert_cmpint(meta_type, ==, NM_META_SETTING_TYPE_CONNECTION);
|
|
|
|
/* ensure that there are no duplicates, and that all properties are also
|
|
* tracked by sis->property_infos. */
|
|
for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) {
|
|
const NMSettInfoProperty *sip = sis->property_infos_sorted[prop_idx];
|
|
|
|
if (!g_hash_table_add(h, (gpointer) sip))
|
|
g_assert_not_reached();
|
|
}
|
|
for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) {
|
|
const NMSettInfoProperty *sip = &sis->property_infos[prop_idx];
|
|
|
|
g_assert(g_hash_table_contains(h, sip));
|
|
}
|
|
} else
|
|
g_assert_cmpint(meta_type, !=, NM_META_SETTING_TYPE_CONNECTION);
|
|
|
|
/* consistency check for gendata-info. */
|
|
if (sis->detail.gendata_info) {
|
|
g_assert_cmpint(meta_type, ==, NM_META_SETTING_TYPE_ETHTOOL);
|
|
g_assert(sis->detail.gendata_info->get_variant_type);
|
|
|
|
/* the gendata info based setting has only one regular property: the "name". */
|
|
g_assert_cmpint(sis->property_infos_len, ==, 1);
|
|
g_assert_cmpstr(sis->property_infos[0].name, ==, NM_SETTING_NAME);
|
|
} else
|
|
g_assert_cmpint(meta_type, !=, NM_META_SETTING_TYPE_ETHTOOL);
|
|
}
|
|
|
|
{
|
|
gs_free NMSettInfoPropertType **a_property_types = NULL;
|
|
guint a_property_types_len;
|
|
guint prop_idx;
|
|
guint prop_idx_2;
|
|
|
|
a_property_types =
|
|
(NMSettInfoPropertType **) g_hash_table_get_keys_as_array(h_property_types,
|
|
&a_property_types_len);
|
|
|
|
for (prop_idx = 0; prop_idx < a_property_types_len; prop_idx++) {
|
|
const NMSettInfoPropertType *pt = a_property_types[prop_idx];
|
|
|
|
for (prop_idx_2 = prop_idx + 1; prop_idx_2 < a_property_types_len; prop_idx_2++) {
|
|
const NMSettInfoPropertType *pt_2 = a_property_types[prop_idx_2];
|
|
|
|
if (!g_variant_type_equal(pt->dbus_type, pt_2->dbus_type)
|
|
|| pt->to_dbus_fcn != pt_2->to_dbus_fcn
|
|
|| pt->from_dbus_fcn != pt_2->from_dbus_fcn
|
|
|| pt->missing_from_dbus_fcn != pt_2->missing_from_dbus_fcn
|
|
|| pt->gprop_to_dbus_fcn != pt_2->gprop_to_dbus_fcn
|
|
|| pt->gprop_from_dbus_fcn != pt_2->gprop_from_dbus_fcn
|
|
|| memcmp(&pt->typdata_to_dbus,
|
|
&pt_2->typdata_to_dbus,
|
|
sizeof(pt->typdata_to_dbus))
|
|
!= 0)
|
|
continue;
|
|
|
|
if ((pt == &nm_sett_info_propert_type_plain_i
|
|
&& pt_2 == &nm_sett_info_propert_type_deprecated_ignore_i)
|
|
|| (pt_2 == &nm_sett_info_propert_type_plain_i
|
|
&& pt == &nm_sett_info_propert_type_deprecated_ignore_i)
|
|
|| (pt == &nm_sett_info_propert_type_plain_u
|
|
&& pt_2 == &nm_sett_info_propert_type_deprecated_ignore_u)
|
|
|| (pt_2 == &nm_sett_info_propert_type_plain_u
|
|
&& pt == &nm_sett_info_propert_type_deprecated_ignore_u)) {
|
|
/* These are known to be duplicated. This is the case for
|
|
* "gsm.network-type" and plain properties like "802-11-wireless-security.fils" ("i" D-Bus type)
|
|
* "gsm.allowed-bands" and plain properties like "802-11-olpc-mesh.channel" ("u" D-Bus type)
|
|
* While the content/behaviour of the property types are identical, their purpose
|
|
* is different. So allow them.
|
|
*/
|
|
continue;
|
|
}
|
|
|
|
/* the property-types with same content should all be shared. Here we have two that
|
|
* are the same content, but different instances. Bug. */
|
|
g_error("The identical property type for D-Bus type \"%s\" is used by: %s and %s",
|
|
(const char *) pt->dbus_type,
|
|
_PROP_IDX_OWNER(h_property_types, pt),
|
|
_PROP_IDX_OWNER(h_property_types, pt_2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_setting_connection_secondaries_verify(void)
|
|
{
|
|
gs_unref_object NMConnection *con = NULL;
|
|
NMSettingConnection * s_con;
|
|
guint i_run;
|
|
guint i_word;
|
|
|
|
con = nmtst_create_minimal_connection("test-sec", NULL, NM_SETTING_WIRED_SETTING_NAME, &s_con);
|
|
nmtst_connection_normalize(con);
|
|
|
|
for (i_run = 0; i_run < 100; i_run++) {
|
|
guint word_len = nmtst_get_rand_word_length(NULL);
|
|
gs_unref_ptrarray GPtrArray *arr = NULL;
|
|
gs_unref_ptrarray GPtrArray *arr_norm = NULL;
|
|
gboolean was_normalized;
|
|
gboolean was_normalized2;
|
|
|
|
/* create a random list of invalid, normalizable and normalized UUIDs. */
|
|
arr = g_ptr_array_new();
|
|
for (i_word = 0; i_word < word_len; i_word++) {
|
|
g_ptr_array_add(arr,
|
|
(char *) nmtst_rand_select((const char *) "",
|
|
"52c3feb9-3aa2-46f6-a07b-1765918699eb",
|
|
"52C3feb9-3aa2-46f6-a07b-1765918699eb",
|
|
"52C3feb9-3aa2-46f6-a07b-1765918699eb",
|
|
"f86dfb13df764894ab3836b7cdb9d82dde8b27c4",
|
|
"52C3feb93-aa2-46f6-a07b-1765918699eb",
|
|
"bogus"));
|
|
}
|
|
g_ptr_array_add(arr, NULL);
|
|
|
|
/* set the new list of secondaries, and assert that the result is as expected. */
|
|
|
|
nmtst_assert_connection_verifies_without_normalization(con);
|
|
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_SECONDARIES, arr->pdata, NULL);
|
|
|
|
#define _assert_secondaries(s_con, expected) \
|
|
G_STMT_START \
|
|
{ \
|
|
NMSettingConnection *const _s_con = (s_con); \
|
|
const char *const * _expected = (expected); \
|
|
GArray * _secondaries; \
|
|
const guint _expected_len = NM_PTRARRAY_LEN(_expected); \
|
|
gs_strfreev char ** _sec_strv = NULL; \
|
|
guint _i; \
|
|
\
|
|
g_assert(_expected); \
|
|
\
|
|
if (nmtst_get_rand_bool()) { \
|
|
_secondaries = _nm_setting_connection_get_secondaries(_s_con); \
|
|
g_assert_cmpint(_expected_len, ==, nm_g_array_len(_secondaries)); \
|
|
g_assert((_expected_len == 0) == (!_secondaries)); \
|
|
g_assert(nm_utils_strv_equal(_expected, \
|
|
_secondaries ? nm_strvarray_get_strv(&_secondaries, NULL) \
|
|
: NM_PTRARRAY_EMPTY(const char *))); \
|
|
} \
|
|
\
|
|
if (nmtst_get_rand_bool()) { \
|
|
g_object_get(_s_con, NM_SETTING_CONNECTION_SECONDARIES, &_sec_strv, NULL); \
|
|
g_assert_cmpint(_expected_len, ==, NM_PTRARRAY_LEN(_sec_strv)); \
|
|
g_assert((_expected_len == 0) == (!_sec_strv)); \
|
|
g_assert(nm_utils_strv_equal(_expected, _sec_strv ?: NM_STRV_EMPTY())); \
|
|
} \
|
|
\
|
|
g_assert_cmpint(nm_setting_connection_get_num_secondaries(_s_con), ==, _expected_len); \
|
|
if (nmtst_get_rand_bool()) { \
|
|
for (_i = 0; _i < _expected_len; _i++) { \
|
|
g_assert_cmpstr(nm_setting_connection_get_secondary(_s_con, _i), \
|
|
==, \
|
|
_expected[_i]); \
|
|
} \
|
|
g_assert_null(nm_setting_connection_get_secondary(_s_con, _expected_len)); \
|
|
} \
|
|
} \
|
|
G_STMT_END
|
|
|
|
_assert_secondaries(s_con, (const char *const *) arr->pdata);
|
|
|
|
/* reimplement the normalization that we expect to happen and
|
|
* create an array @arr_norm with the expected result after normalization. */
|
|
arr_norm = g_ptr_array_new_with_free_func(g_free);
|
|
for (i_word = 0; i_word < word_len; i_word++) {
|
|
const char *s = arr->pdata[i_word];
|
|
gboolean is_normalized;
|
|
char uuid_normalized[37];
|
|
|
|
if (!nm_uuid_is_valid_nm(s, &is_normalized, uuid_normalized))
|
|
continue;
|
|
|
|
if (is_normalized)
|
|
s = uuid_normalized;
|
|
|
|
if (nm_utils_strv_find_first((char **) arr_norm->pdata, arr_norm->len, s) >= 0)
|
|
continue;
|
|
|
|
g_ptr_array_add(arr_norm, g_strdup(s));
|
|
}
|
|
g_ptr_array_add(arr_norm, NULL);
|
|
|
|
was_normalized = !nm_utils_strv_equal((char **) arr->pdata, (char **) arr_norm->pdata);
|
|
|
|
if (was_normalized)
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
else
|
|
nmtst_assert_connection_verifies_without_normalization(con);
|
|
|
|
if (was_normalized || nmtst_get_rand_bool()) {
|
|
was_normalized2 = nmtst_connection_normalize(con);
|
|
g_assert(was_normalized == was_normalized2);
|
|
}
|
|
|
|
_assert_secondaries(s_con, (const char *const *) arr_norm->pdata);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
NMTST_DEFINE();
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
nmtst_init(&argc, &argv, TRUE);
|
|
|
|
g_test_add_func("/libnm/test_connection_uuid", test_connection_uuid);
|
|
|
|
g_test_add_func("/libnm/settings/test_nm_meta_setting_types_by_priority",
|
|
test_nm_meta_setting_types_by_priority);
|
|
|
|
g_test_add_data_func("/libnm/setting-8021x/key-and-cert",
|
|
"test_key_and_cert.pem, test",
|
|
test_8021x);
|
|
g_test_add_data_func("/libnm/setting-8021x/key-only", "test-key-only.pem, test", test_8021x);
|
|
g_test_add_data_func("/libnm/setting-8021x/pkcs8-enc-key",
|
|
"pkcs8-enc-key.pem, 1234567890",
|
|
test_8021x);
|
|
g_test_add_data_func("/libnm/setting-8021x/pkcs12", "test-cert.p12, test", test_8021x);
|
|
|
|
g_test_add_func("/libnm/settings/test_setting_connection_secondaries_verify",
|
|
test_setting_connection_secondaries_verify);
|
|
|
|
g_test_add_func("/libnm/settings/bond/verify", test_bond_verify);
|
|
g_test_add_func("/libnm/settings/bond/compare", test_bond_compare);
|
|
g_test_add_func("/libnm/settings/bond/normalize", test_bond_normalize);
|
|
|
|
g_test_add_func("/libnm/settings/dcb/flags-valid", test_dcb_flags_valid);
|
|
g_test_add_func("/libnm/settings/dcb/flags-invalid", test_dcb_flags_invalid);
|
|
g_test_add_func("/libnm/settings/dcb/app-priorities", test_dcb_app_priorities);
|
|
g_test_add_func("/libnm/settings/dcb/priorities", test_dcb_priorities_valid);
|
|
g_test_add_func("/libnm/settings/dcb/bandwidth-sums", test_dcb_bandwidth_sums);
|
|
|
|
g_test_add_func("/libnm/settings/ethtool/features", test_ethtool_features);
|
|
g_test_add_func("/libnm/settings/ethtool/coalesce", test_ethtool_coalesce);
|
|
g_test_add_func("/libnm/settings/ethtool/ring", test_ethtool_ring);
|
|
g_test_add_func("/libnm/settings/ethtool/pause", test_ethtool_pause);
|
|
|
|
g_test_add_func("/libnm/settings/sriov/vf", test_sriov_vf);
|
|
g_test_add_func("/libnm/settings/sriov/vf-dup", test_sriov_vf_dup);
|
|
g_test_add_func("/libnm/settings/sriov/vf-vlan", test_sriov_vf_vlan);
|
|
g_test_add_func("/libnm/settings/sriov/setting", test_sriov_setting);
|
|
g_test_add_func("/libnm/settings/sriov/vlans", test_sriov_parse_vlans);
|
|
|
|
g_test_add_func("/libnm/settings/tc_config/qdisc", test_tc_config_qdisc);
|
|
g_test_add_func("/libnm/settings/tc_config/action", test_tc_config_action);
|
|
g_test_add_func("/libnm/settings/tc_config/tfilter/matchall_sdata",
|
|
test_tc_config_tfilter_matchall_sdata);
|
|
g_test_add_func("/libnm/settings/tc_config/tfilter/matchall_mirred",
|
|
test_tc_config_tfilter_matchall_mirred);
|
|
g_test_add_func("/libnm/settings/tc_config/setting/valid", test_tc_config_setting_valid);
|
|
g_test_add_func("/libnm/settings/tc_config/setting/duplicates",
|
|
test_tc_config_setting_duplicates);
|
|
g_test_add_func("/libnm/settings/tc_config/dbus", test_tc_config_dbus);
|
|
|
|
g_test_add_func("/libnm/settings/bridge/vlans", test_bridge_vlans);
|
|
g_test_add_func("/libnm/settings/bridge/verify", test_bridge_verify);
|
|
|
|
g_test_add_func("/libnm/test_nm_json", test_nm_json);
|
|
g_test_add_func("/libnm/settings/team/sync_runner_from_config_roundrobin",
|
|
test_runner_roundrobin_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_runner_from_config_broadcast",
|
|
test_runner_broadcast_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_runner_from_config_random",
|
|
test_runner_random_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_runner_from_config_activebackup",
|
|
test_runner_activebackup_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_runner_from_config_loadbalance",
|
|
test_runner_loadbalance_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_runner_from_config_lacp",
|
|
test_runner_lacp_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_watcher_from_config_ethtool",
|
|
test_watcher_ethtool_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_watcher_from_config_nsna_ping",
|
|
test_watcher_nsna_ping_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_watcher_from_config_arp_ping",
|
|
test_watcher_arp_ping_sync_from_config);
|
|
g_test_add_func("/libnm/settings/team/sync_watcher_from_config_all",
|
|
test_multiple_watchers_sync_from_config);
|
|
|
|
g_test_add_func("/libnm/settings/team-port/sync_from_config_defaults", test_team_port_default);
|
|
g_test_add_func("/libnm/settings/team-port/sync_from_config_queue_id", test_team_port_queue_id);
|
|
g_test_add_func("/libnm/settings/team-port/sync_from_config_prio", test_team_port_prio);
|
|
g_test_add_func("/libnm/settings/team-port/sync_from_config_sticky", test_team_port_sticky);
|
|
g_test_add_func("/libnm/settings/team-port/sync_from_config_lacp_prio",
|
|
test_team_port_lacp_prio);
|
|
g_test_add_func("/libnm/settings/team-port/sync_from_config_lacp_key", test_team_port_lacp_key);
|
|
g_test_add_func("/libnm/settings/team-port/sycn_from_config_full", test_team_port_full_config);
|
|
|
|
g_test_add_data_func("/libnm/settings/roundtrip-conversion/general/0",
|
|
GINT_TO_POINTER(0),
|
|
test_roundtrip_conversion);
|
|
g_test_add_data_func("/libnm/settings/roundtrip-conversion/wireguard/1",
|
|
GINT_TO_POINTER(1),
|
|
test_roundtrip_conversion);
|
|
g_test_add_data_func("/libnm/settings/roundtrip-conversion/wireguard/2",
|
|
GINT_TO_POINTER(2),
|
|
test_roundtrip_conversion);
|
|
g_test_add_data_func("/libnm/settings/roundtrip-conversion/general/3",
|
|
GINT_TO_POINTER(3),
|
|
test_roundtrip_conversion);
|
|
|
|
g_test_add_data_func("/libnm/settings/routing-rule/1", GINT_TO_POINTER(0), test_routing_rule);
|
|
|
|
g_test_add_func("/libnm/parse-tc-handle", test_parse_tc_handle);
|
|
|
|
g_test_add_func("/libnm/test_team_setting", test_team_setting);
|
|
|
|
g_test_add_func("/libnm/test_empty_setting", test_empty_setting);
|
|
|
|
g_test_add_func("/libnm/test_setting_metadata", test_setting_metadata);
|
|
|
|
return g_test_run();
|
|
}
|