NetworkManager/libnm-core/tests/test-setting.c
Thomas Haller 13f6f3a410 libnm: rework team handling of JSON config
Completely refactor the team/JSON handling in libnm's NMSettingTeam and
NMSettingTeamPort.

- team handling was added as rh#1398925. The goal is to have a more
  convenient way to set properties than constructing JSON. This requires
  libnm to implement the hard task of parsing JSON (and exposing well-understood
  properties) and generating JSON (based on these "artificial" properties).
  But not only libnm. In particular nmcli and the D-Bus API must make this
  "simpler" API accessible.

- since NMSettingTeam and NMSettingTeamPort are conceptually the same,
  add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to
  handle the similar code side-by-sdie.
  The setting classes now just delegate for everything to NMTeamSetting.

- Previously, there was a very fuzzy understanding of the provided
  JSON config. Tighten that up, when setting a JSON config it
  regenerates/parses all other properties and tries to make the
  best of it. When modifying any abstraction property, the entire
  JSON config gets regenerated. In particular, don't try to merge
  existing JSON config with the new fields. If the user uses the
  abstraction API, then the entire JSON gets replaced.

  For example note that nm_setting_team_add_link_watcher() would not
  be reflected in the JSON config (a bug). That only accidentally worked
  because client would serializing the changed link watcher to
  GVariant/D-Bus, then NetworkManager would set it via g_object_set(),
  which would renerate the JSON, and finally persist it to disk. But
  as far as libnm is concerned, nm_setting_team_add_link_watcher() would
  bring the settings instance in an inconsistent state where JSON and
  the link watcher property disagree. Setting any property must
  immediately update both the JSON and the abstraction API.

- when constucting a team setting from D-Bus, we would previously parse
  both "config" and abstraction properties. That is wrong. Since our
  settings plugins only support JSON, all information must be present
  in the JSON config anyway. So, when "config" is present, only the JSON
  must be parsed. In the best case, the other information is redudant and
  contributes nothing. In the worse case, they information differs
  (which might happen if the client version differs from the server
  version). As the settings plugin only supports JSON, it's wrong to
  consider redundant, differing information from D-Bus.

- we now only convert string to JSON or back when needed. Previously,
  setting a property resulted in parsing several JSON multiple times
  (per property). All operations should now scale well and be reasonably
  efficient.

- also the property-changed signals are now handled correctly. Since
  NMTeamSetting knows the current state of all attributes, it can emit
  the exact property changed signals for what changed.

- we no longer use libjansson to generate the JSON. JSON is supposed
  to be a machine readable exchange format, hence a major goal is
  to be easily handled by applications. While parsing JSON is not so
  trivial, writing a well-known set of values to JSON is.
  The advantage is that when you build libnm without libjansson support,
  then we still can convert the artificial properties to JSON.

- Requiring libjansson in libnm is a burden, because most of the time
  it is not needed (as most users don't create team configurations). With
  this change we only require it to parse the team settings (no longer to
  write them). It should be reasonably simple to use a more minimalistic
  JSON parser that is sufficient for us, so that we can get rid of the
  libjansson dependency (for libnm). This also avoids the pain that we have
  due to the symbol collision of libjansson and libjson-glib.

https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-23 18:09:49 +02:00

3378 lines
128 KiB
C

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright 2008 - 2017 Red Hat, Inc.
*
*/
#include "nm-default.h"
#include <linux/pkt_sched.h>
#include <net/if.h>
#include "nm-utils.h"
#include "nm-utils-private.h"
#include "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 "nm-keyfile-internal.h"
#include "nm-utils/nm-test-utils.h"
#define TEST_CERT_DIR NM_BUILD_SRCDIR"/libnm-core/tests/certs"
/*****************************************************************************/
/* assert that the define is just a plain integer (boolean). */
G_STATIC_ASSERT ( (WITH_JSON_VALIDATION) == 1
|| (WITH_JSON_VALIDATION) == 0);
_nm_unused static const int _with_json_validation = WITH_JSON_VALIDATION;
/*****************************************************************************/
/* 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_int () % G_N_ELEMENTS (cons));
guint idx_b = (nmtst_get_rand_int () % 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 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_int () % 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_int () % 256, nmtst_get_rand_int () % 256, delimiter, num);
else
return g_strdup_printf ("a:b:c::%02x:%02x%c%d", nmtst_get_rand_int () % 256, nmtst_get_rand_int () % 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
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_assert (*con);
g_assert (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 (NM_MAKE_STRV (__VA_ARGS__), exp)
static void
_test_verify_options (const char *const *options,
gboolean expected_result)
{
gs_unref_object NMConnection *con = NULL;
NMSettingBond *s_bond;
GError *error = NULL;
gboolean success;
const char *const *option;
create_bond_connection (&con, &s_bond);
for (option = options; option[0] && option[1]; 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);
nmtst_connection_normalize (con);
success = nm_setting_verify ((NMSetting *) s_bond, con, &error);
nmtst_assert_success (success, error);
} 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");
}
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 }));
/* ignore default values */
test_bond_compare_options (TRUE,
((const char *[]){ "miimon", "1", NULL }),
((const char *[]){ "miimon", "1", "updelay", "0", NULL }));
/* special handling of num_grat_arp, num_unsol_na */
test_bond_compare_options (FALSE,
((const char *[]){ "num_grat_arp", "2", NULL }),
((const char *[]){ "num_grat_arp", "1", NULL }));
test_bond_compare_options (TRUE,
((const char *[]){ "num_grat_arp", "3", NULL }),
((const char *[]){ "num_unsol_na", "3", NULL }));
test_bond_compare_options (TRUE,
((const char *[]){ "num_grat_arp", "4", NULL }),
((const char *[]){ "num_unsol_na", "4", "num_grat_arp", "4", 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", 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_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 (!WITH_JSON_VALIDATION) {
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 ("",
0, 0, 0, 0,
NM_SETTING_TEAM_RUNNER_ROUNDROBIN,
NULL,
NULL, NULL, -1,
FALSE, FALSE, -1, -1, NULL,
NULL);
}
static void
test_runner_broadcast_sync_from_config (void)
{
_test_team_config_sync ("{\"runner\": {\"name\": \"broadcast\"}}",
0, 0, 0, 0,
NM_SETTING_TEAM_RUNNER_BROADCAST,
NULL,
NULL, NULL, -1,
FALSE, FALSE, -1, -1, NULL,
NULL);
}
static void
test_runner_random_sync_from_config (void)
{
_test_team_config_sync ("{\"runner\": {\"name\": \"random\"}}",
0, 0, 0, 0,
NM_SETTING_TEAM_RUNNER_RANDOM,
NULL,
NULL, NULL, -1,
FALSE, FALSE, -1, -1, NULL,
NULL);
}
static void
test_runner_activebackup_sync_from_config (void)
{
_test_team_config_sync ("{\"runner\": {\"name\": \"activebackup\"}}",
NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT, 0,
NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT, 0,
NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP,
NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_DEFAULT,
NULL, NULL, -1,
FALSE, 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\"}}",
0, 0, 0, 0,
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
NULL,
tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT,
FALSE, FALSE, -1, -1, NULL,
NULL);
_test_team_config_sync ("{\"runner\": {\"name\": \"loadbalance\", "
"\"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}",
0, 0, 0, 0,
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
NULL,
tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT,
FALSE, FALSE, -1, -1, NULL,
NULL);
_test_team_config_sync ("{\"runner\": {\"name\": \"loadbalance\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"], "
"\"tx_balancer\": {\"name\": \"basic\", \"balancing_interval\": 30}}}",
0, 0, 0, 0,
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
NULL,
tx_hash, "basic", 30,
FALSE, 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\"]}}",
0, 0, 0, 0,
NM_SETTING_TEAM_RUNNER_LACP,
NULL,
tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT,
TRUE, FALSE, NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT, 0,
NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT,
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\"}}",
0, 0, 0, 0,
NM_SETTING_TEAM_RUNNER_LACP,
NULL,
tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT,
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\"}}",
0, 0, 0, 0,
"roundrobin",
NULL,
NULL, NULL, -1,
FALSE, 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\"}}",
0, 0, 0, 0,
"roundrobin",
NULL,
NULL, NULL, -1,
FALSE, 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\"}}",
0, 0, 0, 0,
"roundrobin",
NULL,
NULL, NULL, -1,
FALSE, 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\"}]}",
0, 0, 0, 0,
"roundrobin",
NULL,
NULL, NULL, -1,
FALSE, 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 (!WITH_JSON_VALIDATION) {
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, 255, 0, NULL);
}
static void
test_team_port_queue_id (void)
{
_test_team_port_config_sync ("{\"queue_id\": 3}",
3, 0, FALSE, 255, 0, NULL);
_test_team_port_config_sync ("{\"queue_id\": 0}",
0, 0, FALSE, 255, 0, NULL);
}
static void
test_team_port_prio (void)
{
_test_team_port_config_sync ("{\"prio\": 6}",
-1, 6, FALSE, 255, 0, NULL);
_test_team_port_config_sync ("{\"prio\": 0}",
-1, 0, FALSE, 255, 0, NULL);
}
static void
test_team_port_sticky (void)
{
_test_team_port_config_sync ("{\"sticky\": true}",
-1, 0, TRUE, 255, 0, NULL);
_test_team_port_config_sync ("{\"sticky\": false}",
-1, 0, FALSE, 255, 0, NULL);
}
static void
test_team_port_lacp_prio (void)
{
_test_team_port_config_sync ("{\"lacp_prio\": 9}",
-1, 0, FALSE, 9, 0, NULL);
_test_team_port_config_sync ("{\"lacp_prio\": 0}",
-1, 0, FALSE, 0, 0, NULL);
}
static void
test_team_port_lacp_key (void)
{
_test_team_port_config_sync ("{\"lacp_key\": 12}",
-1, 0, FALSE, 255, 12, NULL);
_test_team_port_config_sync ("{\"lacp_key\": 0}",
-1, 0, FALSE, 255, 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);
setting_clone = nm_setting_duplicate (setting);
if (!is_port) {
if (nm_setting_team_get_runner (NM_SETTING_TEAM (setting)) == NULL) {
/* such a setting is invalid. We must first coerce it so that it becomes
* valid. */
setting = setting_clone;
g_object_set (setting,
NM_SETTING_TEAM_RUNNER,
NM_SETTING_TEAM_RUNNER_DEFAULT,
NULL);
}
}
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 (WITH_JSON_VALIDATION)
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 = 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);
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'>}]>, 'runner': <'roundrobin'>, 'runner-min-ports': <-1>, 'runner-sys-prio': <-1>, 'runner-tx-balancer-interval': <-1>}");
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\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4} }");
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\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4}, { \"name\": \"arp_ping\", \"target_host\": \"ccc\", \"source_host\": \"ddd\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4} ] }");
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 } }");
}
/*****************************************************************************/
static void
test_ethtool_1 (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;
gs_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));
nm_setting_ethtool_set_feature (s_ethtool,
NM_ETHTOOL_OPTNAME_FEATURE_RX,
NM_TERNARY_TRUE);
nm_setting_ethtool_set_feature (s_ethtool,
NM_ETHTOOL_OPTNAME_FEATURE_LRO,
NM_TERNARY_FALSE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX), ==, NM_TERNARY_TRUE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_LRO), ==, NM_TERNARY_FALSE);
g_assert_cmpint (nm_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 (nm_setting_ethtool_get_feature (s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_RX), ==, NM_TERNARY_TRUE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_LRO), ==, NM_TERNARY_FALSE);
g_assert_cmpint (nm_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, NULL, NULL, &error);
nmtst_assert_success (keyfile, error);
con3 = nm_keyfile_read (keyfile,
"/ignored/current/working/directory/for/loading/relative/paths",
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 (nm_setting_ethtool_get_feature (s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_RX), ==, NM_TERNARY_TRUE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_LRO), ==, NM_TERNARY_FALSE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_SG), ==, NM_TERNARY_DEFAULT);
}
/*****************************************************************************/
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_utils_uuid_generate_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");
g_clear_pointer (&str, g_free);
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
test_tc_config_qdisc (void)
{
NMTCQdisc *qdisc1, *qdisc2;
char *str;
GError *error = NULL;
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 (0x1234 << 16, 0x0000));
g_assert (nm_tc_qdisc_get_parent (qdisc1) == TC_H_MAKE (0xfff1 << 16, 0x0001));
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);
}
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 (void)
{
NMTCAction *action1;
NMTCTfilter *tfilter1, *tfilter2;
char *str;
GError *error = NULL;
tfilter1 = nm_tc_tfilter_new ("matchall",
TC_H_MAKE (0x1234 << 16, 0x0000),
&error);
nmtst_assert_success (tfilter1, error);
tfilter2 = nm_tc_tfilter_new ("matchall",
TC_H_MAKE (0x1234 << 16, 0x0000),
&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_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 (0xfff1 << 16, 0x0001),
&error);
nmtst_assert_success (qdisc2, error);
nm_tc_qdisc_set_handle (qdisc2, TC_H_MAKE (0x1234 << 16, 0x0000));
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 (0x1234 << 16, 0x0000));
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, 0));
nm_setting_tc_config_add_qdisc (NM_SETTING_TC_CONFIG (s_tc), qdisc2);
tfilter1 = nm_tc_tfilter_new ("matchall",
TC_H_MAKE (0x1234 << 16, 0x0000),
&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, 0),
&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_int () % (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++) {
guint p = nmtst_get_rand_int () % 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_int () % 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_int ()));
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_int () % 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, "roundtip-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_int ());
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_int () % 0x10000);
const guint WG_FWMARK = nmtst_rand_select (0u,
nmtst_get_rand_int ());
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_NO_SECRETS,
NM_CONNECTION_SERIALIZE_ONLY_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"
"",
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"
"[ipv4]\n"
"dns-search=\n"
"method=disabled\n"
"\n"
"[ipv6]\n"
"addr-gen-mode=stable-privacy\n"
"dns-search=\n"
"method=ignore\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"
"%s" /* [wireguard] */
"%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"
"",
ID,
UUID,
INTERFACE_NAME,
( ( (WG_FWMARK != 0)
|| (WG_LISTEN_PORT != 0)
|| (WG_PRIVATE_KEY_FLAGS != NM_SETTING_SECRET_FLAG_NONE)
|| ( WG_PRIVATE_KEY
&& WG_PRIVATE_KEY_FLAGS == NM_SETTING_SECRET_FLAG_NONE))
? "\n[wireguard]\n"
: ""),
( (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"
"",
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. */
{
gs_unref_keyfile GKeyFile *kf = NULL;
kf = nm_keyfile_write (con, 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 ());
{
gs_unref_keyfile GKeyFile *kf = NULL;
kf = nm_keyfile_write (con2, 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_NO_SECRETS)
_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 ("not priority 5 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");
}
/*****************************************************************************/
NMTST_DEFINE ();
int
main (int argc, char **argv)
{
nmtst_init (&argc, &argv, TRUE);
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/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/1", test_ethtool_1);
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", test_tc_config_tfilter);
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/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);
return g_test_run ();
}