2020-12-23 22:21:36 +01:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2017-12-03 13:37:39 +01:00
|
|
|
/*
|
2019-10-01 09:20:35 +02:00
|
|
|
* Copyright (C) 2008 - 2017 Red Hat, Inc.
|
2017-12-03 13:37:39 +01:00
|
|
|
*/
|
|
|
|
|
|
2021-02-04 16:04:15 +01:00
|
|
|
#include "libnm-core/nm-default-libnm-core.h"
|
2017-12-03 13:37:39 +01:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
#include <linux/pkt_sched.h>
|
2019-03-13 09:18:49 +01:00
|
|
|
#include <net/if.h>
|
2017-12-03 13:37:39 +01:00
|
|
|
|
2020-07-01 19:26:33 +02:00
|
|
|
#include "nm-glib-aux/nm-json-aux.h"
|
2021-01-09 12:00:33 +01:00
|
|
|
#include "nm-base/nm-ethtool-utils-base.h"
|
2019-09-21 20:35:18 +02:00
|
|
|
#include "nm-core-internal.h"
|
2017-12-03 13:37:39 +01:00
|
|
|
#include "nm-utils.h"
|
2018-05-25 12:05:24 +02:00
|
|
|
#include "nm-utils-private.h"
|
|
|
|
|
#include "nm-core-internal.h"
|
2017-12-03 13:37:39 +01:00
|
|
|
#include "nm-setting-8021x.h"
|
|
|
|
|
#include "nm-setting-bond.h"
|
|
|
|
|
#include "nm-setting-dcb.h"
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
#include "nm-setting-ethtool.h"
|
2017-11-22 14:44:43 +01:00
|
|
|
#include "nm-setting-team.h"
|
2017-12-01 10:07:04 +01:00
|
|
|
#include "nm-setting-team-port.h"
|
2017-12-03 13:42:57 +01:00
|
|
|
#include "nm-setting-tc-config.h"
|
|
|
|
|
#include "nm-setting-dummy.h"
|
2017-12-03 13:37:39 +01:00
|
|
|
#include "nm-connection.h"
|
|
|
|
|
#include "nm-simple-connection.h"
|
|
|
|
|
#include "nm-setting-connection.h"
|
|
|
|
|
#include "nm-errors.h"
|
2020-01-02 07:37:59 +01:00
|
|
|
#include "nm-keyfile/nm-keyfile-internal.h"
|
2017-12-03 13:37:39 +01:00
|
|
|
|
|
|
|
|
#include "nm-utils/nm-test-utils.h"
|
|
|
|
|
|
2018-05-30 10:23:17 +02:00
|
|
|
#define TEST_CERT_DIR NM_BUILD_SRCDIR "/libnm-core/tests/certs"
|
|
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
/* 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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
g_assert(g_variant_is_of_type(dict, NM_VARIANT_TYPE_CONNECTION));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
nmtst_assert_connection_verifies(con_x_0);
|
|
|
|
|
nmtst_assert_connection_verifies(con_x_e);
|
|
|
|
|
nmtst_assert_connection_verifies(con_x_s);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
/* 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};
|
2019-05-30 08:33:14 +02:00
|
|
|
guint idx_a = (nmtst_get_rand_uint32() % G_N_ELEMENTS(cons));
|
|
|
|
|
guint idx_b = (nmtst_get_rand_uint32() % G_N_ELEMENTS(cons));
|
2019-01-03 13:24:06 +01:00
|
|
|
gboolean normalize_a, normalize_b;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
return (normalize) ? g_steal_pointer(&con_x_0) : g_steal_pointer(&con_n_0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
static char *
|
|
|
|
|
_create_random_ipaddr(int addr_family, gboolean as_service)
|
|
|
|
|
{
|
|
|
|
|
char delimiter = as_service ? ':' : '/';
|
|
|
|
|
int num;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
if (addr_family == AF_UNSPEC)
|
|
|
|
|
addr_family = nmtst_rand_select(AF_INET, AF_INET6);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
if (as_service)
|
2019-05-30 08:33:14 +02:00
|
|
|
num = (nmtst_get_rand_uint32() % 1000) + 30000;
|
2019-01-03 13:38:02 +01:00
|
|
|
else
|
|
|
|
|
num = addr_family == AF_INET ? 32 : 128;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
if (addr_family == AF_INET)
|
2019-05-30 08:33:14 +02:00
|
|
|
return g_strdup_printf("192.168.%u.%u%c%d",
|
|
|
|
|
nmtst_get_rand_uint32() % 256,
|
|
|
|
|
nmtst_get_rand_uint32() % 256,
|
|
|
|
|
delimiter,
|
|
|
|
|
num);
|
2019-01-03 13:38:02 +01:00
|
|
|
else
|
2019-05-30 08:33:14 +02:00
|
|
|
return g_strdup_printf("a:b:c::%02x:%02x%c%d",
|
|
|
|
|
nmtst_get_rand_uint32() % 256,
|
|
|
|
|
nmtst_get_rand_uint32() % 256,
|
|
|
|
|
delimiter,
|
|
|
|
|
num);
|
2019-01-03 13:38:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
static void
|
|
|
|
|
compare_blob_data(const char *test, const char *key_path, GBytes *key)
|
|
|
|
|
{
|
2018-08-22 21:35:33 +02:00
|
|
|
gs_free char *contents = NULL;
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
libnm/802-1x: refactor setting certificate from path
NMSetting8021x has various utility functions to set
the certificate:
- nm_setting_802_1x_set_ca_cert()
- nm_setting_802_1x_set_client_cert()
- nm_setting_802_1x_set_private_key()
- nm_setting_802_1x_set_phase2_ca_cert()
- nm_setting_802_1x_set_phase2_client_cert()
- nm_setting_802_1x_set_phase2_private_key()
They support:
- accepting a plain PKCS11 URI, with scheme set to
NM_SETTING_802_1X_CK_SCHEME_PKCS11.
- accepting a filename, with scheme set to
NM_SETTING_802_1X_CK_SCHEME_BLOB or
NM_SETTING_802_1X_CK_SCHEME_PATH.
In the latter case, the function tries to load the file and verify it.
In case of the private-key setters, this also involves accepting a
password. Depending on whether the scheme is BLOB or PATH, the function
will either set the certificate to a PATH blob, or take the blob that
was read from file.
The functions seem misdesigned to me, because their behavior is
rather obscure. E.g. they behave fundamentally different, depending
on whether scheme is PKCS11 or BLOB/PATH.
Anyway, improve them:
- refactor the common code into a function _cert_impl_set(). Previously,
their non-trivial implementations were copy+pasted several times,
now they all use the same implementation.
- if the function is going to fail, don't touch the setting. Previously,
the functions would first clear the certificate before trying to
validate the input. It's more logical, that if a functions is going
to fail to check for failure first and don't modify the settings.
- not every blob can be represented. For example, if we have a blob
which starts with "file://", then there is no way to set it, simply
because we don't support a prefix for blobs (like "data:;base64,").
This means, if we try to set the certificate to a particular binary,
we must check that the binary is interpreted with the expected scheme.
Add this check.
2018-09-01 18:08:33 +02:00
|
|
|
gsize l;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
g_assert(value);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/802-1x: refactor setting certificate from path
NMSetting8021x has various utility functions to set
the certificate:
- nm_setting_802_1x_set_ca_cert()
- nm_setting_802_1x_set_client_cert()
- nm_setting_802_1x_set_private_key()
- nm_setting_802_1x_set_phase2_ca_cert()
- nm_setting_802_1x_set_phase2_client_cert()
- nm_setting_802_1x_set_phase2_private_key()
They support:
- accepting a plain PKCS11 URI, with scheme set to
NM_SETTING_802_1X_CK_SCHEME_PKCS11.
- accepting a filename, with scheme set to
NM_SETTING_802_1X_CK_SCHEME_BLOB or
NM_SETTING_802_1X_CK_SCHEME_PATH.
In the latter case, the function tries to load the file and verify it.
In case of the private-key setters, this also involves accepting a
password. Depending on whether the scheme is BLOB or PATH, the function
will either set the certificate to a PATH blob, or take the blob that
was read from file.
The functions seem misdesigned to me, because their behavior is
rather obscure. E.g. they behave fundamentally different, depending
on whether scheme is PKCS11 or BLOB/PATH.
Anyway, improve them:
- refactor the common code into a function _cert_impl_set(). Previously,
their non-trivial implementations were copy+pasted several times,
now they all use the same implementation.
- if the function is going to fail, don't touch the setting. Previously,
the functions would first clear the certificate before trying to
validate the input. It's more logical, that if a functions is going
to fail to check for failure first and don't modify the settings.
- not every blob can be represented. For example, if we have a blob
which starts with "file://", then there is no way to set it, simply
because we don't support a prefix for blobs (like "data:;base64,").
This means, if we try to set the certificate to a particular binary,
we must check that the binary is interpreted with the expected scheme.
Add this check.
2018-09-01 18:08:33 +02:00
|
|
|
p = g_bytes_get_data(value, &l);
|
|
|
|
|
g_assert_cmpint(l, ==, strlen(path) + NM_STRLEN(NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH) + 1);
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
|
|
|
g_assert(s_8021x);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
g_object_get(s_8021x, NM_SETTING_802_1X_CLIENT_CERT, &client_cert, NULL);
|
|
|
|
|
g_assert(client_cert);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* make sure they are the same */
|
|
|
|
|
g_assert(g_bytes_equal(tmp_key, client_cert));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
g_bytes_unref(tmp_key);
|
|
|
|
|
g_bytes_unref(client_cert);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
|
|
|
g_assert(s_8021x);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
g_object_get(s_8021x, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &client_cert, NULL);
|
|
|
|
|
g_assert(client_cert);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* make sure they are the same */
|
|
|
|
|
g_assert(g_bytes_equal(tmp_key, client_cert));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
g_bytes_unref(tmp_key);
|
|
|
|
|
g_bytes_unref(client_cert);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
|
|
|
g_assert(s_8021x);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
|
|
|
g_assert(s_8021x);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* Ensure the password is also now clear */
|
|
|
|
|
g_assert(!nm_setting_802_1x_get_private_key_password(s_8021x));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
|
|
|
g_assert(s_8021x);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();
|
|
|
|
|
g_assert(s_8021x);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* Ensure the password is also now clear */
|
|
|
|
|
g_assert(!nm_setting_802_1x_get_phase2_private_key_password(s_8021x));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
g_object_unref(s_8021x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_8021x(gconstpointer test_data)
|
|
|
|
|
{
|
|
|
|
|
char **parts, *path, *password;
|
|
|
|
|
|
|
|
|
|
parts = g_strsplit((const char *) test_data, ", ", -1);
|
|
|
|
|
g_assert_cmpint(g_strv_length(parts), ==, 2);
|
|
|
|
|
|
|
|
|
|
path = g_build_filename(TEST_CERT_DIR, parts[0], NULL);
|
|
|
|
|
password = parts[1];
|
|
|
|
|
|
|
|
|
|
/* Test phase1 and phase2 path scheme */
|
|
|
|
|
test_private_key_import(path, password, NM_SETTING_802_1X_CK_SCHEME_PATH);
|
|
|
|
|
test_phase2_private_key_import(path, password, NM_SETTING_802_1X_CK_SCHEME_PATH);
|
|
|
|
|
|
|
|
|
|
/* Test phase1 and phase2 blob scheme */
|
|
|
|
|
test_private_key_import(path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB);
|
|
|
|
|
test_phase2_private_key_import(path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB);
|
|
|
|
|
|
|
|
|
|
/* Test that using a wrong password does not change existing data */
|
|
|
|
|
test_wrong_password_keeps_data(path, password);
|
|
|
|
|
test_wrong_phase2_password_keeps_data(path, password);
|
|
|
|
|
|
|
|
|
|
/* Test clearing the private key */
|
|
|
|
|
test_clear_private_key(path, password);
|
|
|
|
|
test_clear_phase2_private_key(path, password);
|
|
|
|
|
|
|
|
|
|
g_free(path);
|
|
|
|
|
g_strfreev(parts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
create_bond_connection(NMConnection **con, NMSettingBond **s_bond)
|
|
|
|
|
{
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
|
|
|
|
|
g_assert(con);
|
|
|
|
|
g_assert(s_bond);
|
|
|
|
|
|
|
|
|
|
*con = nmtst_create_minimal_connection("bond", NULL, NM_SETTING_BOND_SETTING_NAME, &s_con);
|
|
|
|
|
|
|
|
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "bond0", NULL);
|
|
|
|
|
|
|
|
|
|
*s_bond = (NMSettingBond *) nm_setting_bond_new();
|
|
|
|
|
g_assert(*s_bond);
|
|
|
|
|
|
|
|
|
|
nm_connection_add_setting(*con, NM_SETTING(*s_bond));
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
#define test_verify_options(exp, ...) _test_verify_options(exp, NM_MAKE_STRV(__VA_ARGS__))
|
2017-12-03 13:37:39 +01:00
|
|
|
|
|
|
|
|
static void
|
2020-03-23 19:29:24 +01:00
|
|
|
_test_verify_options(gboolean expected_result, const char *const *options)
|
2017-12-03 13:37:39 +01:00
|
|
|
{
|
|
|
|
|
gs_unref_object NMConnection *con = NULL;
|
|
|
|
|
NMSettingBond * s_bond;
|
2018-11-30 11:37:21 +01:00
|
|
|
const char *const * option;
|
2017-12-03 13:37:39 +01:00
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
g_assert(NM_PTRARRAY_LEN(options) % 2 == 0);
|
|
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
create_bond_connection(&con, &s_bond);
|
|
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
for (option = options; option[0]; option += 2)
|
2017-12-03 13:37:39 +01:00
|
|
|
g_assert(nm_setting_bond_add_option(s_bond, option[0], option[1]));
|
|
|
|
|
|
|
|
|
|
if (expected_result) {
|
|
|
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
|
|
|
} else {
|
|
|
|
|
nmtst_assert_connection_unnormalizable(con,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_bond_verify(void)
|
|
|
|
|
{
|
|
|
|
|
test_verify_options(TRUE, "mode", "3", "arp_interval", "0");
|
|
|
|
|
test_verify_options(FALSE,
|
|
|
|
|
/* arp_interval not supported in balance-alb mode */
|
|
|
|
|
"mode",
|
|
|
|
|
"balance-alb",
|
|
|
|
|
"arp_interval",
|
|
|
|
|
"1",
|
|
|
|
|
"arp_ip_target",
|
|
|
|
|
"1.2.3.4");
|
|
|
|
|
test_verify_options(FALSE,
|
|
|
|
|
/* arp_ip_target requires arp_interval */
|
|
|
|
|
"mode",
|
|
|
|
|
"balance-rr",
|
|
|
|
|
"arp_ip_target",
|
|
|
|
|
"1.2.3.4");
|
|
|
|
|
test_verify_options(TRUE,
|
|
|
|
|
"mode",
|
|
|
|
|
"balance-rr",
|
|
|
|
|
"arp_interval",
|
|
|
|
|
"1",
|
|
|
|
|
"arp_ip_target",
|
|
|
|
|
"1.2.3.4");
|
|
|
|
|
test_verify_options(FALSE,
|
|
|
|
|
/* num_grat_arp, num_unsol_na cannot be different */
|
|
|
|
|
"mode",
|
|
|
|
|
"balance-rr",
|
|
|
|
|
"num_grat_arp",
|
|
|
|
|
"3",
|
|
|
|
|
"num_unsol_na",
|
|
|
|
|
"4");
|
|
|
|
|
test_verify_options(TRUE, "mode", "balance-rr", "num_grat_arp", "5", "num_unsol_na", "5");
|
|
|
|
|
test_verify_options(TRUE, "mode", "active-backup", "primary", "eth0");
|
|
|
|
|
test_verify_options(FALSE,
|
|
|
|
|
/* primary requires mode=active-backup */
|
|
|
|
|
"mode",
|
|
|
|
|
"802.3ad",
|
|
|
|
|
"primary",
|
|
|
|
|
"eth0");
|
|
|
|
|
test_verify_options(TRUE, "mode", "802.3ad", "lacp_rate", "fast");
|
|
|
|
|
test_verify_options(FALSE,
|
|
|
|
|
/* lacp_rate=fast requires mode=802.3ad */
|
|
|
|
|
"mode",
|
|
|
|
|
"balance-rr",
|
|
|
|
|
"lacp_rate",
|
|
|
|
|
"fast");
|
|
|
|
|
test_verify_options(TRUE, "mode", "802.3ad", "ad_actor_system", "ae:00:11:33:44:55");
|
2020-02-27 17:20:09 +01:00
|
|
|
test_verify_options(TRUE, "mode", "0", "miimon", "0", "updelay", "0", "downdelay", "0");
|
|
|
|
|
test_verify_options(TRUE, "mode", "0", "downdelay", "0", "updelay", "0");
|
|
|
|
|
test_verify_options(TRUE,
|
|
|
|
|
"mode",
|
|
|
|
|
"0",
|
|
|
|
|
"miimon",
|
|
|
|
|
"100",
|
2020-02-21 11:43:41 +01:00
|
|
|
"arp_ip_target",
|
2020-02-27 17:20:09 +01:00
|
|
|
"1.1.1.1",
|
2020-02-21 11:43:41 +01:00
|
|
|
"arp_interval",
|
2020-02-27 17:20:09 +01:00
|
|
|
"200");
|
2020-02-21 11:43:41 +01:00
|
|
|
test_verify_options(TRUE,
|
|
|
|
|
"mode",
|
|
|
|
|
"0",
|
|
|
|
|
"downdelay",
|
|
|
|
|
"100",
|
|
|
|
|
"arp_ip_target",
|
|
|
|
|
"1.1.1.1",
|
|
|
|
|
"arp_interval",
|
|
|
|
|
"200");
|
2017-12-03 13:37:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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}));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-03-17 17:36:06 +01:00
|
|
|
test_bond_compare_options(FALSE,
|
2017-12-03 13:37:39 +01:00
|
|
|
((const char *[]){"miimon", "1", NULL}),
|
|
|
|
|
((const char *[]){"miimon", "1", "updelay", "0", NULL}));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
test_bond_compare_options(FALSE,
|
|
|
|
|
((const char *[]){"num_grat_arp", "2", NULL}),
|
|
|
|
|
((const char *[]){"num_grat_arp", "1", NULL}));
|
2020-03-17 17:36:06 +01:00
|
|
|
test_bond_compare_options(FALSE,
|
2017-12-03 13:37:39 +01:00
|
|
|
((const char *[]){"num_grat_arp", "3", NULL}),
|
|
|
|
|
((const char *[]){"num_unsol_na", "3", NULL}));
|
2020-03-17 17:36:06 +01:00
|
|
|
test_bond_compare_options(FALSE,
|
2017-12-03 13:37:39 +01:00
|
|
|
((const char *[]){"num_grat_arp", "4", NULL}),
|
|
|
|
|
((const char *[]){"num_unsol_na", "4", "num_grat_arp", "4", NULL}));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-03-17 17:36:06 +01:00
|
|
|
test_bond_compare_options(FALSE,
|
|
|
|
|
((const char *[]){"mode", "balance-rr", "miimon", "100", NULL}),
|
|
|
|
|
((const char *[]){"mode", "balance-rr", NULL}));
|
2017-12-03 13:37:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_dcb = (NMSettingDcb *) nm_setting_dcb_new();
|
|
|
|
|
g_assert(s_dcb);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
success = nm_setting_verify(NM_SETTING(s_dcb), NULL, &error);
|
|
|
|
|
g_assert_no_error(error);
|
|
|
|
|
g_assert(success);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_dcb = (NMSettingDcb *) nm_setting_dcb_new();
|
|
|
|
|
g_assert(s_dcb);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-01-02 11:21:20 +01:00
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
2017-12-03 13:37:39 +01:00
|
|
|
TEST_FLAG(NM_SETTING_DCB_APP_FCOE_FLAGS, nm_setting_dcb_get_app_fcoe_flags, 0x332523);
|
|
|
|
|
g_test_assert_expected_messages();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-01-02 11:21:20 +01:00
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
2017-12-03 13:37:39 +01:00
|
|
|
TEST_FLAG(NM_SETTING_DCB_APP_ISCSI_FLAGS, nm_setting_dcb_get_app_iscsi_flags, 0xFF);
|
|
|
|
|
g_test_assert_expected_messages();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-01-02 11:21:20 +01:00
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
2017-12-03 13:37:39 +01:00
|
|
|
TEST_FLAG(NM_SETTING_DCB_APP_FIP_FLAGS, nm_setting_dcb_get_app_fip_flags, 0x1111);
|
|
|
|
|
g_test_assert_expected_messages();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-01-02 11:21:20 +01:00
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
2017-12-03 13:37:39 +01:00
|
|
|
TEST_FLAG(NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS,
|
|
|
|
|
nm_setting_dcb_get_priority_flow_control_flags,
|
|
|
|
|
G_MAXUINT32);
|
|
|
|
|
g_test_assert_expected_messages();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-01-02 11:21:20 +01:00
|
|
|
NMTST_EXPECT("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*");
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* Clear remaining bandwidth */
|
|
|
|
|
nm_setting_dcb_set_priority_group_bandwidth(s_dcb, other, 0);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
SET_VALID_PRIORITY_GROUP_BANDWIDTH
|
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
|
TEST_PRIORITY_VALID(strict_bandwidth, i, TRUE, GROUP, TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
s_dcb = (NMSettingDcb *) nm_setting_dcb_new();
|
|
|
|
|
g_assert(s_dcb);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-03 20:13:41 +02:00
|
|
|
static void
|
|
|
|
|
test_nm_json(void)
|
|
|
|
|
{
|
|
|
|
|
g_assert(NM_IN_SET(WITH_JANSSON, 0, 1));
|
|
|
|
|
|
|
|
|
|
#if WITH_JANSSON
|
|
|
|
|
g_assert(nm_json_vt());
|
|
|
|
|
#else
|
|
|
|
|
g_assert(!nm_json_vt());
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if WITH_JANSSON != defined(JANSSON_SONAME)
|
|
|
|
|
#error "WITH_JANSON and JANSSON_SONAME are defined inconsistently."
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: always build libnm with JSON validation
We anyway load libjansson with dlopen(), and already before it could
happen that libjansson is not available. In that case, we would not
crash, but simply proceed without json validation.
Since libnm-core no longer uses libjansson directly, but only via
"nm-glib-aux/nm-json.h", we can just always compile with that, and use
it at runtime. That means, libjansson is not a build dependency for
libnm anymore, so we don't need a compile time check.
Note that if you build without libjansson, then JANSSON_SONAME is
undefined, and loading it will still fail at runtime. So, even if
we now always build with all our code enabled, it only works if you
actually build with libjansson. Still, it's simpler to drop the
conditional build, as the only benefit is a (minimally) smaller
build.
2020-07-01 18:38:22 +02:00
|
|
|
if (!nm_json_vt()) {
|
2019-05-22 16:11:16 +02:00
|
|
|
g_test_skip("team test requires JSON validation");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
s_team = (NMSettingTeam *) nm_setting_team_new();
|
|
|
|
|
g_assert(s_team);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
g_object_set(s_team, NM_SETTING_TEAM_CONFIG, team_config, NULL);
|
2019-05-10 12:19:31 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
if (runner_tx_hash) {
|
2019-05-10 12:19:31 +02:00
|
|
|
g_assert_cmpint(runner_tx_hash->len, ==, nm_setting_team_get_num_runner_tx_hash(s_team));
|
2017-11-22 14:44:43 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2017-11-22 14:44:43 +01:00
|
|
|
g_assert(found);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
if (link_watchers) {
|
2019-05-10 12:19:31 +02:00
|
|
|
g_assert_cmpint(link_watchers->len, ==, nm_setting_team_get_num_link_watchers(s_team));
|
2017-11-22 14:44:43 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
g_assert(nm_setting_verify((NMSetting *) s_team, NULL, NULL));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_runner_roundrobin_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_config_sync("",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
-1,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_runner_broadcast_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"broadcast\"}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2017-11-22 14:44:43 +01:00
|
|
|
NM_SETTING_TEAM_RUNNER_BROADCAST,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
-1,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-05 15:24:36 +01:00
|
|
|
static void
|
|
|
|
|
test_runner_random_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"random\"}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2018-02-05 15:24:36 +01:00
|
|
|
NM_SETTING_TEAM_RUNNER_RANDOM,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
2018-02-05 15:24:36 +01:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
-1,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2018-02-05 15:24:36 +01:00
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
static void
|
|
|
|
|
test_runner_activebackup_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"activebackup\"}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2017-11-22 14:44:43 +01:00
|
|
|
NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL,
|
|
|
|
|
-1,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_runner_loadbalance_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *tx_hash = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-08-12 16:53:18 +02:00
|
|
|
tx_hash = g_ptr_array_new_with_free_func(g_free);
|
2017-11-22 14:44:43 +01:00
|
|
|
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"));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"loadbalance\"}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2017-11-22 14:44:43 +01:00
|
|
|
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
_test_team_config_sync("{\"runner\": {\"name\": \"loadbalance\", "
|
|
|
|
|
"\"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2017-11-22 14:44:43 +01:00
|
|
|
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
|
|
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
tx_hash,
|
|
|
|
|
NULL,
|
|
|
|
|
-1,
|
|
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
_test_team_config_sync(
|
|
|
|
|
"{\"runner\": {\"name\": \"loadbalance\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"], "
|
|
|
|
|
"\"tx_balancer\": {\"name\": \"basic\", \"balancing_interval\": 30}}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2017-11-22 14:44:43 +01:00
|
|
|
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
|
|
|
|
|
NULL,
|
|
|
|
|
tx_hash,
|
|
|
|
|
"basic",
|
|
|
|
|
30,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_runner_lacp_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *tx_hash = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-08-12 16:53:18 +02:00
|
|
|
tx_hash = g_ptr_array_new_with_free_func(g_free);
|
2017-11-22 14:44:43 +01:00
|
|
|
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"));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
_test_team_config_sync(
|
|
|
|
|
"{\"runner\": {\"name\": \"lacp\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2017-11-22 14:44:43 +01:00
|
|
|
NM_SETTING_TEAM_RUNNER_LACP,
|
|
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
tx_hash,
|
|
|
|
|
NULL,
|
|
|
|
|
-1,
|
|
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
_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\"}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2017-11-22 14:44:43 +01:00
|
|
|
NM_SETTING_TEAM_RUNNER_LACP,
|
|
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
tx_hash,
|
|
|
|
|
NULL,
|
|
|
|
|
-1,
|
2017-11-22 14:44:43 +01:00
|
|
|
FALSE,
|
|
|
|
|
TRUE,
|
|
|
|
|
10,
|
|
|
|
|
5,
|
|
|
|
|
"port_config",
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_watcher_ethtool_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
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\"}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL,
|
|
|
|
|
-1,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
link_watchers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_watcher_nsna_ping_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
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\"}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
NULL,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL,
|
|
|
|
|
-1,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
link_watchers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_watcher_arp_ping_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
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\"}}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
NULL,
|
|
|
|
|
-1,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
link_watchers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_multiple_watchers_sync_from_config(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-22 14:44:43 +01:00
|
|
|
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\"}]}",
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
-1,
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
TRUE,
|
|
|
|
|
FALSE,
|
|
|
|
|
-1,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
2017-11-22 14:44:43 +01:00
|
|
|
link_watchers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-12-01 10:07:04 +01:00
|
|
|
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)
|
|
|
|
|
{
|
2017-12-08 08:48:02 +01:00
|
|
|
gs_unref_object NMSettingTeamPort *s_team_port = NULL;
|
2017-12-01 10:07:04 +01:00
|
|
|
guint i, j;
|
|
|
|
|
gboolean found;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: always build libnm with JSON validation
We anyway load libjansson with dlopen(), and already before it could
happen that libjansson is not available. In that case, we would not
crash, but simply proceed without json validation.
Since libnm-core no longer uses libjansson directly, but only via
"nm-glib-aux/nm-json.h", we can just always compile with that, and use
it at runtime. That means, libjansson is not a build dependency for
libnm anymore, so we don't need a compile time check.
Note that if you build without libjansson, then JANSSON_SONAME is
undefined, and loading it will still fail at runtime. So, even if
we now always build with all our code enabled, it only works if you
actually build with libjansson. Still, it's simpler to drop the
conditional build, as the only benefit is a (minimally) smaller
build.
2020-07-01 18:38:22 +02:00
|
|
|
if (!nm_json_vt()) {
|
2019-05-22 16:11:16 +02:00
|
|
|
g_test_skip("team test requires JSON validation");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-01 10:07:04 +01:00
|
|
|
s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new();
|
|
|
|
|
g_assert(s_team_port);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-01 10:07:04 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-01 10:07:04 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-01 10:07:04 +01:00
|
|
|
g_assert(nm_setting_verify((NMSetting *) s_team_port, NULL, NULL));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_team_port_default(void)
|
|
|
|
|
{
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
_test_team_port_config_sync("", -1, 0, FALSE, -1, -1, NULL);
|
2017-12-01 10:07:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_team_port_queue_id(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_port_config_sync("{\"queue_id\": 3}", 3, 0, FALSE, -1, -1, NULL);
|
|
|
|
|
_test_team_port_config_sync("{\"queue_id\": 0}", 0, 0, FALSE, -1, -1, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_team_port_prio(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_port_config_sync("{\"prio\": 6}", -1, 6, FALSE, -1, -1, NULL);
|
|
|
|
|
_test_team_port_config_sync("{\"prio\": 0}", -1, 0, FALSE, -1, -1, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_team_port_sticky(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_port_config_sync("{\"sticky\": true}", -1, 0, TRUE, -1, -1, NULL);
|
|
|
|
|
_test_team_port_config_sync("{\"sticky\": false}", -1, 0, FALSE, -1, -1, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_team_port_lacp_prio(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_port_config_sync("{\"lacp_prio\": 9}", -1, 0, FALSE, 9, -1, NULL);
|
|
|
|
|
_test_team_port_config_sync("{\"lacp_prio\": 0}", -1, 0, FALSE, 0, -1, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_team_port_lacp_key(void)
|
|
|
|
|
{
|
|
|
|
|
_test_team_port_config_sync("{\"lacp_key\": 12}", -1, 0, FALSE, -1, 12, NULL);
|
|
|
|
|
_test_team_port_config_sync("{\"lacp_key\": 0}", -1, 0, FALSE, -1, 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_team_port_full_config(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *link_watchers = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-01 10:07:04 +01:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-01 10:07:04 +01:00
|
|
|
_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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
static void
|
|
|
|
|
_check_team_setting(NMSetting *setting)
|
|
|
|
|
{
|
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-06 12:36:41 +02:00
|
|
|
gs_unref_object NMSetting *setting2 = NULL;
|
|
|
|
|
gs_unref_object NMSetting *setting_clone = NULL;
|
2019-05-13 17:55:18 +02:00
|
|
|
gboolean is_port = NM_IS_SETTING_TEAM_PORT(setting);
|
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-06 12:36:41 +02:00
|
|
|
gs_unref_variant GVariant *variant2 = NULL;
|
|
|
|
|
gs_unref_variant GVariant *variant3 = NULL;
|
2019-05-13 17:55:18 +02:00
|
|
|
|
|
|
|
|
g_assert(NM_IS_SETTING_TEAM(setting) || is_port);
|
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-06 12:36:41 +02:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
libnm: always build libnm with JSON validation
We anyway load libjansson with dlopen(), and already before it could
happen that libjansson is not available. In that case, we would not
crash, but simply proceed without json validation.
Since libnm-core no longer uses libjansson directly, but only via
"nm-glib-aux/nm-json.h", we can just always compile with that, and use
it at runtime. That means, libjansson is not a build dependency for
libnm anymore, so we don't need a compile time check.
Note that if you build without libjansson, then JANSSON_SONAME is
undefined, and loading it will still fail at runtime. So, even if
we now always build with all our code enabled, it only works if you
actually build with libjansson. Still, it's simpler to drop the
conditional build, as the only benefit is a (minimally) smaller
build.
2020-07-01 18:38:22 +02:00
|
|
|
if (nm_json_vt())
|
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-06 12:36:41 +02:00
|
|
|
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. */
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
setting_clone = nm_setting_duplicate(setting);
|
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-06 12:36:41 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2019-06-27 09:07:16 +02:00
|
|
|
variant2 = _nm_setting_to_dbus(setting, NULL, NM_CONNECTION_SERIALIZE_ALL, NULL);
|
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-06 12:36:41 +02:00
|
|
|
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);
|
2019-05-13 17:55:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_team_setting(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_variant GVariant *variant = nmtst_variant_from_string(
|
|
|
|
|
G_VARIANT_TYPE_VARDICT,
|
2019-06-11 08:10:03 +02:00
|
|
|
"{'config': <'{\"link_watch\": {\"name\": \"ethtool\"}}'>, 'interface-name': <'nm-team'>, "
|
|
|
|
|
"'link-watchers': <[{'name': <'ethtool'>}]>}");
|
2019-05-13 17:55:18 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
g_assert(watcher1);
|
|
|
|
|
g_assert(watcher2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
g_object_set(setting, NM_SETTING_TEAM_RUNNER_SYS_PRIO, (int) 10, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
_check_team_setting(setting);
|
|
|
|
|
g_assert_cmpint(nm_setting_team_get_num_link_watchers(NM_SETTING_TEAM(setting)), ==, 1);
|
2019-05-29 15:48:22 +02:00
|
|
|
g_assert_cmpstr(
|
|
|
|
|
nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
|
|
|
==,
|
|
|
|
|
"{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"ethtool\" } }");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
nm_setting_team_remove_link_watcher(NM_SETTING_TEAM(setting), 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
_check_team_setting(setting);
|
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-06 12:36:41 +02:00
|
|
|
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 } }");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
nm_setting_team_add_link_watcher(NM_SETTING_TEAM(setting), watcher1);
|
|
|
|
|
_check_team_setting(setting);
|
2019-05-30 10:16:07 +02:00
|
|
|
g_assert_cmpstr(
|
|
|
|
|
nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
|
|
|
==,
|
|
|
|
|
"{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"nsna_ping\", "
|
|
|
|
|
"\"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, \"target_host\": \"bbb\" } }");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
nm_setting_team_add_link_watcher(NM_SETTING_TEAM(setting), watcher2);
|
|
|
|
|
_check_team_setting(setting);
|
2019-05-30 10:16:07 +02:00
|
|
|
g_assert_cmpstr(
|
|
|
|
|
nm_setting_team_get_config(NM_SETTING_TEAM(setting)),
|
|
|
|
|
==,
|
|
|
|
|
"{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": [ { \"name\": \"nsna_ping\", "
|
|
|
|
|
"\"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, \"target_host\": \"bbb\" }, { "
|
|
|
|
|
"\"name\": \"arp_ping\", \"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, "
|
|
|
|
|
"\"source_host\": \"ddd\", \"target_host\": \"ccc\" } ] }");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
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-06 12:36:41 +02:00
|
|
|
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 } }");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
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-06 12:36:41 +02:00
|
|
|
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 } }");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/team: fix handling default values and stricter validate team config
For each artifical team property we need to track whether it was
explicitly set (i.e., present in JSON/GVariant or set by the user
via NMSettingTeam/NMSettingTeamPort API).
--
As a plus, libnm is now no longer concerned with the underling default values
that teamd uses. For example, the effective default value for "notify_peers.count"
depends on the selected runner. But libnm does not need to care, it only cares
wheher the property is set in JSON or not. This also means that the default (e.g. as
interesting to `nmcli -o con show $PROFILE`) is independent from other properties
(like the runner).
Also change the default value for the GObject properties of
NMSettingTeam and NMSettingTeamPort to indicate the "unset" value.
For most properties, the default value is a special value that is
not a valid configuration itself.
For some properties the default value is itself a valid value, namely,
"runner.active", "runner.fast_rate", "port.sticky" and "port.prio".
As far as NMTeamSetting is concerned, it distinguishes between unset
value and set value (including the default value). That means,
when it parses a JSON or GVariant, it will remember whether the property
was present or not.
When using API of NMSettingTeam/NMSettingTeamPort to set a property to the
default value, it marks the property as unset. For example, setting
NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the
value will not be serialized to JSON/GVariant. For the above 4
properties (where the default value is itself a valid value) this is a
limitation of libnm API, as it does not allow to explicitly set
'"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT,
Note that changing the default value for properties of NMSetting is problematic,
because it changes behavior for how settings are parsed from keyfile/GVariant.
For team settings that's not the case, because if a JSON "config" is
present, all other properties are ignore. Also, we serialize properties
to JSON/GVariant depending on whether it's marked as present, and not
whether the value is set to the default (_nm_team_settings_property_to_dbus()).
--
While at it, sticter validate the settings. Note that if a setting is
initialized from JSON, the strict validation is not not performed. That
means, such a setting will always validate, regardless whether the values
in JSON are invalid according to libnm. Only when using the extended
properties, strict validation is turned on.
Note that libnm serializes the properties to GVariant both as JSON "config"
and extended properties. Since when parsing a setting from GVariant will
prefer the "config" (if present), in most cases also validation is
performed.
Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON
config to disk. When loading a setting from file, strict validation is
also not performed.
The stricter validation only happens if as last operation one of the
artificial properties was set, or if the setting was created from a
GVariant that has no "config" field.
--
This is a (another) change in behavior.
2019-05-31 10:48:47 +02:00
|
|
|
g_object_set(setting,
|
|
|
|
|
NM_SETTING_TEAM_CONFIG,
|
|
|
|
|
"{ \"runner\": { \"tx_hash\": [ \"eth\", \"l3\" ] } }",
|
|
|
|
|
NULL);
|
|
|
|
|
_check_team_setting(setting);
|
2019-05-13 17:55:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
static void
|
|
|
|
|
_setting_ethtool_set_feature(NMSettingEthtool *s_ethtool, const char *opt_name, NMTernary value)
|
|
|
|
|
{
|
|
|
|
|
g_assert(NM_IS_SETTING_ETHTOOL(s_ethtool));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
if (nmtst_get_rand_bool()) {
|
|
|
|
|
nm_setting_ethtool_set_feature(s_ethtool, opt_name, value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
if (value == NM_TERNARY_DEFAULT) {
|
|
|
|
|
nm_setting_option_set(NM_SETTING(s_ethtool), opt_name, NULL);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
if (nmtst_get_rand_bool())
|
|
|
|
|
nm_setting_option_set_boolean(NM_SETTING(s_ethtool), opt_name, value);
|
|
|
|
|
else
|
|
|
|
|
nm_setting_option_set(NM_SETTING(s_ethtool), opt_name, g_variant_new_boolean(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMTernary
|
|
|
|
|
_setting_ethtool_get_feature(NMSettingEthtool *s_ethtool, const char *opt_name)
|
|
|
|
|
{
|
|
|
|
|
GVariant *v;
|
|
|
|
|
gboolean b;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
switch (nmtst_get_rand_uint32() % 3) {
|
|
|
|
|
case 0:
|
|
|
|
|
return nm_setting_ethtool_get_feature(s_ethtool, opt_name);
|
|
|
|
|
case 1:
|
|
|
|
|
if (!nm_setting_option_get_boolean(NM_SETTING(s_ethtool), opt_name, &b))
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
|
|
|
|
return b;
|
|
|
|
|
default:
|
|
|
|
|
v = nm_setting_option_get(NM_SETTING(s_ethtool), opt_name);
|
|
|
|
|
if (!v || !g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN))
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
|
|
|
|
return g_variant_get_boolean(v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
static void
|
2020-05-12 17:27:45 +02:00
|
|
|
test_ethtool_features(void)
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
{
|
|
|
|
|
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;
|
2020-09-02 17:36:08 +02:00
|
|
|
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
NMSettingConnection * s_con;
|
|
|
|
|
NMSettingEthtool * s_ethtool;
|
|
|
|
|
NMSettingEthtool * s_ethtool2;
|
|
|
|
|
NMSettingEthtool * s_ethtool3;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
_setting_ethtool_set_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX, NM_TERNARY_TRUE);
|
|
|
|
|
_setting_ethtool_set_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_LRO, NM_TERNARY_FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_TRUE);
|
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_LRO),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_FALSE);
|
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_SG),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_DEFAULT);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
nmtst_connection_normalize(con);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
con2 = nm_simple_connection_new_from_dbus(variant, &error);
|
|
|
|
|
nmtst_assert_success(con2, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_RX),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_TRUE);
|
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_LRO),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_FALSE);
|
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_SG),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_DEFAULT);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
nmtst_assert_connection_equals(con, FALSE, con2, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-26 09:55:40 +02:00
|
|
|
keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
nmtst_assert_success(keyfile, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
con3 = nm_keyfile_read(keyfile,
|
keyfile: split automatically setting ID/UUID for keyfile
keyfile already supports omitting the "connection.id" and
"connection.uuid". In that case, the ID would be taken from the
keyfile's name, and the UUID was generated by md5 hashing the
full filename.
No longer do this during nm_keyfile_read(), instead let all
callers call nm_keyfile_read_ensure_*() to their liking. This is done
for two reasons:
- a minor reason is, that one day we want to expose keyfile API
as public API. That means, we also want to read keyfiles from
stdin, where there is no filename available. The implementation
which parses stdio needs to define their own way of auto-generating
ID and UUID. Note how nm_keyfile_read()'s API no longer takes a
filename as argument, which would be awkward for the stdin case.
- Currently, we only support one keyfile directory, which (configurably)
is "/etc/NetworkManager/system-connections".
In the future, we want to support multiple keyfile dirctories, like
"/var/run/NetworkManager/profiles" or "/usr/lib/NetworkManager/profiles".
Here we want that a file "foo" (which does not specify a UUID) gets the
same UUID regardless of the directory it is in. That seems better, because
then the UUID won't change as you move the file between directories.
Yes, that means, that the same UUID will be provided by multiple
files, but NetworkManager must already cope with that situation anyway.
Unfortunately, the UUID generation scheme hashes the full path. That
means, we must hash the path name of the file "foo" inside the
original "system-connections" directory.
Refactor the code so that it accounds for a difference between the
filename of the keyfile, and the profile_dir used for generating
the UUID.
2018-10-02 19:53:54 +02:00
|
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
2020-05-26 09:55:40 +02:00
|
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
nmtst_assert_success(con3, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
keyfile: split automatically setting ID/UUID for keyfile
keyfile already supports omitting the "connection.id" and
"connection.uuid". In that case, the ID would be taken from the
keyfile's name, and the UUID was generated by md5 hashing the
full filename.
No longer do this during nm_keyfile_read(), instead let all
callers call nm_keyfile_read_ensure_*() to their liking. This is done
for two reasons:
- a minor reason is, that one day we want to expose keyfile API
as public API. That means, we also want to read keyfiles from
stdin, where there is no filename available. The implementation
which parses stdio needs to define their own way of auto-generating
ID and UUID. Note how nm_keyfile_read()'s API no longer takes a
filename as argument, which would be awkward for the stdin case.
- Currently, we only support one keyfile directory, which (configurably)
is "/etc/NetworkManager/system-connections".
In the future, we want to support multiple keyfile dirctories, like
"/var/run/NetworkManager/profiles" or "/usr/lib/NetworkManager/profiles".
Here we want that a file "foo" (which does not specify a UUID) gets the
same UUID regardless of the directory it is in. That seems better, because
then the UUID won't change as you move the file between directories.
Yes, that means, that the same UUID will be provided by multiple
files, but NetworkManager must already cope with that situation anyway.
Unfortunately, the UUID generation scheme hashes the full path. That
means, we must hash the path name of the file "foo" inside the
original "system-connections" directory.
Refactor the code so that it accounds for a difference between the
filename of the keyfile, and the profile_dir used for generating
the UUID.
2018-10-02 19:53:54 +02:00
|
|
|
nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id");
|
|
|
|
|
nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
nmtst_connection_normalize(con3);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
nmtst_assert_connection_equals(con, FALSE, con3, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_RX),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_TRUE);
|
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_LRO),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_FALSE);
|
|
|
|
|
g_assert_cmpint(_setting_ethtool_get_feature(s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_SG),
|
|
|
|
|
==,
|
|
|
|
|
NM_TERNARY_DEFAULT);
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
static void
|
|
|
|
|
test_ethtool_coalesce(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_object NMConnection *con = NULL;
|
|
|
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
|
|
|
gs_unref_object NMConnection *con3 = NULL;
|
|
|
|
|
gs_unref_variant GVariant *variant = NULL;
|
|
|
|
|
gs_free_error GError *error = NULL;
|
2020-09-02 17:36:08 +02:00
|
|
|
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
2020-05-07 16:58:32 +02:00
|
|
|
NMSettingConnection * s_con;
|
|
|
|
|
NMSettingEthtool * s_ethtool;
|
|
|
|
|
NMSettingEthtool * s_ethtool2;
|
|
|
|
|
NMSettingEthtool * s_ethtool3;
|
2020-05-14 09:16:34 +02:00
|
|
|
guint32 u32;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
con = nmtst_create_minimal_connection("ethtool-coalesce",
|
|
|
|
|
NULL,
|
|
|
|
|
NM_SETTING_WIRED_SETTING_NAME,
|
|
|
|
|
&s_con);
|
|
|
|
|
s_ethtool = NM_SETTING_ETHTOOL(nm_setting_ethtool_new());
|
|
|
|
|
nm_connection_add_setting(con, NM_SETTING(s_ethtool));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
nm_setting_option_set_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
|
|
|
&u32));
|
|
|
|
|
g_assert_cmpuint(u32, ==, 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
nmtst_connection_normalize(con);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
con2 = nm_simple_connection_new_from_dbus(variant, &error);
|
|
|
|
|
nmtst_assert_success(con2, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool2),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
|
|
|
&u32));
|
|
|
|
|
g_assert_cmpuint(u32, ==, 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
nmtst_assert_connection_equals(con, FALSE, con2, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-26 09:55:40 +02:00
|
|
|
keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
2020-05-07 16:58:32 +02:00
|
|
|
nmtst_assert_success(keyfile, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
con3 = nm_keyfile_read(keyfile,
|
|
|
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
2020-05-26 09:55:40 +02:00
|
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
2020-05-07 16:58:32 +02:00
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
nmtst_assert_success(con3, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id");
|
|
|
|
|
nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
nmtst_connection_normalize(con3);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
nmtst_assert_connection_equals(con, FALSE, con3, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-07 16:58:32 +02:00
|
|
|
s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool3),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
|
|
|
&u32));
|
|
|
|
|
g_assert_cmpuint(u32, ==, 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
nm_setting_option_set(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, NULL);
|
|
|
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
|
|
|
|
NULL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
nm_setting_option_set_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES, 8);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES,
|
|
|
|
|
&u32));
|
|
|
|
|
g_assert_cmpuint(u32, ==, 8);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
nm_setting_option_clear_by_name(NM_SETTING(s_ethtool), nm_ethtool_optname_is_coalesce);
|
|
|
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL));
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES,
|
|
|
|
|
NULL));
|
|
|
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS,
|
|
|
|
|
NULL));
|
2020-05-07 16:58:32 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
static void
|
|
|
|
|
test_ethtool_ring(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_object NMConnection *con = NULL;
|
|
|
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
|
|
|
gs_unref_object NMConnection *con3 = NULL;
|
|
|
|
|
gs_unref_variant GVariant *variant = NULL;
|
|
|
|
|
gs_free_error GError *error = NULL;
|
2020-09-02 17:36:08 +02:00
|
|
|
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
2020-05-12 17:27:45 +02:00
|
|
|
NMSettingConnection * s_con;
|
|
|
|
|
NMSettingEthtool * s_ethtool;
|
|
|
|
|
NMSettingEthtool * s_ethtool2;
|
|
|
|
|
NMSettingEthtool * s_ethtool3;
|
|
|
|
|
guint32 out_value;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
con = nmtst_create_minimal_connection("ethtool-ring",
|
|
|
|
|
NULL,
|
|
|
|
|
NM_SETTING_WIRED_SETTING_NAME,
|
|
|
|
|
&s_con);
|
|
|
|
|
s_ethtool = NM_SETTING_ETHTOOL(nm_setting_ethtool_new());
|
|
|
|
|
nm_connection_add_setting(con, NM_SETTING(s_ethtool));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
nm_setting_option_set_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_RX_JUMBO, 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
|
|
|
&out_value));
|
2020-05-12 17:27:45 +02:00
|
|
|
g_assert_cmpuint(out_value, ==, 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
nmtst_connection_normalize(con);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
con2 = nm_simple_connection_new_from_dbus(variant, &error);
|
|
|
|
|
nmtst_assert_success(con2, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool2),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
|
|
|
&out_value));
|
2020-05-12 17:27:45 +02:00
|
|
|
g_assert_cmpuint(out_value, ==, 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
nmtst_assert_connection_equals(con, FALSE, con2, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-26 09:55:40 +02:00
|
|
|
keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
2020-05-12 17:27:45 +02:00
|
|
|
nmtst_assert_success(keyfile, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
con3 = nm_keyfile_read(keyfile,
|
|
|
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
2020-05-26 09:55:40 +02:00
|
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
2020-05-12 17:27:45 +02:00
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
nmtst_assert_success(con3, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id");
|
|
|
|
|
nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
nmtst_connection_normalize(con3);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
nmtst_assert_connection_equals(con, FALSE, con3, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool3),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
|
|
|
&out_value));
|
2020-05-12 17:27:45 +02:00
|
|
|
g_assert_cmpuint(out_value, ==, 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
nm_setting_option_set(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_RX_JUMBO, NULL);
|
|
|
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
|
|
|
NULL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
nm_setting_option_set_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_RX_JUMBO, 8);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
|
|
|
&out_value));
|
2020-05-12 17:27:45 +02:00
|
|
|
g_assert_cmpuint(out_value, ==, 8);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:34 +02:00
|
|
|
nm_setting_option_clear_by_name(NM_SETTING(s_ethtool), nm_ethtool_optname_is_ring);
|
|
|
|
|
g_assert_false(nm_setting_option_get_uint32(NM_SETTING(s_ethtool),
|
|
|
|
|
NM_ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
|
|
|
|
NULL));
|
|
|
|
|
g_assert_false(
|
|
|
|
|
nm_setting_option_get_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_RX, NULL));
|
|
|
|
|
g_assert_false(
|
|
|
|
|
nm_setting_option_get_uint32(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_RING_TX, NULL));
|
2020-05-12 17:27:45 +02:00
|
|
|
}
|
|
|
|
|
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
static void
|
|
|
|
|
test_sriov_vf(void)
|
|
|
|
|
{
|
|
|
|
|
NMSriovVF *vf1, *vf2;
|
|
|
|
|
GError * error = NULL;
|
|
|
|
|
char * str;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
g_assert(nm_sriov_vf_equal(vf1, vf2));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
nm_sriov_vf_unref(vf);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
con = nm_simple_connection_new();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
s_con = (NMSettingConnection *) nm_setting_connection_new();
|
|
|
|
|
nm_connection_add_setting(con, NM_SETTING(s_con));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
nm_connection_add_setting(con, nm_setting_wired_new());
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
s_sriov = (NMSettingSriov *) nm_setting_sriov_new();
|
|
|
|
|
nm_connection_add_setting(con, NM_SETTING(s_sriov));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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)));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
vf = nm_sriov_vf_new(1);
|
|
|
|
|
g_assert(vf);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
res = _nm_sriov_vf_parse_vlans(vf, string, NULL);
|
|
|
|
|
g_assert_cmpint(res, ==, exp_res);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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});
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
static void
|
|
|
|
|
test_bridge_vlans(void)
|
|
|
|
|
{
|
|
|
|
|
NMBridgeVlan *v1, *v2;
|
|
|
|
|
GError * error = NULL;
|
2019-04-15 15:14:33 +02:00
|
|
|
guint16 vid_start, vid_end;
|
2019-03-19 15:35:28 +01:00
|
|
|
char * str;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
v1 = nm_bridge_vlan_from_str("1 foobar", &error);
|
|
|
|
|
nmtst_assert_no_success(v1, error);
|
|
|
|
|
g_clear_error(&error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
v1 = nm_bridge_vlan_from_str("4095", &error);
|
|
|
|
|
nmtst_assert_no_success(v1, error);
|
|
|
|
|
g_clear_error(&error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
/* test comparison (1) */
|
|
|
|
|
v1 = nm_bridge_vlan_from_str("10 untagged", &error);
|
|
|
|
|
nmtst_assert_success(v1, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
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);
|
2019-03-19 15:35:28 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
nm_bridge_vlan_set_pvid(v1, TRUE);
|
|
|
|
|
nm_bridge_vlan_set_untagged(v1, FALSE);
|
|
|
|
|
nm_bridge_vlan_seal(v1);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
str = nm_bridge_vlan_to_str(v1, &error);
|
|
|
|
|
nmtst_assert_success(str, error);
|
|
|
|
|
g_assert_cmpstr(str, ==, "10 pvid");
|
2020-03-23 11:00:43 +01:00
|
|
|
nm_clear_g_free(&str);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
v2 = nm_bridge_vlan_from_str(" 10 pvid ", &error);
|
|
|
|
|
nmtst_assert_success(v2, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
g_assert_cmpint(nm_bridge_vlan_cmp(v1, v2), ==, 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
nm_bridge_vlan_unref(v1);
|
|
|
|
|
nm_bridge_vlan_unref(v2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
g_assert_cmpint(nm_bridge_vlan_cmp(v1, v2), <, 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
nm_bridge_vlan_unref(v1);
|
|
|
|
|
nm_bridge_vlan_unref(v2);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
static void
|
|
|
|
|
create_bridge_connection(NMConnection **con, NMSettingBridge **s_bridge)
|
|
|
|
|
{
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
|
|
|
|
|
g_assert(con);
|
|
|
|
|
g_assert(s_bridge);
|
|
|
|
|
|
|
|
|
|
*con = nmtst_create_minimal_connection("bridge", NULL, NM_SETTING_BOND_SETTING_NAME, &s_con);
|
|
|
|
|
|
|
|
|
|
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "bridge0", NULL);
|
|
|
|
|
|
|
|
|
|
*s_bridge = (NMSettingBridge *) nm_setting_bridge_new();
|
|
|
|
|
g_assert(*s_bridge);
|
|
|
|
|
|
|
|
|
|
nm_connection_add_setting(*con, NM_SETTING(*s_bridge));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define test_verify_options_bridge(exp, ...) \
|
|
|
|
|
_test_verify_options_bridge(exp, NM_MAKE_STRV(__VA_ARGS__))
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_test_verify_options_bridge(gboolean expected_result, const char *const *options)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_object NMConnection *con = NULL;
|
|
|
|
|
NMSettingBridge * s_bridge;
|
|
|
|
|
const char *const * option;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
g_assert(NM_PTRARRAY_LEN(options) % 2 == 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
create_bridge_connection(&con, &s_bridge);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
for (option = options; option[0]; option += 2) {
|
|
|
|
|
const char *option_key = option[0];
|
|
|
|
|
const char *option_val = option[1];
|
|
|
|
|
GParamSpec *pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(s_bridge), option_key);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
g_assert(pspec);
|
|
|
|
|
g_assert(option_val);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
switch (G_PARAM_SPEC_VALUE_TYPE(pspec)) {
|
|
|
|
|
case G_TYPE_UINT:
|
|
|
|
|
{
|
|
|
|
|
guint uvalue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-06-10 19:35:36 +02:00
|
|
|
uvalue = _nm_utils_ascii_str_to_uint64(option_val, 10, 0, G_MAXUINT, -1);
|
|
|
|
|
g_assert(errno == 0);
|
2020-03-23 19:29:24 +01:00
|
|
|
g_object_set(s_bridge, option_key, uvalue, NULL);
|
|
|
|
|
} break;
|
|
|
|
|
case G_TYPE_BOOLEAN:
|
|
|
|
|
{
|
2020-06-10 19:35:36 +02:00
|
|
|
int bvalue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-06-10 19:35:36 +02:00
|
|
|
bvalue = _nm_utils_ascii_str_to_bool(option_val, -1);
|
|
|
|
|
g_assert(bvalue != -1);
|
2020-03-23 19:29:24 +01:00
|
|
|
g_object_set(s_bridge, option_key, bvalue, NULL);
|
|
|
|
|
} break;
|
|
|
|
|
case G_TYPE_STRING:
|
|
|
|
|
g_object_set(s_bridge, option_key, option_val, NULL);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
if (expected_result)
|
|
|
|
|
nmtst_assert_connection_verifies_and_normalizable(con);
|
|
|
|
|
else {
|
|
|
|
|
nmtst_assert_connection_unnormalizable(con,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_bridge_verify(void)
|
|
|
|
|
{
|
|
|
|
|
/* group-address */
|
|
|
|
|
test_verify_options_bridge(FALSE, "group-address", "nonsense");
|
|
|
|
|
test_verify_options_bridge(FALSE, "group-address", "FF:FF:FF:FF:FF:FF");
|
|
|
|
|
test_verify_options_bridge(FALSE, "group-address", "01:02:03:04:05:06");
|
|
|
|
|
test_verify_options_bridge(TRUE, "group-address", "01:80:C2:00:00:00");
|
|
|
|
|
test_verify_options_bridge(FALSE, "group-address", "01:80:C2:00:00:02");
|
|
|
|
|
test_verify_options_bridge(FALSE, "group-address", "01:80:C2:00:00:03");
|
|
|
|
|
test_verify_options_bridge(TRUE, "group-address", "01:80:C2:00:00:00");
|
|
|
|
|
test_verify_options_bridge(TRUE, "group-address", "01:80:C2:00:00:0A");
|
2020-03-26 12:02:20 +01:00
|
|
|
/* vlan-protocol */
|
|
|
|
|
test_verify_options_bridge(FALSE, "vlan-protocol", "nonsense124");
|
|
|
|
|
test_verify_options_bridge(FALSE, "vlan-protocol", "802.11");
|
2020-03-26 18:38:04 +01:00
|
|
|
test_verify_options_bridge(FALSE, "vlan-protocol", "802.1Q1");
|
|
|
|
|
test_verify_options_bridge(TRUE, "vlan-protocol", "802.1Q");
|
|
|
|
|
test_verify_options_bridge(TRUE, "vlan-protocol", "802.1ad");
|
|
|
|
|
/* multicast-router */
|
|
|
|
|
test_verify_options_bridge(FALSE, "multicast-router", "nonsense");
|
|
|
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "no", "multicast-router", "auto");
|
|
|
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "no", "multicast-router", "enabled");
|
|
|
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "no", "multicast-router", "disabled");
|
|
|
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "yes", "multicast-router", "enabled");
|
|
|
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "yes", "multicast-router", "auto");
|
|
|
|
|
test_verify_options_bridge(TRUE, "multicast-snooping", "yes", "multicast-router", "disabled");
|
2020-04-10 15:03:39 +02:00
|
|
|
/* multicast-hash-max */
|
|
|
|
|
test_verify_options_bridge(TRUE, "multicast-hash-max", "1024");
|
|
|
|
|
test_verify_options_bridge(TRUE, "multicast-hash-max", "8192");
|
|
|
|
|
test_verify_options_bridge(FALSE, "multicast-hash-max", "3");
|
2020-03-23 19:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
static void
|
|
|
|
|
test_tc_config_qdisc(void)
|
|
|
|
|
{
|
|
|
|
|
NMTCQdisc *qdisc1, *qdisc2;
|
|
|
|
|
char * str;
|
|
|
|
|
GError * error = NULL;
|
2020-04-30 09:19:55 +02:00
|
|
|
GVariant * variant;
|
2017-12-03 13:42:57 +01:00
|
|
|
|
|
|
|
|
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");
|
2020-05-13 22:34:05 +02:00
|
|
|
g_assert(nm_tc_qdisc_get_handle(qdisc1) == TC_H_MAKE(0x1234u << 16, 0x0000u));
|
|
|
|
|
g_assert(nm_tc_qdisc_get_parent(qdisc1) == TC_H_MAKE(0xfff1u << 16, 0x0001u));
|
2017-12-03 13:42:57 +01:00
|
|
|
|
|
|
|
|
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);
|
2020-04-30 09:19:55 +02:00
|
|
|
|
2020-07-09 05:32:07 +02:00
|
|
|
qdisc1 = nm_utils_tc_qdisc_from_str("clsact", &error);
|
|
|
|
|
nmtst_assert_success(qdisc1, error);
|
|
|
|
|
str = nm_utils_tc_qdisc_to_str(qdisc1, &error);
|
|
|
|
|
nmtst_assert_success(str, error);
|
|
|
|
|
g_assert_cmpstr(str, ==, "clsact");
|
|
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
|
|
|
g_free(str);
|
|
|
|
|
|
2020-04-30 09:19:55 +02:00
|
|
|
#define CHECK_ATTRIBUTE(qdisc, name, vtype, type, value) \
|
|
|
|
|
variant = nm_tc_qdisc_get_attribute(qdisc, name); \
|
|
|
|
|
g_assert(variant); \
|
|
|
|
|
g_assert(g_variant_is_of_type(variant, vtype)); \
|
|
|
|
|
g_assert_cmpint(g_variant_get_##type(variant), ==, value);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-04-30 09:19:55 +02:00
|
|
|
qdisc1 = nm_utils_tc_qdisc_from_str("handle 1235 root sfq perturb 10 quantum 1480 "
|
|
|
|
|
"limit 9000 flows 1024 divisor 500 depth 12",
|
|
|
|
|
&error);
|
|
|
|
|
nmtst_assert_success(qdisc1, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-04-30 09:19:55 +02:00
|
|
|
g_assert_cmpstr(nm_tc_qdisc_get_kind(qdisc1), ==, "sfq");
|
|
|
|
|
g_assert(nm_tc_qdisc_get_handle(qdisc1) == TC_H_MAKE(0x1235u << 16, 0x0000u));
|
|
|
|
|
g_assert(nm_tc_qdisc_get_parent(qdisc1) == TC_H_ROOT);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "perturb", G_VARIANT_TYPE_INT32, int32, 10);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "quantum", G_VARIANT_TYPE_UINT32, uint32, 1480);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "limit", G_VARIANT_TYPE_UINT32, uint32, 9000);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "flows", G_VARIANT_TYPE_UINT32, uint32, 1024);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "divisor", G_VARIANT_TYPE_UINT32, uint32, 500);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "depth", G_VARIANT_TYPE_UINT32, uint32, 12);
|
|
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-08 19:11:44 +02:00
|
|
|
qdisc1 = nm_utils_tc_qdisc_from_str("handle 1235 root tbf rate 1000000 burst 5000 limit 10000",
|
|
|
|
|
&error);
|
|
|
|
|
nmtst_assert_success(qdisc1, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-08 19:11:44 +02:00
|
|
|
g_assert_cmpstr(nm_tc_qdisc_get_kind(qdisc1), ==, "tbf");
|
|
|
|
|
g_assert(nm_tc_qdisc_get_handle(qdisc1) == TC_H_MAKE(0x1235u << 16, 0x0000u));
|
|
|
|
|
g_assert(nm_tc_qdisc_get_parent(qdisc1) == TC_H_ROOT);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "rate", G_VARIANT_TYPE_UINT64, uint64, 1000000);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "burst", G_VARIANT_TYPE_UINT32, uint32, 5000);
|
|
|
|
|
CHECK_ATTRIBUTE(qdisc1, "limit", G_VARIANT_TYPE_UINT32, uint32, 10000);
|
|
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
|
|
|
|
2020-04-30 09:19:55 +02:00
|
|
|
#undef CHECK_ATTRIBUTE
|
2017-12-03 13:42:57 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-28 09:24:08 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-28 09:26:46 +01:00
|
|
|
static void
|
2020-05-11 15:36:10 +02:00
|
|
|
test_tc_config_tfilter_matchall_sdata(void)
|
2017-11-28 09:26:46 +01:00
|
|
|
{
|
|
|
|
|
NMTCAction * action1;
|
|
|
|
|
NMTCTfilter *tfilter1, *tfilter2;
|
|
|
|
|
char * str;
|
|
|
|
|
GError * error = NULL;
|
|
|
|
|
|
|
|
|
|
tfilter1 = nm_tc_tfilter_new("matchall", TC_H_MAKE(0x1234u << 16, 0x0000u), &error);
|
|
|
|
|
nmtst_assert_success(tfilter1, error);
|
|
|
|
|
|
|
|
|
|
tfilter2 = nm_tc_tfilter_new("matchall", TC_H_MAKE(0x1234u << 16, 0x0000u), &error);
|
|
|
|
|
nmtst_assert_success(tfilter2, error);
|
|
|
|
|
|
|
|
|
|
g_assert(nm_tc_tfilter_equal(tfilter1, tfilter2));
|
|
|
|
|
|
|
|
|
|
action1 = nm_tc_action_new("simple", &error);
|
|
|
|
|
nmtst_assert_success(action1, error);
|
|
|
|
|
nm_tc_action_set_attribute(action1, "sdata", g_variant_new_bytestring("Hello"));
|
|
|
|
|
nm_tc_tfilter_set_action(tfilter1, action1);
|
|
|
|
|
nm_tc_action_unref(action1);
|
|
|
|
|
|
|
|
|
|
g_assert(!nm_tc_tfilter_equal(tfilter1, tfilter2));
|
|
|
|
|
|
|
|
|
|
str = nm_utils_tc_tfilter_to_str(tfilter1, &error);
|
|
|
|
|
nmtst_assert_success(str, error);
|
|
|
|
|
g_assert_cmpstr(str, ==, "parent 1234: matchall action simple sdata Hello");
|
|
|
|
|
g_free(str);
|
|
|
|
|
|
|
|
|
|
nm_tc_tfilter_unref(tfilter2);
|
|
|
|
|
tfilter2 = nm_tc_tfilter_dup(tfilter1);
|
|
|
|
|
|
|
|
|
|
g_assert(nm_tc_tfilter_equal(tfilter1, tfilter2));
|
|
|
|
|
|
|
|
|
|
nm_tc_tfilter_unref(tfilter1);
|
|
|
|
|
tfilter1 = nm_utils_tc_tfilter_from_str("narodil sa kristus pan", &error);
|
|
|
|
|
nmtst_assert_no_success(tfilter1, error);
|
|
|
|
|
g_clear_error(&error);
|
|
|
|
|
|
|
|
|
|
str = nm_utils_tc_tfilter_to_str(tfilter2, &error);
|
|
|
|
|
nmtst_assert_success(str, error);
|
|
|
|
|
tfilter1 = nm_utils_tc_tfilter_from_str(str, &error);
|
|
|
|
|
nmtst_assert_success(tfilter1, error);
|
|
|
|
|
g_free(str);
|
|
|
|
|
|
|
|
|
|
g_assert(nm_tc_tfilter_equal(tfilter1, tfilter2));
|
|
|
|
|
|
|
|
|
|
nm_tc_tfilter_unref(tfilter1);
|
|
|
|
|
nm_tc_tfilter_unref(tfilter2);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-11 15:36:10 +02:00
|
|
|
static void
|
|
|
|
|
test_tc_config_tfilter_matchall_mirred(void)
|
|
|
|
|
{
|
|
|
|
|
NMTCAction * action;
|
|
|
|
|
NMTCTfilter * tfilter1;
|
|
|
|
|
GError * error = NULL;
|
|
|
|
|
gs_strfreev char **attr_names = NULL;
|
|
|
|
|
gs_free char * str;
|
|
|
|
|
GVariant * variant;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-11 15:36:10 +02:00
|
|
|
tfilter1 =
|
|
|
|
|
nm_utils_tc_tfilter_from_str("parent ffff: matchall action mirred ingress mirror dev eth0",
|
|
|
|
|
&error);
|
|
|
|
|
nmtst_assert_success(tfilter1, error);
|
|
|
|
|
g_assert_cmpint(nm_tc_tfilter_get_parent(tfilter1), ==, TC_H_MAKE(0xffff << 16, 0));
|
|
|
|
|
g_assert_cmpstr(nm_tc_tfilter_get_kind(tfilter1), ==, "matchall");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-11 15:36:10 +02:00
|
|
|
action = nm_tc_tfilter_get_action(tfilter1);
|
|
|
|
|
nm_assert(action);
|
|
|
|
|
g_assert_cmpstr(nm_tc_action_get_kind(action), ==, "mirred");
|
|
|
|
|
attr_names = nm_tc_action_get_attribute_names(action);
|
|
|
|
|
g_assert(attr_names);
|
|
|
|
|
g_assert_cmpint(g_strv_length(attr_names), ==, 3);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-11 15:36:10 +02:00
|
|
|
variant = nm_tc_action_get_attribute(action, "ingress");
|
|
|
|
|
g_assert(variant);
|
|
|
|
|
g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN));
|
|
|
|
|
g_assert(g_variant_get_boolean(variant));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-11 15:36:10 +02:00
|
|
|
variant = nm_tc_action_get_attribute(action, "mirror");
|
|
|
|
|
g_assert(variant);
|
|
|
|
|
g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN));
|
|
|
|
|
g_assert(g_variant_get_boolean(variant));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-11 15:36:10 +02:00
|
|
|
variant = nm_tc_action_get_attribute(action, "dev");
|
|
|
|
|
g_assert(variant);
|
|
|
|
|
g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING));
|
|
|
|
|
g_assert_cmpstr(g_variant_get_string(variant, NULL), ==, "eth0");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-11 15:36:10 +02:00
|
|
|
str = nm_utils_tc_tfilter_to_str(tfilter1, &error);
|
|
|
|
|
nmtst_assert_success(str, error);
|
|
|
|
|
g_assert_cmpstr(str, ==, "parent ffff: matchall action mirred dev eth0 ingress mirror");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-11 15:36:10 +02:00
|
|
|
nm_tc_tfilter_unref(tfilter1);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
static void
|
2018-06-21 15:56:29 +02:00
|
|
|
test_tc_config_setting_valid(void)
|
2017-12-03 13:42:57 +01:00
|
|
|
{
|
|
|
|
|
gs_unref_object NMSettingTCConfig *s_tc = NULL;
|
|
|
|
|
NMTCQdisc * qdisc1, *qdisc2;
|
|
|
|
|
GError * error = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
qdisc1 = nm_tc_qdisc_new("fq_codel", TC_H_ROOT, &error);
|
|
|
|
|
nmtst_assert_success(qdisc1, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
qdisc2 = nm_tc_qdisc_new("pfifo_fast", TC_H_MAKE(0xfff1u << 16, 0x0001u), &error);
|
|
|
|
|
nmtst_assert_success(qdisc2, error);
|
2020-05-13 22:34:05 +02:00
|
|
|
nm_tc_qdisc_set_handle(qdisc2, TC_H_MAKE(0x1234u << 16, 0x0000u));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
|
|
|
nm_tc_qdisc_unref(qdisc2);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
/* 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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
static void
|
|
|
|
|
test_tc_config_dbus(void)
|
|
|
|
|
{
|
|
|
|
|
NMConnection *connection1, *connection2;
|
|
|
|
|
NMSetting * s_tc;
|
|
|
|
|
NMTCQdisc * qdisc1, *qdisc2;
|
2017-11-28 09:26:46 +01:00
|
|
|
NMTCTfilter * tfilter1, *tfilter2;
|
|
|
|
|
NMTCAction * action;
|
2017-12-03 13:42:57 +01:00
|
|
|
GVariant * dbus, *tc_dbus, *var1, *var2;
|
|
|
|
|
GError * error = NULL;
|
|
|
|
|
gboolean success;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
connection1 =
|
|
|
|
|
nmtst_create_minimal_connection("dummy", NULL, NM_SETTING_DUMMY_SETTING_NAME, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
s_tc = nm_setting_tc_config_new();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
qdisc1 = nm_tc_qdisc_new("fq_codel", TC_H_ROOT, &error);
|
|
|
|
|
nmtst_assert_success(qdisc1, error);
|
2020-05-13 22:34:05 +02:00
|
|
|
nm_tc_qdisc_set_handle(qdisc1, TC_H_MAKE(0x1234u << 16, 0x0000u));
|
2017-12-03 13:42:57 +01:00
|
|
|
nm_setting_tc_config_add_qdisc(NM_SETTING_TC_CONFIG(s_tc), qdisc1);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
qdisc2 = nm_tc_qdisc_new("ingress", TC_H_INGRESS, &error);
|
|
|
|
|
nmtst_assert_success(qdisc2, error);
|
2020-05-13 22:34:05 +02:00
|
|
|
nm_tc_qdisc_set_handle(qdisc2, TC_H_MAKE(TC_H_INGRESS, 0u));
|
2017-12-03 13:42:57 +01:00
|
|
|
nm_setting_tc_config_add_qdisc(NM_SETTING_TC_CONFIG(s_tc), qdisc2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:46 +01:00
|
|
|
tfilter1 = nm_tc_tfilter_new("matchall", TC_H_MAKE(0x1234u << 16, 0x0000u), &error);
|
|
|
|
|
nmtst_assert_success(tfilter1, error);
|
|
|
|
|
action = nm_tc_action_new("drop", &error);
|
|
|
|
|
nmtst_assert_success(action, error);
|
|
|
|
|
nm_tc_tfilter_set_action(tfilter1, action);
|
|
|
|
|
nm_tc_action_unref(action);
|
|
|
|
|
nm_setting_tc_config_add_tfilter(NM_SETTING_TC_CONFIG(s_tc), tfilter1);
|
|
|
|
|
nm_tc_tfilter_unref(tfilter1);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:46 +01:00
|
|
|
tfilter2 = nm_tc_tfilter_new("matchall", TC_H_MAKE(TC_H_INGRESS, 0u), &error);
|
|
|
|
|
nmtst_assert_success(tfilter2, error);
|
|
|
|
|
action = nm_tc_action_new("simple", &error);
|
|
|
|
|
nmtst_assert_success(action, error);
|
|
|
|
|
nm_tc_action_set_attribute(action, "sdata", g_variant_new_bytestring("Hello"));
|
|
|
|
|
nm_tc_tfilter_set_action(tfilter2, action);
|
|
|
|
|
nm_tc_action_unref(action);
|
|
|
|
|
nm_setting_tc_config_add_tfilter(NM_SETTING_TC_CONFIG(s_tc), tfilter2);
|
|
|
|
|
nm_tc_tfilter_unref(tfilter2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
nm_connection_add_setting(connection1, s_tc);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
dbus = nm_connection_to_dbus(connection1, NM_CONNECTION_SERIALIZE_ALL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
tc_dbus = g_variant_lookup_value(dbus, "tc", G_VARIANT_TYPE_VARDICT);
|
|
|
|
|
g_assert(tc_dbus);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:46 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
g_variant_unref(tc_dbus);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
connection2 = nm_simple_connection_new();
|
|
|
|
|
success = nm_connection_replace_settings(connection2, dbus, &error);
|
|
|
|
|
nmtst_assert_success(success, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
g_assert(nm_connection_diff(connection1, connection2, NM_SETTING_COMPARE_FLAG_EXACT, NULL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
g_variant_unref(dbus);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
nm_tc_qdisc_unref(qdisc1);
|
|
|
|
|
nm_tc_qdisc_unref(qdisc2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
g_object_unref(connection1);
|
|
|
|
|
g_object_unref(connection2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2017-12-03 13:37:39 +01:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
option_names = nm_setting_wired_get_valid_s390_options(nmtst_get_rand_bool() ? NULL : s_wired);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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);
|
2019-05-30 08:33:14 +02:00
|
|
|
n_opts = nmtst_get_rand_uint32() % (n_opts + 1);
|
2019-04-24 12:03:10 +02:00
|
|
|
opt_keys[n_opts] = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
opt_vals = g_new0(char *, n_opts + 1);
|
|
|
|
|
opt_found = g_new0(bool, n_opts + 1);
|
|
|
|
|
for (i = 0; i < n_opts; i++) {
|
2019-05-30 08:33:14 +02:00
|
|
|
guint p = nmtst_get_rand_uint32() % 1000;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
if (nmtst_get_rand_bool()) {
|
|
|
|
|
gs_unref_hashtable GHashTable *hash = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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 {
|
2019-04-24 09:24:15 +02:00
|
|
|
_nm_setting_wired_clear_s390_options(s_wired);
|
2019-04-24 12:03:10 +02:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
g_assert_cmpint(nm_setting_wired_get_num_s390_options(s_wired), ==, n_opts);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
nm_setting_wired_get_s390_option(s_wired, i, &k, &v);
|
|
|
|
|
g_assert(k);
|
|
|
|
|
g_assert(v);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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]);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
static GPtrArray *
|
|
|
|
|
_rndt_wg_peers_create(void)
|
|
|
|
|
{
|
|
|
|
|
GPtrArray *wg_peers;
|
|
|
|
|
guint i, n;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
wg_peers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_wireguard_peer_unref);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-30 08:33:14 +02:00
|
|
|
n = nmtst_get_rand_uint32() % 10;
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
/* 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();
|
2019-03-01 15:52:19 +01:00
|
|
|
if (!nm_wireguard_peer_set_public_key(peer, public_key, TRUE))
|
|
|
|
|
g_assert_not_reached();
|
2019-01-03 13:38:02 +01:00
|
|
|
|
2019-03-01 15:52:19 +01:00
|
|
|
if (!nm_wireguard_peer_set_preshared_key(peer,
|
|
|
|
|
nmtst_rand_select(NULL, preshared_key),
|
|
|
|
|
TRUE))
|
|
|
|
|
g_assert_not_reached();
|
2019-01-03 13:38:02 +01:00
|
|
|
|
|
|
|
|
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,
|
2019-05-30 08:33:14 +02:00
|
|
|
nmtst_rand_select((guint32) 0, nmtst_get_rand_uint32()));
|
2019-01-03 13:38:02 +01:00
|
|
|
|
2019-03-01 15:52:19 +01:00
|
|
|
if (!nm_wireguard_peer_set_endpoint(peer, nmtst_rand_select(s_endpoint, NULL), TRUE))
|
|
|
|
|
g_assert_not_reached();
|
2019-01-03 13:38:02 +01:00
|
|
|
|
2019-05-30 08:33:14 +02:00
|
|
|
n_aip = nmtst_rand_select(0, nmtst_get_rand_uint32() % 10);
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert(wg_peers);
|
|
|
|
|
g_assert(out_str && !*out_str);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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) ?: "");
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
if (!s_endpoint && !s_preshared_key && !s_preshared_key_flags && !s_persistent_keepalive
|
|
|
|
|
&& !s_allowed_ips)
|
|
|
|
|
s_endpoint = g_strdup_printf("endpoint=\n");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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 ?: "");
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert(NM_IS_SETTING_WIREGUARD(s_wg));
|
|
|
|
|
g_assert(peers);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert_cmpint(peers->len, ==, nm_setting_wireguard_get_peers_len(s_wg));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert(a);
|
|
|
|
|
g_assert(b);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert_cmpint(nm_wireguard_peer_cmp(a, b, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS), ==, 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert(NM_IS_SETTING_WIREGUARD(s_wg));
|
|
|
|
|
g_assert(peers);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert_cmpint(peers->len, ==, nm_setting_wireguard_get_peers_len(s_wg));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
g_assert(a);
|
|
|
|
|
g_assert(b);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
2019-03-01 15:52:19 +01:00
|
|
|
if (!nm_wireguard_peer_set_preshared_key(b_clone,
|
|
|
|
|
nm_wireguard_peer_get_preshared_key(a),
|
|
|
|
|
TRUE))
|
|
|
|
|
g_assert_not_reached();
|
2019-01-03 13:38:02 +01:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2019-01-03 13:38:02 +01:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
static void
|
|
|
|
|
test_roundtrip_conversion(gconstpointer test_data)
|
|
|
|
|
{
|
|
|
|
|
const int MODE = GPOINTER_TO_INT(test_data);
|
2019-08-25 13:29:41 +02:00
|
|
|
const char *ID = nm_sprintf_bufa(100, "roundtrip-conversion-%d", MODE);
|
2019-01-03 13:24:06 +01:00
|
|
|
const char *UUID = "63376701-b61e-4318-bf7e-664a1c1eeaab";
|
|
|
|
|
const char *INTERFACE_NAME = nm_sprintf_bufa(100, "ifname%d", MODE);
|
|
|
|
|
guint32 ETH_MTU = nmtst_rand_select((guint32) 0u, nmtst_get_rand_uint32());
|
2019-01-03 13:38:02 +01:00
|
|
|
const char *WG_PRIVATE_KEY =
|
|
|
|
|
nmtst_get_rand_bool() ? "yGXGK+5bVnxSJUejH4vbpXbq+ZtaG4NB8IHRK/aVtE0=" : NULL;
|
|
|
|
|
const NMSettingSecretFlags WG_PRIVATE_KEY_FLAGS =
|
|
|
|
|
nmtst_rand_select(NM_SETTING_SECRET_FLAG_NONE,
|
|
|
|
|
NM_SETTING_SECRET_FLAG_NOT_SAVED,
|
|
|
|
|
NM_SETTING_SECRET_FLAG_AGENT_OWNED);
|
|
|
|
|
const guint WG_LISTEN_PORT = nmtst_rand_select(0u, nmtst_get_rand_uint32() % 0x10000);
|
|
|
|
|
const guint WG_FWMARK = nmtst_rand_select(0u, nmtst_get_rand_uint32());
|
2019-01-03 13:24:06 +01:00
|
|
|
gs_unref_ptrarray GPtrArray *kf_data_arr = g_ptr_array_new_with_free_func(g_free);
|
2019-01-03 13:38:02 +01:00
|
|
|
gs_unref_ptrarray GPtrArray * wg_peers = NULL;
|
2019-01-03 13:24:06 +01:00
|
|
|
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;
|
2019-01-03 13:38:02 +01:00
|
|
|
gs_free char * tmp_str = NULL;
|
2019-01-03 13:24:06 +01:00
|
|
|
guint kf_data_idx;
|
|
|
|
|
NMSettingConnection * s_con = NULL;
|
|
|
|
|
NMSettingWired * s_eth = NULL;
|
2019-01-03 13:38:02 +01:00
|
|
|
NMSettingWireGuard * s_wg = NULL;
|
2019-03-14 12:04:21 +01:00
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
NMSettingIPConfig *s_6;
|
|
|
|
|
NMSettingIPConfig *s_4;
|
|
|
|
|
};
|
|
|
|
|
NMSettingIPConfig *s_x[2];
|
|
|
|
|
} s_ip;
|
|
|
|
|
int is_ipv4;
|
2019-01-03 13:38:02 +01:00
|
|
|
guint i;
|
2019-03-14 12:04:21 +01:00
|
|
|
gboolean success;
|
2019-04-24 12:03:10 +02:00
|
|
|
gs_free char *s390_keyfile_entries = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
s_eth = NM_SETTING_WIRED(nm_connection_get_setting(con, NM_TYPE_SETTING_WIRED));
|
|
|
|
|
g_assert(NM_IS_SETTING_WIRED(s_eth));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
g_object_set(s_eth, NM_SETTING_WIRED_MTU, ETH_MTU, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
_rndt_wired_add_s390_options(s_eth, &s390_keyfile_entries);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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"
|
2019-04-24 12:03:10 +02:00
|
|
|
"%s" /* [ethernet-s390-options] */
|
2019-01-03 13:24:06 +01:00
|
|
|
"[ipv4]\n"
|
|
|
|
|
"dns-search=\n"
|
|
|
|
|
"method=auto\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"[ipv6]\n"
|
|
|
|
|
"addr-gen-mode=stable-privacy\n"
|
|
|
|
|
"dns-search=\n"
|
|
|
|
|
"method=auto\n"
|
2019-08-25 13:29:41 +02:00
|
|
|
"\n"
|
|
|
|
|
"[proxy]\n"
|
2019-01-03 13:24:06 +01:00
|
|
|
"",
|
|
|
|
|
ID,
|
|
|
|
|
UUID,
|
|
|
|
|
INTERFACE_NAME,
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
(ETH_MTU != 0) ? nm_sprintf_bufa(100, "mtu=%u\n", ETH_MTU) : "",
|
2019-04-24 12:03:10 +02:00
|
|
|
s390_keyfile_entries));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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"
|
2019-04-24 12:03:10 +02:00
|
|
|
"%s" /* [ethernet-s390-options] */
|
2019-01-03 13:24:06 +01:00
|
|
|
"[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,
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
(ETH_MTU != 0) ? nm_sprintf_bufa(100, "mtu=%d\n", (int) ETH_MTU) : "",
|
2019-04-24 12:03:10 +02:00
|
|
|
s390_keyfile_entries));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
s_wg = NM_SETTING_WIREGUARD(nm_connection_get_setting(con, NM_TYPE_SETTING_WIREGUARD));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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"
|
2019-08-25 13:29:41 +02:00
|
|
|
"[wireguard]\n"
|
|
|
|
|
"\n"
|
2019-01-03 13:38:02 +01:00
|
|
|
"[ipv4]\n"
|
|
|
|
|
"dns-search=\n"
|
|
|
|
|
"method=disabled\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"[ipv6]\n"
|
|
|
|
|
"addr-gen-mode=stable-privacy\n"
|
|
|
|
|
"dns-search=\n"
|
|
|
|
|
"method=ignore\n"
|
2019-08-25 13:29:41 +02:00
|
|
|
"\n"
|
|
|
|
|
"[proxy]\n"
|
2019-01-03 13:38:02 +01:00
|
|
|
"",
|
|
|
|
|
ID,
|
|
|
|
|
UUID,
|
|
|
|
|
INTERFACE_NAME));
|
|
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
wg_peers = _rndt_wg_peers_create();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
for (i = 0; i < wg_peers->len; i++)
|
|
|
|
|
nm_setting_wireguard_append_peer(s_wg, wg_peers->pdata[i]);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
nm_clear_g_free(&tmp_str);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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"
|
2019-08-25 13:29:41 +02:00
|
|
|
"\n"
|
|
|
|
|
"[wireguard]\n"
|
2019-01-03 13:38:02 +01:00
|
|
|
"%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"
|
2019-08-25 13:29:41 +02:00
|
|
|
"\n"
|
|
|
|
|
"[proxy]\n"
|
2019-01-03 13:38:02 +01:00
|
|
|
"",
|
|
|
|
|
ID,
|
|
|
|
|
UUID,
|
|
|
|
|
INTERFACE_NAME,
|
|
|
|
|
((WG_FWMARK != 0) ? nm_sprintf_bufa(100, "fwmark=%u\n", WG_FWMARK) : ""),
|
|
|
|
|
((WG_LISTEN_PORT != 0) ? nm_sprintf_bufa(100, "listen-port=%u\n", WG_LISTEN_PORT)
|
|
|
|
|
: ""),
|
|
|
|
|
((WG_PRIVATE_KEY_FLAGS != NM_SETTING_SECRET_FLAG_NONE)
|
|
|
|
|
? nm_sprintf_bufa(100, "private-key-flags=%u\n", (guint) WG_PRIVATE_KEY_FLAGS)
|
|
|
|
|
: ""),
|
|
|
|
|
((WG_PRIVATE_KEY && WG_PRIVATE_KEY_FLAGS == NM_SETTING_SECRET_FLAG_NONE)
|
|
|
|
|
? nm_sprintf_bufa(100, "private-key=%s\n", WG_PRIVATE_KEY)
|
|
|
|
|
: ""),
|
|
|
|
|
_rndt_wg_peers_to_keyfile(wg_peers, TRUE, &tmp_str)));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
_rndt_wg_peers_assert_equal(s_wg, wg_peers, TRUE, TRUE, FALSE);
|
|
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
s_eth = NM_SETTING_WIRED(nm_connection_get_setting(con, NM_TYPE_SETTING_WIRED));
|
|
|
|
|
g_assert(NM_IS_SETTING_WIRED(s_eth));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
g_object_set(s_eth, NM_SETTING_WIRED_MTU, ETH_MTU, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
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];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
nm_auto_unref_ip_routing_rule NMIPRoutingRule *rr = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
success = nm_ip_routing_rule_validate(rr, &error);
|
|
|
|
|
nmtst_assert_success(success, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
nm_setting_ip_config_add_routing_rule(s_ip.s_x[is_ipv4], rr);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2019-03-14 12:04:21 +01:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
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"
|
2019-08-25 13:29:41 +02:00
|
|
|
"\n"
|
|
|
|
|
"[proxy]\n"
|
2019-03-14 12:04:21 +01:00
|
|
|
"",
|
|
|
|
|
ID,
|
|
|
|
|
UUID,
|
|
|
|
|
INTERFACE_NAME,
|
|
|
|
|
(ETH_MTU != 0) ? nm_sprintf_bufa(100, "mtu=%u\n", ETH_MTU) : ""));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
default:
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
/* 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. */
|
|
|
|
|
{
|
2020-09-02 17:36:08 +02:00
|
|
|
nm_auto_unref_keyfile GKeyFile *kf = NULL;
|
2019-01-03 13:24:06 +01:00
|
|
|
|
2020-05-26 09:55:40 +02:00
|
|
|
kf = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
2019-01-03 13:24:06 +01:00
|
|
|
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;
|
2019-01-03 13:38:02 +01:00
|
|
|
NMSettingWireGuard * s_wg2 = NULL;
|
2019-01-03 13:24:06 +01:00
|
|
|
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) {
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
/* 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. */
|
2019-01-03 13:24:06 +01:00
|
|
|
g_assert_cmpint(nm_setting_wired_get_mtu(s_eth2), ==, 0);
|
|
|
|
|
g_object_set(s_eth2, NM_SETTING_WIRED_MTU, ETH_MTU, NULL);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
g_assert_cmpint(nm_setting_wired_get_mtu(s_eth), ==, ETH_MTU);
|
|
|
|
|
g_assert_cmpint(nm_setting_wired_get_mtu(s_eth2), ==, ETH_MTU);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
g_assert_cmpint(nm_setting_wired_get_num_s390_options(s_eth2),
|
|
|
|
|
==,
|
|
|
|
|
nm_setting_wired_get_num_s390_options(s_eth));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
case 1:
|
|
|
|
|
s_wg2 =
|
|
|
|
|
NM_SETTING_WIREGUARD(nm_connection_get_setting(con2, NM_TYPE_SETTING_WIREGUARD));
|
|
|
|
|
g_assert(NM_IS_SETTING_WIREGUARD(s_wg2));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
case 2:
|
|
|
|
|
s_wg2 =
|
|
|
|
|
NM_SETTING_WIREGUARD(nm_connection_get_setting(con2, NM_TYPE_SETTING_WIREGUARD));
|
|
|
|
|
g_assert(NM_IS_SETTING_WIREGUARD(s_wg2));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
/* 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);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
_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;
|
2019-01-03 13:24:06 +01:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
nmtst_assert_connection_equals(con, nmtst_get_rand_bool(), con2, nmtst_get_rand_bool());
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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;
|
2019-01-03 13:38:02 +01:00
|
|
|
NMSettingWireGuard * s_wg2 = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:24:06 +01:00
|
|
|
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());
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-08 16:16:03 +01:00
|
|
|
{
|
2020-09-02 17:36:08 +02:00
|
|
|
nm_auto_unref_keyfile GKeyFile *kf = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-26 09:55:40 +02:00
|
|
|
kf = nm_keyfile_write(con2, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
2019-01-08 16:16:03 +01:00
|
|
|
nmtst_assert_success(kf, error);
|
|
|
|
|
nmtst_keyfile_assert_data(kf, kf_data_arr->pdata[0], -1);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2019-01-08 16:16:03 +01:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
switch (MODE) {
|
|
|
|
|
case 2:
|
|
|
|
|
if (flag == NM_CONNECTION_SERIALIZE_ALL) {
|
|
|
|
|
s_wg2 = NM_SETTING_WIREGUARD(
|
|
|
|
|
nm_connection_get_setting(con2, NM_TYPE_SETTING_WIREGUARD));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-03 13:38:02 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2019-01-03 13:24:06 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
rr = nm_ip_routing_rule_from_string(str,
|
|
|
|
|
NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE,
|
|
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
nmtst_assert_success(rr, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
addr_family = nm_ip_routing_rule_get_addr_family(rr);
|
|
|
|
|
g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
switch (i) {
|
|
|
|
|
case 0:
|
|
|
|
|
rr2 = nm_ip_routing_rule_ref(rr);
|
|
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
g_assert_cmpstr(str, ==, str1);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
rr2 = nm_ip_routing_rule_from_dbus(variant1, TRUE, &error);
|
|
|
|
|
nmtst_assert_success(rr, error);
|
|
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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])
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
#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];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
_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",
|
libnm: use nm_utils_escaped_tokens_*() for parsing NMIPRoutingRule
Replace nm_utils_str_simpletokens_extract_next() by
nm_utils_escaped_tokens_split().
nm_utils_escaped_tokens_split() should become our first choice for
parsing and tokenizing.
Note that both nm_utils_str_simpletokens_extract_next() and
nm_utils_escaped_tokens_split() need to strdup the string once,
and tokenizing takes O(n). So, they are roughtly the same performance
wise. The only difference is, that as we iterate through the tokens,
we might abort early on error with nm_utils_str_simpletokens_extract_next()
and not parse the entire string. But that is a small benefit, since we
anyway always strdup() the string (being O(n) already).
Note that to-string will no longer escape ',' and ';'. This is a change
in behavior, of unreleased API. Also note, that escaping these is no
longer necessary, because nmcli soon will also use nm_utils_escaped_tokens_*().
Another change in behavior is that nm_utils_str_simpletokens_extract_next()
treated invalid escape sequences (backslashes followed by an arbitrary
character), buy stripping the backslash. nm_utils_escaped_tokens_*()
leaves such backslashes as is, and only honors them if they are followed
by a whitespace (the delimiter) or another backslash. The disadvantage
of the new approach is that backslashes are treated differently
depending on the following character. The benefit is, that most
backslashes can now be written verbatim, not requiring them to escape
them with a double-backslash.
Yes, there is a problem with these nested escape schemes:
- the caller may already need to escape backslash in shell.
- then nmcli will use backslash escaping to split the rules at ','.
- then nm_ip_routing_rule_from_string() will honor backslash escaping
for spaces.
- then iifname and oifname use backslash escaping for nm_utils_buf_utf8safe_escape()
to express non-UTF-8 characters (because interface names are not
necessarily UTF-8).
This is only redeamed because escaping is really only necessary for very
unusual cases, if you want to embed a backslash, a space, a comma, or a
non-UTF-8 character. But if you have to, now you will be able to express
that.
The other upside of these layers of escaping is that they become all
indendent from each other:
- shell can accept quoted/escaped arguments and will unescape them.
- nmcli can do the tokenizing for ',' (and escape the content
unconditionally when converting to string).
- nm_ip_routing_rule_from_string() can do its tokenizing without
special consideration of utf8safe escaping.
- NMIPRoutingRule takes iifname/oifname as-is and is not concerned
about nm_utils_buf_utf8safe_escape(). However, before configuring
the rule in kernel, this utf8safe escape will be unescaped to get
the interface name (which is non-UTF8 binary).
(cherry picked from commit b6d0be2d3b4caa30685abf46ae6a355cada8bf4e)
2019-04-12 12:38:11 +02:00
|
|
|
"priority 5 from :: table 0x19 dev aab oif er");
|
2019-03-13 09:18:49 +01:00
|
|
|
_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");
|
2019-08-03 09:04:33 +02:00
|
|
|
_rr_from_str("priority 5 not to 0.0.0.0 dport 10-133 table 6",
|
|
|
|
|
"not priority 5 to 0.0.0.0 dport 10-133 table 6",
|
|
|
|
|
"not priority 5 not to 0.0.0.0 dport 10-133 table 6",
|
2019-03-13 09:18:49 +01:00
|
|
|
"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");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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);
|
2019-03-31 11:46:00 +02:00
|
|
|
nm_clear_pointer(&rr1, nm_ip_routing_rule_unref);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: use nm_utils_escaped_tokens_*() for parsing NMIPRoutingRule
Replace nm_utils_str_simpletokens_extract_next() by
nm_utils_escaped_tokens_split().
nm_utils_escaped_tokens_split() should become our first choice for
parsing and tokenizing.
Note that both nm_utils_str_simpletokens_extract_next() and
nm_utils_escaped_tokens_split() need to strdup the string once,
and tokenizing takes O(n). So, they are roughtly the same performance
wise. The only difference is, that as we iterate through the tokens,
we might abort early on error with nm_utils_str_simpletokens_extract_next()
and not parse the entire string. But that is a small benefit, since we
anyway always strdup() the string (being O(n) already).
Note that to-string will no longer escape ',' and ';'. This is a change
in behavior, of unreleased API. Also note, that escaping these is no
longer necessary, because nmcli soon will also use nm_utils_escaped_tokens_*().
Another change in behavior is that nm_utils_str_simpletokens_extract_next()
treated invalid escape sequences (backslashes followed by an arbitrary
character), buy stripping the backslash. nm_utils_escaped_tokens_*()
leaves such backslashes as is, and only honors them if they are followed
by a whitespace (the delimiter) or another backslash. The disadvantage
of the new approach is that backslashes are treated differently
depending on the following character. The benefit is, that most
backslashes can now be written verbatim, not requiring them to escape
them with a double-backslash.
Yes, there is a problem with these nested escape schemes:
- the caller may already need to escape backslash in shell.
- then nmcli will use backslash escaping to split the rules at ','.
- then nm_ip_routing_rule_from_string() will honor backslash escaping
for spaces.
- then iifname and oifname use backslash escaping for nm_utils_buf_utf8safe_escape()
to express non-UTF-8 characters (because interface names are not
necessarily UTF-8).
This is only redeamed because escaping is really only necessary for very
unusual cases, if you want to embed a backslash, a space, a comma, or a
non-UTF-8 character. But if you have to, now you will be able to express
that.
The other upside of these layers of escaping is that they become all
indendent from each other:
- shell can accept quoted/escaped arguments and will unescape them.
- nmcli can do the tokenizing for ',' (and escape the content
unconditionally when converting to string).
- nm_ip_routing_rule_from_string() can do its tokenizing without
special consideration of utf8safe escaping.
- NMIPRoutingRule takes iifname/oifname as-is and is not concerned
about nm_utils_buf_utf8safe_escape(). However, before configuring
the rule in kernel, this utf8safe escape will be unescaped to get
the interface name (which is non-UTF8 binary).
(cherry picked from commit b6d0be2d3b4caa30685abf46ae6a355cada8bf4e)
2019-04-12 12:38:11 +02:00
|
|
|
rr1 = _rr_from_str_get("priority 5 from :: iif a\\\\303\\\\261,x;b table 254",
|
2019-03-13 09:18:49 +01:00
|
|
|
"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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-05-01 10:49:16 +02:00
|
|
|
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
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-01 10:49:16 +02:00
|
|
|
#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))))
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-01 10:49:16 +02:00
|
|
|
_parse_tc_handle_inval("");
|
|
|
|
|
_parse_tc_handle_inval(" ");
|
|
|
|
|
_parse_tc_handle_inval(" \n");
|
|
|
|
|
_parse_tc_handle_valid("1", 1, 0);
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
_parse_tc_handle_valid(" 1 ", 1, 0);
|
2019-05-01 10:49:16 +02:00
|
|
|
_parse_tc_handle_valid("1:", 1, 0);
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
_parse_tc_handle_valid("1: ", 1, 0);
|
2019-05-01 10:49:16 +02:00
|
|
|
_parse_tc_handle_valid("1:0", 1, 0);
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
_parse_tc_handle_valid("1 :0", 1, 0);
|
|
|
|
|
_parse_tc_handle_valid("1 \t\n\f\r:0", 1, 0);
|
2019-05-01 10:49:16 +02:00
|
|
|
_parse_tc_handle_inval("1 \t\n\f\r\v:0");
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
_parse_tc_handle_valid(" 1 : 0 ", 1, 0);
|
|
|
|
|
_parse_tc_handle_inval(" \t\v\n1: 0");
|
2019-05-01 10:49:16 +02:00
|
|
|
_parse_tc_handle_valid("1:2", 1, 2);
|
|
|
|
|
_parse_tc_handle_valid("01:02", 1, 2);
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
_parse_tc_handle_inval("0x01:0x02");
|
2019-05-01 10:49:16 +02:00
|
|
|
_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);
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
_parse_tc_handle_inval("0xFFFF");
|
2019-05-01 10:49:16 +02:00
|
|
|
_parse_tc_handle_inval("10000");
|
|
|
|
|
_parse_tc_handle_valid("\t\n\f\r FFFF", 0xFFFF, 0);
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
_parse_tc_handle_inval("\t\n\f\r \vFFFF");
|
2019-05-01 10:49:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-08-25 14:29:13 +02:00
|
|
|
static void
|
|
|
|
|
test_empty_setting(void)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_object NMConnection *con = NULL;
|
|
|
|
|
gs_unref_object NMConnection *con2 = NULL;
|
|
|
|
|
NMSettingBluetooth * s_bt;
|
|
|
|
|
NMSettingGsm * s_gsm;
|
2020-09-02 17:36:08 +02:00
|
|
|
nm_auto_unref_keyfile GKeyFile *kf = NULL;
|
2019-08-25 14:29:13 +02:00
|
|
|
gs_free_error GError *error = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 14:29:13 +02:00
|
|
|
con = nmtst_create_minimal_connection("bt-empty-gsm",
|
|
|
|
|
"dca3192a-f2dc-48eb-b806-d0ff788f122c",
|
|
|
|
|
NM_SETTING_BLUETOOTH_SETTING_NAME,
|
|
|
|
|
NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 14:29:13 +02:00
|
|
|
s_bt = _nm_connection_get_setting(con, NM_TYPE_SETTING_BLUETOOTH);
|
|
|
|
|
g_object_set(s_bt,
|
|
|
|
|
NM_SETTING_BLUETOOTH_TYPE,
|
|
|
|
|
"dun",
|
|
|
|
|
NM_SETTING_BLUETOOTH_BDADDR,
|
|
|
|
|
"aa:bb:cc:dd:ee:ff",
|
|
|
|
|
NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 14:29:13 +02:00
|
|
|
s_gsm = NM_SETTING_GSM(nm_setting_gsm_new());
|
|
|
|
|
nm_connection_add_setting(con, NM_SETTING(s_gsm));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 14:29:13 +02:00
|
|
|
nmtst_connection_normalize(con);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 14:29:13 +02:00
|
|
|
nmtst_assert_connection_verifies_without_normalization(con);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-26 09:55:40 +02:00
|
|
|
kf = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
2019-08-25 14:29:13 +02:00
|
|
|
nmtst_assert_success(kf, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 13:29:41 +02:00
|
|
|
g_assert(g_key_file_has_group(kf, "gsm"));
|
|
|
|
|
g_assert_cmpint(nmtst_keyfile_get_num_keys(kf, "gsm"), ==, 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 14:29:13 +02:00
|
|
|
con2 = nm_keyfile_read(kf,
|
|
|
|
|
"/ignored/current/working/directory/for/loading/relative/paths",
|
2020-05-26 09:55:40 +02:00
|
|
|
NM_KEYFILE_HANDLER_FLAGS_NONE,
|
2019-08-25 14:29:13 +02:00
|
|
|
NULL,
|
2020-09-28 16:03:33 +02:00
|
|
|
NULL,
|
2019-08-25 14:29:13 +02:00
|
|
|
&error);
|
|
|
|
|
nmtst_assert_success(con2, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 13:29:41 +02:00
|
|
|
g_assert(nm_connection_get_setting(con2, NM_TYPE_SETTING_GSM));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 13:29:41 +02:00
|
|
|
nmtst_assert_connection_verifies_without_normalization(con2);
|
2019-08-25 14:29:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
static guint
|
|
|
|
|
_PROP_IDX_PACK(NMMetaSettingType meta_type, guint idx)
|
|
|
|
|
{
|
|
|
|
|
return (((guint) meta_type) & 0xFFu) | (idx << 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
_PROP_IDX_OWNER(GHashTable *h_property_types, const NMSettInfoPropertType *property_type)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoSetting *sett_info_settings = nmtst_sett_info_settings();
|
|
|
|
|
const NMSettInfoSetting *sis;
|
|
|
|
|
const NMMetaSettingInfo *msi;
|
|
|
|
|
GArray * arr;
|
|
|
|
|
guint idx;
|
|
|
|
|
NMMetaSettingType meta_type;
|
|
|
|
|
guint prop_idx;
|
|
|
|
|
char sbuf[300];
|
|
|
|
|
|
|
|
|
|
g_assert(h_property_types);
|
|
|
|
|
g_assert(property_type);
|
|
|
|
|
|
|
|
|
|
arr = g_hash_table_lookup(h_property_types, property_type);
|
|
|
|
|
|
|
|
|
|
g_assert(arr);
|
|
|
|
|
g_assert(arr->len > 0);
|
|
|
|
|
|
|
|
|
|
idx = g_array_index(arr, guint, 0);
|
|
|
|
|
|
|
|
|
|
meta_type = (idx & 0xFFu);
|
|
|
|
|
prop_idx = idx >> 8;
|
|
|
|
|
|
|
|
|
|
g_assert(meta_type < _NM_META_SETTING_TYPE_NUM);
|
|
|
|
|
|
|
|
|
|
sis = &sett_info_settings[meta_type];
|
|
|
|
|
msi = &nm_meta_setting_infos[meta_type];
|
|
|
|
|
|
|
|
|
|
g_assert(prop_idx < sis->property_infos_len);
|
|
|
|
|
|
|
|
|
|
nm_sprintf_buf(sbuf, "%s.%s", msi->setting_name, sis->property_infos[prop_idx].name);
|
|
|
|
|
|
|
|
|
|
return g_intern_string(sbuf);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
static void
|
|
|
|
|
test_setting_metadata(void)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoSetting *sett_info_settings = nmtst_sett_info_settings();
|
|
|
|
|
NMMetaSettingType meta_type;
|
2019-09-22 10:57:57 +02:00
|
|
|
gs_unref_hashtable GHashTable *h_property_types = NULL;
|
2019-09-21 20:35:18 +02:00
|
|
|
|
|
|
|
|
G_STATIC_ASSERT(_NM_META_SETTING_TYPE_NUM == NM_META_SETTING_TYPE_UNKNOWN);
|
|
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
h_property_types =
|
|
|
|
|
g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) g_array_unref);
|
|
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
for (meta_type = 0; meta_type < _NM_META_SETTING_TYPE_NUM; meta_type++) {
|
|
|
|
|
const NMMetaSettingInfo *msi = &nm_meta_setting_infos[meta_type];
|
|
|
|
|
nm_auto_unref_gtypeclass NMSettingClass *klass = NULL;
|
|
|
|
|
GType gtype;
|
|
|
|
|
|
|
|
|
|
g_assert(msi->setting_name);
|
|
|
|
|
g_assert(msi->get_setting_gtype);
|
|
|
|
|
g_assert(msi->meta_type == meta_type);
|
|
|
|
|
g_assert(msi->setting_priority >= NM_SETTING_PRIORITY_CONNECTION);
|
|
|
|
|
g_assert(msi->setting_priority <= NM_SETTING_PRIORITY_USER);
|
|
|
|
|
|
|
|
|
|
if (meta_type > 0)
|
|
|
|
|
g_assert_cmpint(
|
|
|
|
|
strcmp(nm_meta_setting_infos[meta_type - 1].setting_name, msi->setting_name),
|
|
|
|
|
<,
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
gtype = msi->get_setting_gtype();
|
|
|
|
|
|
|
|
|
|
g_assert(g_type_is_a(gtype, NM_TYPE_SETTING));
|
|
|
|
|
g_assert(gtype != NM_TYPE_SETTING);
|
|
|
|
|
|
|
|
|
|
klass = g_type_class_ref(gtype);
|
|
|
|
|
g_assert(klass);
|
|
|
|
|
g_assert(NM_IS_SETTING_CLASS(klass));
|
2019-09-22 10:57:57 +02:00
|
|
|
|
|
|
|
|
g_assert(msi == klass->setting_info);
|
2019-09-21 20:35:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_assert(sett_info_settings);
|
|
|
|
|
|
|
|
|
|
for (meta_type = 0; meta_type < _NM_META_SETTING_TYPE_NUM; meta_type++) {
|
|
|
|
|
const NMSettInfoSetting *sis = &sett_info_settings[meta_type];
|
|
|
|
|
const NMMetaSettingInfo *msi = &nm_meta_setting_infos[meta_type];
|
|
|
|
|
gs_unref_hashtable GHashTable *h_properties = NULL;
|
|
|
|
|
GType gtype;
|
|
|
|
|
gs_unref_object NMSetting *setting = NULL;
|
|
|
|
|
guint prop_idx;
|
|
|
|
|
gs_free GParamSpec **property_specs = NULL;
|
|
|
|
|
guint n_property_specs;
|
|
|
|
|
|
|
|
|
|
g_assert(sis);
|
|
|
|
|
|
|
|
|
|
g_assert(NM_IS_SETTING_CLASS(sis->setting_class));
|
|
|
|
|
|
|
|
|
|
gtype = msi->get_setting_gtype();
|
|
|
|
|
|
|
|
|
|
g_assert(G_TYPE_FROM_CLASS(sis->setting_class) == gtype);
|
|
|
|
|
|
|
|
|
|
setting = g_object_new(gtype, NULL);
|
|
|
|
|
|
|
|
|
|
g_assert(NM_IS_SETTING(setting));
|
|
|
|
|
|
|
|
|
|
g_assert_cmpint(sis->property_infos_len, >, 0);
|
|
|
|
|
g_assert(sis->property_infos);
|
|
|
|
|
|
|
|
|
|
h_properties = g_hash_table_new(nm_str_hash, g_str_equal);
|
|
|
|
|
|
|
|
|
|
for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) {
|
|
|
|
|
const NMSettInfoProperty *sip = &sis->property_infos[prop_idx];
|
2019-09-22 10:57:57 +02:00
|
|
|
GArray * property_types_data;
|
|
|
|
|
guint prop_idx_val;
|
2019-09-21 20:35:18 +02:00
|
|
|
|
|
|
|
|
g_assert(sip->name);
|
|
|
|
|
|
|
|
|
|
if (prop_idx > 0)
|
|
|
|
|
g_assert_cmpint(strcmp(sis->property_infos[prop_idx - 1].name, sip->name), <, 0);
|
|
|
|
|
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
g_assert(sip->property_type);
|
|
|
|
|
g_assert(sip->property_type->dbus_type);
|
|
|
|
|
g_assert(g_variant_type_string_is_valid((const char *) sip->property_type->dbus_type));
|
|
|
|
|
|
|
|
|
|
g_assert(!sip->property_type->to_dbus_fcn || !sip->property_type->gprop_to_dbus_fcn);
|
|
|
|
|
g_assert(!sip->property_type->from_dbus_fcn
|
|
|
|
|
|| !sip->property_type->gprop_from_dbus_fcn);
|
2019-09-21 20:35:18 +02:00
|
|
|
|
|
|
|
|
if (!g_hash_table_insert(h_properties, (char *) sip->name, sip->param_spec))
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
property_types_data = g_hash_table_lookup(h_property_types, sip->property_type);
|
|
|
|
|
if (!property_types_data) {
|
|
|
|
|
property_types_data = g_array_new(FALSE, FALSE, sizeof(guint));
|
|
|
|
|
if (!g_hash_table_insert(h_property_types,
|
|
|
|
|
(gpointer) sip->property_type,
|
|
|
|
|
property_types_data))
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
prop_idx_val = _PROP_IDX_PACK(meta_type, prop_idx);
|
|
|
|
|
g_array_append_val(property_types_data, prop_idx_val);
|
|
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
if (sip->param_spec) {
|
|
|
|
|
nm_auto_unset_gvalue GValue val = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
g_assert_cmpstr(sip->name, ==, sip->param_spec->name);
|
|
|
|
|
|
|
|
|
|
g_value_init(&val, sip->param_spec->value_type);
|
|
|
|
|
g_object_get_property(G_OBJECT(setting), sip->name, &val);
|
|
|
|
|
|
|
|
|
|
if (sip->param_spec->value_type == G_TYPE_STRING) {
|
|
|
|
|
const char *default_value;
|
|
|
|
|
|
|
|
|
|
default_value = ((const GParamSpecString *) sip->param_spec)->default_value;
|
|
|
|
|
if (default_value) {
|
|
|
|
|
/* having a string property with a default != NULL is really ugly. They
|
|
|
|
|
* should be best avoided... */
|
|
|
|
|
if (meta_type == NM_META_SETTING_TYPE_DCB
|
|
|
|
|
&& nm_streq(sip->name, NM_SETTING_DCB_APP_FCOE_MODE)) {
|
|
|
|
|
/* Whitelist the properties that have a non-NULL default value. */
|
|
|
|
|
g_assert_cmpstr(default_value, ==, NM_SETTING_DCB_FCOE_MODE_FABRIC);
|
|
|
|
|
} else
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
if (nm_streq(sip->name, NM_SETTING_NAME))
|
|
|
|
|
g_assert_cmpstr(g_value_get_string(&val), ==, msi->setting_name);
|
|
|
|
|
else
|
|
|
|
|
g_assert_cmpstr(g_value_get_string(&val), ==, default_value);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-24 18:25:00 +02:00
|
|
|
if (NM_FLAGS_HAS(sip->param_spec->flags, NM_SETTING_PARAM_TO_DBUS_IGNORE_FLAGS))
|
|
|
|
|
g_assert(sip->property_type->to_dbus_fcn);
|
2019-09-21 20:35:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
/* check that all GObject based properties are tracked by the settings. */
|
|
|
|
|
property_specs =
|
|
|
|
|
g_object_class_list_properties(G_OBJECT_CLASS(sis->setting_class), &n_property_specs);
|
|
|
|
|
g_assert(property_specs);
|
|
|
|
|
g_assert_cmpint(n_property_specs, >, 0);
|
|
|
|
|
for (prop_idx = 0; prop_idx < n_property_specs; prop_idx++) {
|
|
|
|
|
const GParamSpec *pip = property_specs[prop_idx];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
g_assert(g_hash_table_lookup(h_properties, pip->name) == pip);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
/* check that property_infos_sorted is as expected. */
|
|
|
|
|
if (sis->property_infos_sorted) {
|
|
|
|
|
gs_unref_hashtable GHashTable *h = g_hash_table_new(nm_direct_hash, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
/* property_infos_sorted is only implemented for [connection] type */
|
|
|
|
|
g_assert_cmpint(meta_type, ==, NM_META_SETTING_TYPE_CONNECTION);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
/* ensure that there are no duplicates, and that all properties are also
|
|
|
|
|
* tracked by sis->property_infos. */
|
|
|
|
|
for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) {
|
|
|
|
|
const NMSettInfoProperty *sip = sis->property_infos_sorted[prop_idx];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
if (!g_hash_table_add(h, (gpointer) sip))
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) {
|
|
|
|
|
const NMSettInfoProperty *sip = &sis->property_infos[prop_idx];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
g_assert(g_hash_table_contains(h, sip));
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
g_assert_cmpint(meta_type, !=, NM_META_SETTING_TYPE_CONNECTION);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
/* consistency check for gendata-info. */
|
|
|
|
|
if (sis->detail.gendata_info) {
|
|
|
|
|
g_assert_cmpint(meta_type, ==, NM_META_SETTING_TYPE_ETHTOOL);
|
|
|
|
|
g_assert(sis->detail.gendata_info->get_variant_type);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
/* the gendata info based setting has only one regular property: the "name". */
|
|
|
|
|
g_assert_cmpint(sis->property_infos_len, ==, 1);
|
|
|
|
|
g_assert_cmpstr(sis->property_infos[0].name, ==, NM_SETTING_NAME);
|
|
|
|
|
} else
|
|
|
|
|
g_assert_cmpint(meta_type, !=, NM_META_SETTING_TYPE_ETHTOOL);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
{
|
|
|
|
|
gs_free NMSettInfoPropertType **a_property_types = NULL;
|
|
|
|
|
guint a_property_types_len;
|
|
|
|
|
guint prop_idx;
|
|
|
|
|
guint prop_idx_2;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
a_property_types =
|
|
|
|
|
(NMSettInfoPropertType **) g_hash_table_get_keys_as_array(h_property_types,
|
|
|
|
|
&a_property_types_len);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
for (prop_idx = 0; prop_idx < a_property_types_len; prop_idx++) {
|
|
|
|
|
const NMSettInfoPropertType *pt = a_property_types[prop_idx];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
for (prop_idx_2 = prop_idx + 1; prop_idx_2 < a_property_types_len; prop_idx_2++) {
|
|
|
|
|
const NMSettInfoPropertType *pt_2 = a_property_types[prop_idx_2];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
if (!g_variant_type_equal(pt->dbus_type, pt_2->dbus_type)
|
|
|
|
|
|| pt->to_dbus_fcn != pt_2->to_dbus_fcn
|
|
|
|
|
|| pt->from_dbus_fcn != pt_2->from_dbus_fcn
|
|
|
|
|
|| pt->missing_from_dbus_fcn != pt_2->missing_from_dbus_fcn
|
|
|
|
|
|| pt->gprop_to_dbus_fcn != pt_2->gprop_to_dbus_fcn
|
|
|
|
|
|| pt->gprop_from_dbus_fcn != pt_2->gprop_from_dbus_fcn)
|
|
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
if ((pt == &nm_sett_info_propert_type_plain_i
|
|
|
|
|
&& pt_2 == &nm_sett_info_propert_type_deprecated_ignore_i)
|
|
|
|
|
|| (pt_2 == &nm_sett_info_propert_type_plain_i
|
|
|
|
|
&& pt == &nm_sett_info_propert_type_deprecated_ignore_i)
|
|
|
|
|
|| (pt == &nm_sett_info_propert_type_plain_u
|
|
|
|
|
&& pt_2 == &nm_sett_info_propert_type_deprecated_ignore_u)
|
|
|
|
|
|| (pt_2 == &nm_sett_info_propert_type_plain_u
|
|
|
|
|
&& pt == &nm_sett_info_propert_type_deprecated_ignore_u)) {
|
|
|
|
|
/* These are known to be duplicated. This is the case for
|
2020-07-04 11:37:01 +03:00
|
|
|
* "gsm.network-type" and plain properties like "802-11-wireless-security.fils" ("i" D-Bus type)
|
|
|
|
|
* "gsm.allowed-bands" and plain properties like "802-11-olpc-mesh.channel" ("u" D-Bus type)
|
2019-09-22 10:57:57 +02:00
|
|
|
* While the content/behaviour of the property types are identical, their purpose
|
2020-07-04 11:37:01 +03:00
|
|
|
* is different. So allow them.
|
2019-09-22 10:57:57 +02:00
|
|
|
*/
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* the property-types with same content should all be shared. Here we have two that
|
|
|
|
|
* are the same content, but different instances. Bug. */
|
|
|
|
|
g_error("The identical property type for D-Bus type \"%s\" is used by: %s and %s",
|
|
|
|
|
(const char *) pt->dbus_type,
|
|
|
|
|
_PROP_IDX_OWNER(h_property_types, pt),
|
|
|
|
|
_PROP_IDX_OWNER(h_property_types, pt_2));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-21 20:35:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
NMTST_DEFINE();
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
nmtst_init(&argc, &argv, TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-12 17:27:45 +02:00
|
|
|
g_test_add_func("/libnm/settings/ethtool/features", test_ethtool_features);
|
2020-05-07 16:58:32 +02:00
|
|
|
g_test_add_func("/libnm/settings/ethtool/coalesce", test_ethtool_coalesce);
|
2020-05-12 17:27:45 +02:00
|
|
|
g_test_add_func("/libnm/settings/ethtool/ring", test_ethtool_ring);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:42:57 +01:00
|
|
|
g_test_add_func("/libnm/settings/tc_config/qdisc", test_tc_config_qdisc);
|
2017-11-28 09:24:08 +01:00
|
|
|
g_test_add_func("/libnm/settings/tc_config/action", test_tc_config_action);
|
2020-05-11 15:36:10 +02:00
|
|
|
g_test_add_func("/libnm/settings/tc_config/tfilter/matchall_sdata",
|
|
|
|
|
test_tc_config_tfilter_matchall_sdata);
|
|
|
|
|
g_test_add_func("/libnm/settings/tc_config/tfilter/matchall_mirred",
|
|
|
|
|
test_tc_config_tfilter_matchall_mirred);
|
2018-06-21 15:56:29 +02:00
|
|
|
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);
|
2017-12-03 13:42:57 +01:00
|
|
|
g_test_add_func("/libnm/settings/tc_config/dbus", test_tc_config_dbus);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-19 15:35:28 +01:00
|
|
|
g_test_add_func("/libnm/settings/bridge/vlans", test_bridge_vlans);
|
2020-03-23 19:29:24 +01:00
|
|
|
g_test_add_func("/libnm/settings/bridge/verify", test_bridge_verify);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-03 20:13:41 +02:00
|
|
|
g_test_add_func("/libnm/test_nm_json", test_nm_json);
|
2017-11-22 14:44:43 +01:00
|
|
|
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);
|
2018-02-05 15:24:36 +01:00
|
|
|
g_test_add_func("/libnm/settings/team/sync_runner_from_config_random",
|
|
|
|
|
test_runner_random_sync_from_config);
|
2017-11-22 14:44:43 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-01 10:07:04 +01:00
|
|
|
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);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
g_test_add_data_func("/libnm/settings/roundtrip-conversion/general/0",
|
|
|
|
|
GINT_TO_POINTER(0),
|
|
|
|
|
test_roundtrip_conversion);
|
2019-01-03 13:38:02 +01:00
|
|
|
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);
|
2019-03-14 12:04:21 +01:00
|
|
|
g_test_add_data_func("/libnm/settings/roundtrip-conversion/general/3",
|
|
|
|
|
GINT_TO_POINTER(3),
|
|
|
|
|
test_roundtrip_conversion);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-13 09:18:49 +01:00
|
|
|
g_test_add_data_func("/libnm/settings/routing-rule/1", GINT_TO_POINTER(0), test_routing_rule);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-01 10:49:16 +02:00
|
|
|
g_test_add_func("/libnm/parse-tc-handle", test_parse_tc_handle);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 17:55:18 +02:00
|
|
|
g_test_add_func("/libnm/test_team_setting", test_team_setting);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-25 14:29:13 +02:00
|
|
|
g_test_add_func("/libnm/test_empty_setting", test_empty_setting);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
g_test_add_func("/libnm/test_setting_metadata", test_setting_metadata);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-03 13:37:39 +01:00
|
|
|
return g_test_run();
|
|
|
|
|
}
|