Thomas Haller 2019-05-23 18:10:54 +02:00
commit 3f760601d4
33 changed files with 4291 additions and 2084 deletions

View file

@ -343,6 +343,8 @@ shared_nm_glib_aux_libnm_glib_aux_la_SOURCES = \
shared/nm-glib-aux/nm-io-utils.c \
shared/nm-glib-aux/nm-io-utils.h \
shared/nm-glib-aux/nm-jansson.h \
shared/nm-glib-aux/nm-json-aux.c \
shared/nm-glib-aux/nm-json-aux.h \
shared/nm-glib-aux/nm-keyfile-aux.c \
shared/nm-glib-aux/nm-keyfile-aux.h \
shared/nm-glib-aux/nm-logging-fwd.h \
@ -356,6 +358,7 @@ shared_nm_glib_aux_libnm_glib_aux_la_SOURCES = \
shared/nm-glib-aux/nm-shared-utils.h \
shared/nm-glib-aux/nm-time-utils.c \
shared/nm-glib-aux/nm-time-utils.h \
shared/nm-glib-aux/nm-value-type.h \
$(NULL)
shared_nm_glib_aux_libnm_glib_aux_la_LDFLAGS = \
@ -788,21 +791,25 @@ libnm_core_lib_h_pub_real = \
libnm-core/nm-version.h \
libnm-core/nm-vpn-dbus-interface.h \
libnm-core/nm-vpn-editor-plugin.h \
libnm-core/nm-vpn-plugin-info.h
libnm-core/nm-vpn-plugin-info.h \
$(NULL)
libnm_core_lib_h_pub_mkenums = \
libnm-core/nm-core-enum-types.h
libnm-core/nm-core-enum-types.h \
$(NULL)
libnm_core_lib_h_priv = \
shared/nm-meta-setting.h \
libnm-core/nm-crypto.h \
libnm-core/nm-crypto-impl.h \
libnm-core/nm-connection-private.h \
libnm-core/nm-core-internal.h \
libnm-core/nm-core-types-internal.h \
libnm-core/nm-crypto-impl.h \
libnm-core/nm-crypto.h \
libnm-core/nm-keyfile-internal.h \
libnm-core/nm-keyfile-utils.h \
libnm-core/nm-property-compare.h \
libnm-core/nm-setting-private.h \
libnm-core/nm-utils-private.h
libnm-core/nm-team-utils.h \
libnm-core/nm-utils-private.h \
$(NULL)
libnm_core_lib_c_settings_real = \
libnm-core/nm-setting-6lowpan.c \
libnm-core/nm-setting-8021x.c \
@ -850,22 +857,25 @@ libnm_core_lib_c_settings_real = \
libnm-core/nm-setting-wireguard.c \
libnm-core/nm-setting-wireless-security.c \
libnm-core/nm-setting-wireless.c \
libnm-core/nm-setting-wpan.c
libnm-core/nm-setting-wpan.c \
$(NULL)
libnm_core_lib_c_real = \
$(libnm_core_lib_c_settings_real) \
shared/nm-meta-setting.c \
libnm-core/nm-crypto.c \
libnm-core/nm-connection.c \
libnm-core/nm-crypto.c \
libnm-core/nm-dbus-utils.c \
libnm-core/nm-errors.c \
libnm-core/nm-keyfile.c \
libnm-core/nm-keyfile-utils.c \
libnm-core/nm-keyfile.c \
libnm-core/nm-property-compare.c \
libnm-core/nm-setting.c \
libnm-core/nm-simple-connection.c \
libnm-core/nm-team-utils.c \
libnm-core/nm-utils.c \
libnm-core/nm-vpn-editor-plugin.c \
libnm-core/nm-vpn-plugin-info.c
libnm-core/nm-vpn-plugin-info.c \
$(NULL)
if WITH_JSON_VALIDATION
libnm_core_lib_h_priv += \

View file

@ -554,7 +554,6 @@ nmc_team_check_config (const char *config, char **out_config, GError **error)
_TEAM_CONFIG_TYPE_FILE,
_TEAM_CONFIG_TYPE_JSON,
} desired_type = _TEAM_CONFIG_TYPE_GUESS;
const char *filename = NULL;
size_t c_len = 0;
gs_free char *config_clone = NULL;
@ -588,22 +587,10 @@ nmc_team_check_config (const char *config, char **out_config, GError **error)
config);
return FALSE;
}
filename = config;
config = config_clone = g_steal_pointer (&contents);
}
}
if (!nm_utils_is_json_object (config, NULL)) {
if (filename) {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("'%s' does not contain a valid team configuration"), filename);
} else {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("team configuration must be a JSON object"));
}
return FALSE;
}
*out_config = (config == config_clone)
? g_steal_pointer (&config_clone)
: g_strdup (config);

View file

@ -310,7 +310,7 @@
#define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL N_("Corresponds to the teamd mcast_rejoin.interval.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_COUNT N_("Corresponds to the teamd notify_peers.count.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL N_("Corresponds to the teamd notify_peers.interval.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\". When setting the runner, all the properties specific to the runner will be reset to the default value; all the properties specific to other runners will be set to an empty value (or if not possible to a default value).")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\".")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_ACTIVE N_("Corresponds to the teamd runner.active.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY N_("Corresponds to the teamd runner.agg_select_policy.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_FAST_RATE N_("Corresponds to the teamd runner.fast_rate.")

View file

@ -112,15 +112,16 @@ libnm_core_settings_sources = files(
)
libnm_core_sources = libnm_core_settings_sources + files(
'nm-crypto.c',
'nm-connection.c',
'nm-crypto.c',
'nm-dbus-utils.c',
'nm-errors.c',
'nm-keyfile.c',
'nm-keyfile-utils.c',
'nm-keyfile.c',
'nm-property-compare.c',
'nm-setting.c',
'nm-simple-connection.c',
'nm-team-utils.c',
'nm-utils.c',
'nm-vpn-editor-plugin.c',
'nm-vpn-plugin-info.c',

View file

@ -534,20 +534,18 @@ gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr);
/*****************************************************************************/
gboolean _nm_team_link_watchers_equal (GPtrArray *a, GPtrArray *b, gboolean ignore_order);
NMTeamLinkWatcher *_nm_team_link_watcher_ref (NMTeamLinkWatcher *watcher);
gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, gboolean port);
GValue *_nm_utils_team_config_get (const char *conf,
const char *key,
const char *key2,
const char *key3,
gboolean port_config);
int nm_team_link_watcher_cmp (const NMTeamLinkWatcher *watcher, const NMTeamLinkWatcher *other);
gboolean _nm_utils_team_config_set (char **conf,
const char *key,
const char *key2,
const char *key3,
const GValue *value);
int nm_team_link_watchers_cmp (const NMTeamLinkWatcher *const*a,
const NMTeamLinkWatcher *const*b,
gsize len,
gboolean ignore_order);
gboolean nm_team_link_watchers_equal (const GPtrArray *a,
const GPtrArray *b,
gboolean ignore_order);
/*****************************************************************************/

View file

@ -1619,16 +1619,16 @@ team_config_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
gs_free_error GError *error = NULL;
conf = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
g_object_set (G_OBJECT (setting), key, conf, NULL);
if ( conf
&& conf[0]
&& !nm_utils_is_json_object (conf, &error)) {
&& !nm_setting_verify (setting, NULL, &error)) {
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid team configuration: %s"),
error->message);
g_clear_pointer (&conf, g_free);
g_object_set (G_OBJECT (setting), key, NULL, NULL);
}
g_object_set (G_OBJECT (setting), key, conf, NULL);
}
static void

View file

@ -30,6 +30,7 @@
#include "nm-utils-private.h"
#include "nm-connection-private.h"
#include "nm-setting-connection.h"
#include "nm-team-utils.h"
/**
* SECTION:nm-setting-team-port
@ -41,34 +42,10 @@
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE (NMSettingTeamPort,
PROP_CONFIG,
PROP_QUEUE_ID,
PROP_PRIO,
PROP_STICKY,
PROP_LACP_PRIO,
PROP_LACP_KEY,
PROP_LINK_WATCHERS,
);
static const _NMUtilsTeamPropertyKeys _prop_to_keys[_PROPERTY_ENUMS_LAST] = {
[PROP_CONFIG] = { },
[PROP_QUEUE_ID] = { .key1 = "queue_id", .default_int = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT, },
[PROP_PRIO] = { .key1 = "prio", },
[PROP_STICKY] = { .key1 = "sticky", },
[PROP_LACP_PRIO] = { .key1 = "lacp_prio", .default_int = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT, },
[PROP_LACP_KEY] = { .key1 = "lacp_key", },
[PROP_LINK_WATCHERS] = { .key1 = "link_watch", },
};
static GParamSpec *obj_properties[_NM_TEAM_ATTRIBUTE_PORT_NUM] = { NULL, };
typedef struct {
char *config;
int queue_id;
int prio;
gboolean sticky;
int lacp_prio;
int lacp_key;
GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */
NMTeamSetting *team_setting;
} NMSettingTeamPortPrivate;
G_DEFINE_TYPE (NMSettingTeamPort, nm_setting_team_port, NM_TYPE_SETTING)
@ -77,6 +54,17 @@ G_DEFINE_TYPE (NMSettingTeamPort, nm_setting_team_port, NM_TYPE_SETTING)
/*****************************************************************************/
#define _maybe_changed(self, changed) \
nm_team_setting_maybe_changed (NM_SETTING (_NM_ENSURE_TYPE (NMSettingTeamPort *, self)), (const GParamSpec *const*) obj_properties, (changed))
#define _maybe_changed_with_assert(self, changed) \
G_STMT_START { \
if (!_maybe_changed ((self), (changed))) \
nm_assert_not_reached (); \
} G_STMT_END
/*****************************************************************************/
/**
* nm_setting_team_port_get_config:
* @setting: the #NMSettingTeamPort
@ -88,7 +76,7 @@ nm_setting_team_port_get_config (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), NULL);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->config;
return nm_team_setting_config_get (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting);
}
/**
@ -104,7 +92,7 @@ nm_setting_team_port_get_queue_id (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), -1);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->queue_id;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.queue_id;
}
/**
@ -120,7 +108,7 @@ nm_setting_team_port_get_prio (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->prio;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.prio;
}
/**
@ -136,7 +124,7 @@ nm_setting_team_port_get_sticky (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->sticky;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.sticky;
}
/**
@ -152,7 +140,7 @@ nm_setting_team_port_get_lacp_prio (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->lacp_prio;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.lacp_prio;
}
/**
@ -168,7 +156,7 @@ nm_setting_team_port_get_lacp_key (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->lacp_key;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.lacp_key;
}
/**
@ -182,11 +170,9 @@ nm_setting_team_port_get_lacp_key (NMSettingTeamPort *setting)
guint
nm_setting_team_port_get_num_link_watchers (NMSettingTeamPort *setting)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0);
return priv->link_watchers->len;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.link_watchers->len;
}
/**
@ -201,12 +187,15 @@ nm_setting_team_port_get_num_link_watchers (NMSettingTeamPort *setting)
NMTeamLinkWatcher *
nm_setting_team_port_get_link_watcher (NMSettingTeamPort *setting, guint idx)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
NMSettingTeamPortPrivate *priv;
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), NULL);
g_return_val_if_fail (idx < priv->link_watchers->len, NULL);
return priv->link_watchers->pdata[idx];
priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
g_return_val_if_fail (idx < priv->team_setting->d.link_watchers->len, NULL);
return priv->team_setting->d.link_watchers->pdata[idx];
}
/**
@ -225,20 +214,12 @@ gboolean
nm_setting_team_port_add_link_watcher (NMSettingTeamPort *setting,
NMTeamLinkWatcher *link_watcher)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
guint i;
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE);
g_return_val_if_fail (link_watcher != NULL, FALSE);
for (i = 0; i < priv->link_watchers->len; i++) {
if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher))
return FALSE;
}
g_ptr_array_add (priv->link_watchers, nm_team_link_watcher_dup (link_watcher));
_notify (setting, PROP_LINK_WATCHERS);
return TRUE;
return _maybe_changed (setting,
nm_team_setting_value_link_watchers_add (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
link_watcher));
}
/**
@ -253,13 +234,17 @@ nm_setting_team_port_add_link_watcher (NMSettingTeamPort *setting,
void
nm_setting_team_port_remove_link_watcher (NMSettingTeamPort *setting, guint idx)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
NMSettingTeamPortPrivate *priv;
g_return_if_fail (NM_IS_SETTING_TEAM_PORT (setting));
g_return_if_fail (idx < priv->link_watchers->len);
g_ptr_array_remove_index (priv->link_watchers, idx);
_notify (setting, PROP_LINK_WATCHERS);
priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
g_return_if_fail (idx < priv->team_setting->d.link_watchers->len);
_maybe_changed_with_assert (setting,
nm_team_setting_value_link_watchers_remove (priv->team_setting,
idx));
}
/**
@ -277,19 +262,12 @@ gboolean
nm_setting_team_port_remove_link_watcher_by_value (NMSettingTeamPort *setting,
NMTeamLinkWatcher *link_watcher)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
guint i;
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE);
g_return_val_if_fail (link_watcher, FALSE);
for (i = 0; i < priv->link_watchers->len; i++) {
if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher)) {
g_ptr_array_remove_index (priv->link_watchers, i);
_notify (setting, PROP_LINK_WATCHERS);
return TRUE;
}
}
return FALSE;
return _maybe_changed (setting,
nm_team_setting_value_link_watchers_remove_by_value (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
link_watcher));
}
/**
@ -303,14 +281,12 @@ nm_setting_team_port_remove_link_watcher_by_value (NMSettingTeamPort *setting,
void
nm_setting_team_port_clear_link_watchers (NMSettingTeamPort *setting)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
g_return_if_fail (NM_IS_SETTING_TEAM_PORT (setting));
if (priv->link_watchers->len != 0) {
g_ptr_array_set_size (priv->link_watchers, 0);
_notify (setting, PROP_LINK_WATCHERS);
}
_maybe_changed (setting,
nm_team_setting_value_link_watchers_set_list (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
NULL,
0));
}
static GVariant *
@ -323,7 +299,7 @@ static void
team_link_watchers_from_dbus (GVariant *dbus_value,
GValue *prop_value)
{
g_value_take_boxed (prop_value, _nm_utils_team_link_watchers_from_variant (dbus_value));
g_value_take_boxed (prop_value, _nm_utils_team_link_watchers_from_variant (dbus_value, FALSE, NULL));
}
static gboolean
@ -360,29 +336,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
if (priv->config) {
if (strlen (priv->config) > 1*1024*1024) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("team config exceeds size limit"));
g_prefix_error (error,
"%s.%s: ",
NM_SETTING_TEAM_PORT_SETTING_NAME,
NM_SETTING_TEAM_PORT_CONFIG);
return FALSE;
}
if (!nm_utils_is_json_object (priv->config, error)) {
g_prefix_error (error,
"%s.%s: ",
NM_SETTING_TEAM_PORT_SETTING_NAME,
NM_SETTING_TEAM_PORT_CONFIG);
/* We treat an empty string as no config for compatibility. */
return *priv->config ? FALSE : NM_SETTING_VERIFY_NORMALIZABLE;
}
}
/* NOTE: normalizable/normalizable-errors must appear at the end with decreasing severity.
* Take care to properly order statements with priv->config above. */
if (!nm_team_setting_verify (priv->team_setting, error))
return FALSE;
return TRUE;
}
@ -407,27 +362,26 @@ compare_property (const NMSettInfoSetting *sett_info,
return TRUE;
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_a);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_b);
return _nm_team_link_watchers_equal (a_priv->link_watchers,
b_priv->link_watchers,
TRUE);
return nm_team_link_watchers_equal (a_priv->team_setting->d.link_watchers,
b_priv->team_setting->d.link_watchers,
TRUE);
}
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_PORT_CONFIG)) {
if (set_b) {
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_a);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_b);
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
/* If we are trying to match a connection in order to assume it (and thus
* @flags contains INFERRABLE), use the "relaxed" matching for team
* configuration. Otherwise, for all other purposes (including connection
* comparison before an update), resort to the default string comparison. */
return _nm_utils_team_config_equal (a_priv->config,
b_priv->config,
TRUE);
return TRUE;
}
return nm_streq0 (a_priv->config, b_priv->config);
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_a);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_b);
return nm_streq0 (nm_team_setting_config_get (a_priv->team_setting),
nm_team_setting_config_get (b_priv->team_setting));
}
return TRUE;
@ -442,6 +396,37 @@ compare_property (const NMSettInfoSetting *sett_info,
flags);
}
static void
duplicate_copy_properties (const NMSettInfoSetting *sett_info,
NMSetting *src,
NMSetting *dst)
{
_maybe_changed (NM_SETTING_TEAM_PORT (dst),
nm_team_setting_reset (NM_SETTING_TEAM_PORT_GET_PRIVATE (dst)->team_setting,
NM_SETTING_TEAM_PORT_GET_PRIVATE (src)->team_setting));
}
static gboolean
init_from_dbus (NMSetting *setting,
GHashTable *keys,
GVariant *setting_dict,
GVariant *connection_dict,
guint /* NMSettingParseFlags */ parse_flags,
GError **error)
{
guint32 changed = 0;
gboolean success;
success = nm_team_setting_reset_from_dbus (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
setting_dict,
keys,
&changed,
parse_flags,
error);
_maybe_changed (NM_SETTING_TEAM_PORT (setting), changed);
return success;
}
/*****************************************************************************/
static void
@ -452,27 +437,26 @@ get_property (GObject *object, guint prop_id,
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
switch (prop_id) {
case PROP_CONFIG:
g_value_set_string (value, nm_setting_team_port_get_config (setting));
case NM_TEAM_ATTRIBUTE_CONFIG:
g_value_set_string (value,
nm_team_setting_config_get (priv->team_setting));
break;
case PROP_QUEUE_ID:
g_value_set_int (value, priv->queue_id);
case NM_TEAM_ATTRIBUTE_PORT_STICKY:
g_value_set_boolean (value,
nm_team_setting_value_get_bool (priv->team_setting,
prop_id));
break;
case PROP_PRIO:
g_value_set_int (value, priv->prio);
case NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID:
case NM_TEAM_ATTRIBUTE_PORT_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_KEY:
g_value_set_int (value,
nm_team_setting_value_get_int32 (priv->team_setting,
prop_id));
break;
case PROP_STICKY:
g_value_set_boolean (value, priv->sticky);
break;
case PROP_LACP_PRIO:
g_value_set_int (value, priv->lacp_prio);
break;
case PROP_LACP_KEY:
g_value_set_int (value, priv->lacp_key);
break;
case PROP_LINK_WATCHERS:
g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers,
(NMUtilsCopyFunc) nm_team_link_watcher_dup,
case NM_TEAM_ATTRIBUTE_LINK_WATCHERS:
g_value_take_boxed (value, _nm_utils_copy_array (priv->team_setting->d.link_watchers,
(NMUtilsCopyFunc) _nm_team_link_watcher_ref,
(GDestroyNotify) nm_team_link_watcher_unref));
break;
default:
@ -485,81 +469,40 @@ static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (object);
const GValue *align_value = NULL;
gboolean align_config = FALSE;
#define JSON_TO_VAL(typ, id) _nm_utils_json_extract_##typ (priv->config, _prop_to_keys[id], TRUE)
NMSettingTeamPort *setting = NM_SETTING_TEAM_PORT (object);
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
guint32 changed;
const GPtrArray *v_ptrarr;
switch (prop_id) {
case PROP_CONFIG:
g_free (priv->config);
priv->config = g_value_dup_string (value);
priv->queue_id = JSON_TO_VAL (int, PROP_QUEUE_ID);
priv->prio = JSON_TO_VAL (int, PROP_PRIO);
priv->sticky = JSON_TO_VAL (boolean, PROP_STICKY);
priv->lacp_prio = JSON_TO_VAL (int, PROP_LACP_PRIO);
priv->lacp_key = JSON_TO_VAL (int, PROP_LACP_KEY);
g_ptr_array_unref (priv->link_watchers);
priv->link_watchers = JSON_TO_VAL (ptr_array, PROP_LINK_WATCHERS);
case NM_TEAM_ATTRIBUTE_CONFIG:
changed = nm_team_setting_config_set (priv->team_setting, g_value_get_string (value));
break;
case PROP_QUEUE_ID:
if (priv->queue_id == g_value_get_int (value))
break;
priv->queue_id = g_value_get_int (value);
if (priv->queue_id != NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT)
align_value = value;
align_config = TRUE;
case NM_TEAM_ATTRIBUTE_PORT_STICKY:
changed = nm_team_setting_value_set_bool (priv->team_setting,
prop_id,
g_value_get_boolean (value));
break;
case PROP_PRIO:
if (priv->prio == g_value_get_int (value))
break;
priv->prio = g_value_get_int (value);
if (priv->prio)
align_value = value;
align_config = TRUE;
case NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID:
case NM_TEAM_ATTRIBUTE_PORT_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_KEY:
changed = nm_team_setting_value_set_int32 (priv->team_setting,
prop_id,
g_value_get_int (value));
break;
case PROP_STICKY:
if (priv->sticky == g_value_get_boolean (value))
break;
priv->sticky = g_value_get_boolean (value);
if (priv->sticky)
align_value = value;
align_config = TRUE;
break;
case PROP_LACP_PRIO:
if (priv->lacp_prio == g_value_get_int (value))
break;
priv->lacp_prio = g_value_get_int (value);
/* from libteam sources: lacp_prio default value is 0xff */
if (priv->lacp_prio != NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT)
align_value = value;
align_config = TRUE;
break;
case PROP_LACP_KEY:
if (priv->lacp_key == g_value_get_int (value))
break;
priv->lacp_key = g_value_get_int (value);
if (priv->lacp_key)
align_value = value;
align_config = TRUE;
break;
case PROP_LINK_WATCHERS:
g_ptr_array_unref (priv->link_watchers);
priv->link_watchers = _nm_utils_copy_array (g_value_get_boxed (value),
(NMUtilsCopyFunc) nm_team_link_watcher_dup,
(GDestroyNotify) nm_team_link_watcher_unref);
if (priv->link_watchers->len)
align_value = value;
align_config = TRUE;
case NM_TEAM_ATTRIBUTE_LINK_WATCHERS:
v_ptrarr = g_value_get_boxed (value);
changed = nm_team_setting_value_link_watchers_set_list (priv->team_setting,
v_ptrarr ? (const NMTeamLinkWatcher *const*) v_ptrarr->pdata : NULL,
v_ptrarr ? v_ptrarr->len : 0u);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
return;
}
if (align_config)
_nm_utils_json_append_gvalue (&priv->config, _prop_to_keys[prop_id], align_value);
_maybe_changed (setting, changed & ~(((guint32) 1) << prop_id));
}
/*****************************************************************************/
@ -569,9 +512,7 @@ nm_setting_team_port_init (NMSettingTeamPort *setting)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
priv->queue_id = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT;
priv->lacp_prio = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT;
priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
priv->team_setting = nm_team_setting_new (TRUE, NULL);
}
/**
@ -592,8 +533,7 @@ finalize (GObject *object)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (object);
g_free (priv->config);
g_ptr_array_unref (priv->link_watchers);
nm_team_setting_free (priv->team_setting);
G_OBJECT_CLASS (nm_setting_team_port_parent_class)->finalize (object);
}
@ -611,8 +551,10 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
object_class->set_property = set_property;
object_class->finalize = finalize;
setting_class->compare_property = compare_property;
setting_class->verify = verify;
setting_class->compare_property = compare_property;
setting_class->verify = verify;
setting_class->duplicate_copy_properties = duplicate_copy_properties;
setting_class->init_from_dbus = init_from_dbus;
/**
* NMSettingTeamPort:config:
@ -628,7 +570,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
* description: Team port configuration in JSON. See man teamd.conf for details.
* ---end---
*/
obj_properties[PROP_CONFIG] =
obj_properties[NM_TEAM_ATTRIBUTE_CONFIG] =
g_param_spec_string (NM_SETTING_TEAM_PORT_CONFIG, "", "",
NULL,
G_PARAM_READWRITE |
@ -643,7 +585,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_QUEUE_ID] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID] =
g_param_spec_int (NM_SETTING_TEAM_PORT_QUEUE_ID, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@ -656,7 +598,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_PRIO] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_PRIO] =
g_param_spec_int (NM_SETTING_TEAM_PORT_PRIO, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@ -669,7 +611,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_STICKY] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_STICKY] =
g_param_spec_boolean (NM_SETTING_TEAM_PORT_STICKY, "", "",
FALSE,
G_PARAM_READWRITE |
@ -682,7 +624,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_LACP_PRIO] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO] =
g_param_spec_int (NM_SETTING_TEAM_PORT_LACP_PRIO, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@ -695,7 +637,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_LACP_KEY] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_KEY] =
g_param_spec_int (NM_SETTING_TEAM_PORT_LACP_KEY, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@ -715,19 +657,19 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_LINK_WATCHERS] =
obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS] =
g_param_spec_boxed (NM_SETTING_TEAM_PORT_LINK_WATCHERS, "", "",
G_TYPE_PTR_ARRAY,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
_properties_override_add_transform (properties_override,
obj_properties[PROP_LINK_WATCHERS],
obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS],
G_VARIANT_TYPE ("aa{sv}"),
team_link_watchers_to_dbus,
team_link_watchers_from_dbus);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_properties), obj_properties);
_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_TEAM_PORT,
NULL, properties_override);

File diff suppressed because it is too large Load diff

View file

@ -88,29 +88,30 @@ void nm_team_link_watcher_ref (NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
void nm_team_link_watcher_unref (NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
gboolean nm_team_link_watcher_equal (NMTeamLinkWatcher *watcher, NMTeamLinkWatcher *other);
gboolean nm_team_link_watcher_equal (const NMTeamLinkWatcher *watcher,
const NMTeamLinkWatcher *other);
NM_AVAILABLE_IN_1_12
NMTeamLinkWatcher *nm_team_link_watcher_dup (NMTeamLinkWatcher *watcher);
NMTeamLinkWatcher *nm_team_link_watcher_dup (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
const char *nm_team_link_watcher_get_name (NMTeamLinkWatcher *watcher);
const char *nm_team_link_watcher_get_name (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
int nm_team_link_watcher_get_delay_up (NMTeamLinkWatcher *watcher);
int nm_team_link_watcher_get_delay_up (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
int nm_team_link_watcher_get_delay_down (NMTeamLinkWatcher *watcher);
int nm_team_link_watcher_get_delay_down (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
int nm_team_link_watcher_get_init_wait (NMTeamLinkWatcher *watcher);
int nm_team_link_watcher_get_init_wait (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
int nm_team_link_watcher_get_interval (NMTeamLinkWatcher *watcher);
int nm_team_link_watcher_get_interval (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
int nm_team_link_watcher_get_missed_max (NMTeamLinkWatcher *watcher);
int nm_team_link_watcher_get_missed_max (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
const char *nm_team_link_watcher_get_target_host (NMTeamLinkWatcher *watcher);
const char *nm_team_link_watcher_get_target_host (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
const char *nm_team_link_watcher_get_source_host (NMTeamLinkWatcher *watcher);
const char *nm_team_link_watcher_get_source_host (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_12
NMTeamLinkWatcherArpPingFlags nm_team_link_watcher_get_flags (NMTeamLinkWatcher *watcher);
NMTeamLinkWatcherArpPingFlags nm_team_link_watcher_get_flags (const NMTeamLinkWatcher *watcher);
NM_AVAILABLE_IN_1_16
int nm_team_link_watcher_get_vlanid (NMTeamLinkWatcher *watcher);
int nm_team_link_watcher_get_vlanid (const NMTeamLinkWatcher *watcher);
#define NM_TYPE_SETTING_TEAM (nm_setting_team_get_type ())
#define NM_SETTING_TEAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_TEAM, NMSettingTeam))

View file

@ -863,10 +863,9 @@ _nm_setting_new_from_dbus (GType setting_type,
NMSettingParseFlags parse_flags,
GError **error)
{
gs_unref_ptrarray GPtrArray *keys_keep_variant = NULL;
gs_unref_object NMSetting *setting = NULL;
gs_unref_hashtable GHashTable *keys = NULL;
const NMSettInfoSetting *sett_info;
guint i;
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (setting_type), NULL);
g_return_val_if_fail (g_variant_is_of_type (setting_dict, NM_VARIANT_TYPE_SETTING), NULL);
@ -890,18 +889,19 @@ _nm_setting_new_from_dbus (GType setting_type,
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
GVariantIter iter;
GVariant *entry, *entry_key;
char *key;
const char *key;
keys = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL);
keys_keep_variant = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_unref);
keys = g_hash_table_new (nm_str_hash, g_str_equal);
g_variant_iter_init (&iter, setting_dict);
while ((entry = g_variant_iter_next_value (&iter))) {
entry_key = g_variant_get_child_value (entry, 0);
key = g_strdup (g_variant_get_string (entry_key, NULL));
g_variant_unref (entry_key);
g_ptr_array_add (keys_keep_variant, entry_key);
g_variant_unref (entry);
if (!g_hash_table_add (keys, key)) {
key = g_variant_get_string (entry_key, NULL);
if (!g_hash_table_add (keys, (char *) key)) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
_("duplicate property"));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
@ -910,6 +910,47 @@ _nm_setting_new_from_dbus (GType setting_type,
}
}
if (!NM_SETTING_GET_CLASS (setting)->init_from_dbus (setting,
keys,
setting_dict,
connection_dict,
parse_flags,
error))
return NULL;
if ( NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)
&& g_hash_table_size (keys) > 0) {
GHashTableIter iter;
const char *key;
g_hash_table_iter_init (&iter, keys);
if (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("unknown property"));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
return NULL;
}
}
return g_steal_pointer (&setting);
}
static gboolean
init_from_dbus (NMSetting *setting,
GHashTable *keys,
GVariant *setting_dict,
GVariant *connection_dict,
guint /* NMSettingParseFlags */ parse_flags,
GError **error)
{
const NMSettInfoSetting *sett_info;
guint i;
nm_assert (NM_IS_SETTING (setting));
nm_assert (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL));
nm_assert (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT));
sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
if (sett_info->detail.gendata_info) {
@ -925,10 +966,12 @@ _nm_setting_new_from_dbus (GType setting_type,
g_hash_table_insert (hash,
key,
val);
if (keys)
g_hash_table_remove (keys, key);
}
_nm_setting_gendata_notify (setting, TRUE);
return g_steal_pointer (&setting);
return TRUE;
}
for (i = 0; i < sett_info->property_infos_len; i++) {
@ -942,7 +985,8 @@ _nm_setting_new_from_dbus (GType setting_type,
value = g_variant_lookup_value (setting_dict, property_info->name, NULL);
if (value && keys)
if ( value
&& keys)
g_hash_table_remove (keys, property_info->name);
if ( value
@ -960,7 +1004,7 @@ _nm_setting_new_from_dbus (GType setting_type,
g_type_name (property_info->param_spec->value_type) : "(unknown)",
g_variant_get_type_string (value));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
return FALSE;
}
if (!property_info->from_dbus_fcn (setting,
@ -975,7 +1019,7 @@ _nm_setting_new_from_dbus (GType setting_type,
_("failed to set property: %s"),
local->message);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
return FALSE;
}
} else if ( !value
&& property_info->missing_from_dbus_fcn) {
@ -990,7 +1034,7 @@ _nm_setting_new_from_dbus (GType setting_type,
_("failed to set property: %s"),
local->message);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
return FALSE;
}
} else if ( value
&& property_info->param_spec) {
@ -1010,7 +1054,7 @@ _nm_setting_new_from_dbus (GType setting_type,
: "(unknown)"),
g_variant_get_type_string (value));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
return FALSE;
}
if (!nm_g_object_set_property (G_OBJECT (setting), property_info->param_spec->name, &object_value, &local)) {
@ -1020,26 +1064,12 @@ _nm_setting_new_from_dbus (GType setting_type,
_("can not set property: %s"),
local->message);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
return FALSE;
}
}
}
if ( NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)
&& g_hash_table_size (keys) > 0) {
GHashTableIter iter;
const char *key;
g_hash_table_iter_init (&iter, keys);
if (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("unknown property"));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
return NULL;
}
}
return g_steal_pointer (&setting);
return TRUE;
}
/**
@ -2694,6 +2724,7 @@ nm_setting_class_init (NMSettingClass *setting_class)
setting_class->duplicate_copy_properties = duplicate_copy_properties;
setting_class->enumerate_values = enumerate_values;
setting_class->aggregate = aggregate;
setting_class->init_from_dbus = init_from_dbus;
/**
* NMSetting:name:

View file

@ -268,7 +268,15 @@ typedef struct {
GVariantBuilder *setting_builder);
/*< private >*/
gpointer padding[2];
gboolean (*init_from_dbus) (NMSetting *setting,
GHashTable *keys,
GVariant *setting_dict,
GVariant *connection_dict,
guint /* NMSettingParseFlags */ parse_flags,
GError **error);
/*< private >*/
gpointer padding[1];
/*< private >*/
const struct _NMMetaSettingInfo *setting_info;

2323
libnm-core/nm-team-utils.c Normal file

File diff suppressed because it is too large Load diff

280
libnm-core/nm-team-utils.h Normal file
View file

@ -0,0 +1,280 @@
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2019 Red Hat, Inc.
*/
#ifndef __NM_TEAM_UITLS_H__
#define __NM_TEAM_UITLS_H__
#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE)
#error Cannot use this header.
#endif
#include "nm-glib-aux/nm-value-type.h"
struct _NMSetting;
struct NMTeamLinkWatcher;
typedef enum {
_NM_TEAM_ATTRIBUTE_0 = 0,
NM_TEAM_ATTRIBUTE_CONFIG = 1,
NM_TEAM_ATTRIBUTE_LINK_WATCHERS = 2,
_NM_TEAM_ATTRIBUTE_START = 3,
NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT = _NM_TEAM_ATTRIBUTE_START,
NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL,
NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT,
NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY,
_NM_TEAM_ATTRIBUTE_MASTER_NUM,
NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID = _NM_TEAM_ATTRIBUTE_START,
NM_TEAM_ATTRIBUTE_PORT_PRIO,
NM_TEAM_ATTRIBUTE_PORT_STICKY,
NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO,
NM_TEAM_ATTRIBUTE_PORT_LACP_KEY,
_NM_TEAM_ATTRIBUTE_PORT_NUM,
_NM_TEAM_ATTRIBUTE_NUM = NM_CONST_MAX (_NM_TEAM_ATTRIBUTE_MASTER_NUM, _NM_TEAM_ATTRIBUTE_PORT_NUM),
} NMTeamAttribute;
static inline guint32
nm_team_attribute_to_flags (NMTeamAttribute team_attr)
{
nm_assert (_NM_INT_NOT_NEGATIVE (team_attr));
nm_assert (team_attr < _NM_TEAM_ATTRIBUTE_NUM);
G_STATIC_ASSERT_EXPR (_NM_TEAM_ATTRIBUTE_NUM < 32);
return ((guint32) 1) << team_attr;
}
struct _NMTeamSettingData {
const char *_js_str;
const GPtrArray *link_watchers;
/* this means that @_js_str is unset and needs to be created by
* converting the properties to JSON. This flag indicates that
* we need to re-generate the JSON string on-demand (lazily). */
bool _js_str_need_synthetize;
bool strict_validated:1;
/* indicates tha the JSON is invalid. Usually, we do a very relaxed validation of
* the JSON config, in case !@strict_validated and accept all unknown fields. This
* flag indicates that the JSON value is not even parsable as JSON. nm_connection_verify()
* would reject such a setting. */
bool js_str_invalid:1;
bool is_port:1;
union {
struct {
const GPtrArray *runner_tx_hash;
const char *runner;
const char *runner_hwaddr_policy;
const char *runner_tx_balancer;
const char *runner_agg_select_policy;
gint32 notify_peers_count;
gint32 notify_peers_interval;
gint32 mcast_rejoin_count;
gint32 mcast_rejoin_interval;
gint32 runner_sys_prio;
gint32 runner_min_ports;
gint32 runner_tx_balancer_interval;
bool runner_active;
bool runner_fast_rate;
} master;
struct {
gint32 queue_id;
gint32 prio;
gint32 lacp_prio;
gint32 lacp_key;
bool sticky;
} port;
};
};
/*****************************************************************************/
typedef struct {
union {
const struct _NMTeamSettingData d;
struct _NMTeamSettingData _data_priv;
};
} NMTeamSetting;
NMTeamSetting *nm_team_setting_new (gboolean is_port,
const char *js_str);
void nm_team_setting_free (NMTeamSetting *self);
NM_AUTO_DEFINE_FCN0 (NMTeamSetting *, _nm_auto_free_team_setting, nm_team_setting_free)
#define nm_auto_free_team_setting nm_auto (_nm_auto_free_team_setting)
/*****************************************************************************/
const char *nm_team_setting_config_get (const NMTeamSetting *self);
guint32 nm_team_setting_config_set (NMTeamSetting *self, const char *js_str);
/*****************************************************************************/
gconstpointer _nm_team_setting_value_get (const NMTeamSetting *self,
NMTeamAttribute team_attr,
NMValueType value_type);
static inline gboolean
nm_team_setting_value_get_bool (const NMTeamSetting *self,
NMTeamAttribute team_attr)
{
const bool *p;
p = _nm_team_setting_value_get (self, team_attr, NM_VALUE_TYPE_BOOL);
return p ? *p : 0;
}
static inline gint32
nm_team_setting_value_get_int32 (const NMTeamSetting *self,
NMTeamAttribute team_attr)
{
const gint32 *p;
p = _nm_team_setting_value_get (self, team_attr, NM_VALUE_TYPE_INT32);
return p ? *p : 0;
}
static inline const char *
nm_team_setting_value_get_string (const NMTeamSetting *self,
NMTeamAttribute team_attr)
{
const char *const*p;
p = _nm_team_setting_value_get (self, team_attr, NM_VALUE_TYPE_STRING);
return p ? *p : NULL;
}
/*****************************************************************************/
guint32 _nm_team_setting_value_set (NMTeamSetting *self,
NMTeamAttribute team_attr,
NMValueType value_type,
gconstpointer val);
static inline guint32
nm_team_setting_value_set_bool (NMTeamSetting *self,
NMTeamAttribute team_attr,
gboolean val)
{
const bool bool_val = val;
return _nm_team_setting_value_set (self, team_attr, NM_VALUE_TYPE_BOOL, &bool_val);
}
static inline guint32
nm_team_setting_value_set_int32 (NMTeamSetting *self,
NMTeamAttribute team_attr,
gint32 val)
{
return _nm_team_setting_value_set (self, team_attr, NM_VALUE_TYPE_INT32, &val);
}
static inline guint32
nm_team_setting_value_set_string (NMTeamSetting *self,
NMTeamAttribute team_attr,
const char *arg)
{
return _nm_team_setting_value_set (self, team_attr, NM_VALUE_TYPE_STRING, &arg);
}
/*****************************************************************************/
guint32 nm_team_setting_value_link_watchers_add (NMTeamSetting *self,
const struct NMTeamLinkWatcher *link_watcher);
guint32 nm_team_setting_value_link_watchers_remove (NMTeamSetting *self,
guint idx);
guint32 nm_team_setting_value_link_watchers_remove_by_value (NMTeamSetting *self,
const struct NMTeamLinkWatcher *link_watcher);
guint32 nm_team_setting_value_link_watchers_set_list (NMTeamSetting *self,
const struct NMTeamLinkWatcher *const*arr,
guint len);
/*****************************************************************************/
guint32 nm_team_setting_value_master_runner_tx_hash_add (NMTeamSetting *self,
const char *txhash);
guint32 nm_team_setting_value_master_runner_tx_hash_remove (NMTeamSetting *self,
guint idx);
guint32 nm_team_setting_value_master_runner_tx_hash_set_list (NMTeamSetting *self,
const char *const*arr,
guint len);
/*****************************************************************************/
gboolean nm_team_setting_verify (const NMTeamSetting *self,
GError **error);
/*****************************************************************************/
int nm_team_setting_cmp (const NMTeamSetting *self_a,
const NMTeamSetting *self_b,
gboolean ignore_js_str);
guint32 nm_team_setting_reset (NMTeamSetting *self,
const NMTeamSetting *src);
gboolean nm_team_setting_reset_from_dbus (NMTeamSetting *self,
GVariant *setting_dict,
GHashTable *keys,
guint32 *out_changed,
guint /* NMSettingParseFlags */ parse_flags,
GError **error);
/*****************************************************************************/
GPtrArray *_nm_utils_team_link_watchers_from_variant (GVariant *value,
gboolean strict_parsing,
GError **error);
GVariant *_nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers);
/*****************************************************************************/
gboolean nm_team_setting_maybe_changed (struct _NMSetting *source,
const GParamSpec *const*obj_properties,
guint32 changed);
#endif /* __NM_TEAM_UITLS_H__ */

View file

@ -103,9 +103,6 @@ void _nm_utils_bytes_from_dbus (GVariant *dbus_value,
char * _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize length);
GPtrArray * _nm_utils_team_link_watchers_from_variant (GVariant *value);
GVariant * _nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers);
void _nm_utils_format_variant_attributes_full (GString *str,
const NMUtilsNamedValue *values,
guint num_values,
@ -131,116 +128,4 @@ gboolean _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
const char *setting,
const char *property);
/* JSON to GValue conversion macros */
static inline void
_nm_auto_unset_and_free_gvalue (GValue **ptr)
{
if (*ptr) {
g_value_unset (*ptr);
g_free (*ptr);
}
}
#define nm_auto_unset_and_free_gvalue nm_auto(_nm_auto_unset_and_free_gvalue)
typedef struct {
const char *key1;
const char *key2;
const char *key3;
union {
int default_int;
gboolean default_bool;
const char *default_str;
};
} _NMUtilsTeamPropertyKeys;
static inline int
_nm_utils_json_extract_int (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_VALUE_HOLDS_INT (t_value))
return key.default_int;
return g_value_get_int (t_value);
}
static inline gboolean
_nm_utils_json_extract_boolean (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_VALUE_HOLDS_BOOLEAN (t_value))
return key.default_bool;
return g_value_get_boolean (t_value);
}
static inline char *
_nm_utils_json_extract_string (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_VALUE_HOLDS_STRING (t_value))
return g_strdup (key.default_str);
return g_value_dup_string (t_value);
}
static inline char **
_nm_utils_json_extract_strv (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_TYPE_CHECK_VALUE_TYPE (t_value, G_TYPE_STRV))
return NULL;
return g_strdupv (g_value_get_boxed (t_value))
?: g_new0 (char *, 1);
}
static inline GPtrArray *
_nm_utils_json_extract_ptr_array (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
GPtrArray *data, *ret;
guint i;
ret = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_TYPE_CHECK_VALUE_TYPE (t_value, G_TYPE_PTR_ARRAY))
return ret;
data = g_value_get_boxed (t_value);
if (!data)
return ret;
for (i = 0; i < data->len; i++)
g_ptr_array_add (ret, nm_team_link_watcher_dup (data->pdata[i]));
return ret;
}
static inline void
_nm_utils_json_append_gvalue (char **conf,
_NMUtilsTeamPropertyKeys key,
const GValue *val)
{
_nm_utils_team_config_set (conf, key.key1, key.key2, key.key3, val);
}
#endif

View file

@ -5378,429 +5378,6 @@ _nm_utils_is_json_object_no_validation (const char *str, GError **error)
return FALSE;
}
#if WITH_JSON_VALIDATION
static void
_json_add_object (json_t *json,
const char *key1,
const char *key2,
const char *key3,
json_t *value)
{
json_t *json_element, *json_link;
json_element = json_object_get (json, key1);
if (!json_element) {
json_element = value;
if (key2) {
if (key3) {
json_element = json_object ();
json_object_set_new (json_element, key3, value);
}
json_link = json_object ();
json_object_set_new (json_link, key2, json_element);
json_element = json_link;
}
json_object_set_new (json, key1, json_element);
return;
}
if (!key2)
goto key_already_there;
json_link = json_element;
json_element = json_object_get (json_element, key2);
if (!json_element) {
json_element = value;
if (key3) {
json_element = json_object ();
json_object_set_new (json_element, key3, value);
}
json_object_set_new (json_link, key2, json_element);
return;
}
if (!key3)
goto key_already_there;
json_link = json_element;
json_element = json_object_get (json_element, key3);
if (!json_element) {
json_object_set_new (json_link, key3, value);
return;
}
key_already_there:
json_decref (value);
}
/*
* Removes the specified key1[.key2.key3] from json.
* Returns TRUE if json has been modified, FALSE otherwise. */
static gboolean
_json_del_object (json_t *json,
const char *key1,
const char *key2,
const char *key3)
{
json_t *json_element = json;
json_t *json_link = NULL;
const char *iter_key = key1;
if (key2) {
json_link = json;
json_element = json_object_get (json, key1);
if (!json_element)
return FALSE;
iter_key = key2;
}
if (key3) {
json_link = json_element;
json_element = json_object_get (json_element, key2);
if (!json_element)
return FALSE;
iter_key = key3;
}
if (json_object_del (json_element, iter_key) != 0)
return FALSE;
/* 1st level key only */
if (!json_link)
return TRUE;
if (json_object_size (json_element) == 0)
json_object_del (json_link, (key3 ? key2 : key1));
if (key3 && json_object_size (json_link) == 0)
json_object_del (json, key1);
return TRUE;
}
/* Adds in place to json the defaults for missing properties;
* the "add_implicit" allows to add to the json also the default
* values used but not shown with teamdctl */
static void
_json_team_add_defaults (json_t *json,
gboolean port_config,
gboolean add_implicit)
{
json_t *json_element;
const char *runner = NULL;
if (port_config) {
_json_add_object (json, "link_watch", "name", NULL,
json_string (NM_TEAM_LINK_WATCHER_ETHTOOL));
return;
}
/* Retrieve runner or add default one */
json_element = json_object_get (json, "runner");
if (json_element) {
runner = json_string_value (json_object_get (json_element, "name"));
} else {
json_element = json_object ();
json_object_set_new (json, "runner", json_element);
}
if (!runner) {
runner = NM_SETTING_TEAM_RUNNER_DEFAULT;
json_object_set_new (json_element, "name", json_string (runner));
}
if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) {
_json_add_object (json, "notify_peers", "count", NULL,
json_integer (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT));
_json_add_object (json, "mcast_rejoin", "count", NULL,
json_integer (NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT));
} else if ( nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE)
|| nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) {
json_element = json_array ();
json_array_append_new (json_element, json_string ("eth"));
json_array_append_new (json_element, json_string ("ipv4"));
json_array_append_new (json_element, json_string ("ipv6"));
_json_add_object (json, "runner", "tx_hash", NULL, json_element);
}
if (!add_implicit)
return;
if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP))
_json_add_object (json, "runner", "hwaddr_policy", NULL, json_string ("same_all"));
else if (NM_IN_STRSET (runner,
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
NM_SETTING_TEAM_RUNNER_LACP)) {
_json_add_object (json, "runner", "tx_balancer", "balancing_interval",
json_integer (NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT));
if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) {
_json_add_object (json, "runner", "active", NULL, json_boolean (TRUE));
_json_add_object (json, "runner", "sys_prio", NULL,
json_integer (NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT));
_json_add_object (json, "runner", "min_ports", NULL, json_integer (0));
_json_add_object (json, "runner", "agg_select_policy", NULL,
json_string (NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT));
}
}
}
static json_t *
_json_find_object (json_t *json,
const char *key1,
const char *key2,
const char *key3)
{
json_t *json_element;
if (!key1)
return NULL;
json_element = json_object_get (json, key1);
if (!key2 || !json_element)
return json_element;
json_element = json_object_get (json_element, key2);
if (!key3 || !json_element)
return json_element;
json_element = json_object_get (json_element, key3);
return json_element;
}
static void
_json_delete_object_on_int_match (json_t *json,
const char *key1,
const char *key2,
const char *key3,
int val)
{
json_t *json_element;
json_element = _json_find_object (json, key1, key2, key3);
if (!json_element || !json_is_integer (json_element))
return;
if (json_integer_value (json_element) == val)
_json_del_object (json, key1, key2, key3);
}
static void
_json_delete_object_on_bool_match (json_t *json,
const char *key1,
const char *key2,
const char *key3,
gboolean val)
{
json_t *json_element;
json_element = _json_find_object (json, key1, key2, key3);
if (!json_element || !json_is_boolean (json_element))
return;
if (json_boolean_value (json_element) == val)
_json_del_object (json, key1, key2, key3);
}
static void
_json_delete_object_on_string_match (json_t *json,
const char *key1,
const char *key2,
const char *key3,
const char *val)
{
json_t *json_element;
json_element = _json_find_object (json, key1, key2, key3);
if (!json_element || !json_is_string (json_element))
return;
if (nm_streq0 (json_string_value (json_element), val))
_json_del_object (json, key1, key2, key3);
}
static void
_json_team_normalize_defaults (json_t *json, gboolean reset)
{
json_t *json_element;
const char *runner = NM_SETTING_TEAM_RUNNER_DEFAULT;
gs_free char *runner_free = NULL;
int notify_peers_count = 0, notify_peers_interval = 0;
int mcast_rejoin_count = 0, mcast_rejoin_interval = 0;
int runner_tx_balancer_interval = -1;
gboolean runner_active = FALSE, runner_fast_rate = FALSE;
int runner_sys_prio = -1, runner_min_ports = -1;
json_element = _json_find_object (json, "runner", "name", NULL);
if (json_element) {
runner_free = g_strdup (json_string_value (json_element));
runner = runner_free;
_json_delete_object_on_string_match (json, "runner", "name", NULL,
NM_SETTING_TEAM_RUNNER_DEFAULT);
}
/* the runner changed: clear all the properties. Then team.config will be saved
* and reloaded triggering the reset of the values through _nm_utils_team_config_get
*/
if (reset) {
_json_del_object (json, "notify_peers", "count", NULL);
_json_del_object (json, "notify_peers", "interval", NULL);
_json_del_object (json, "mcast_rejoin", "count", NULL);
_json_del_object (json, "mcast_rejoin", "interval", NULL);
_json_del_object (json, "runner", "hwaddr_policy", NULL);
_json_del_object (json, "runner", "tx_hash", NULL);
_json_del_object (json, "runner", "tx_balancer", "name");
_json_del_object (json, "runner", "tx_balancer", "balancing_interval");
_json_del_object (json, "runner", "active", NULL);
_json_del_object (json, "runner", "fast_rate", NULL);
_json_del_object (json, "runner", "sys_prio", NULL);
_json_del_object (json, "runner", "min_ports", NULL);
_json_del_object (json, "runner", "agg_select_policy", NULL);
return;
}
if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) {
notify_peers_count = 1;
mcast_rejoin_count = 1;
_json_delete_object_on_string_match (json, "runner", "hwaddr_policy", NULL,
NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_DEFAULT);
} else if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) {
runner_tx_balancer_interval = NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT;
runner_active = TRUE;
runner_sys_prio = NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT;
runner_min_ports = 0;
_json_delete_object_on_string_match (json, "runner", "agg_select_policy", NULL,
NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT);
} else if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE))
runner_tx_balancer_interval = 50;
_json_delete_object_on_int_match (json, "notify_peers", "count", NULL, notify_peers_count);
_json_delete_object_on_int_match (json, "notify_peers", "interval", NULL, notify_peers_interval);
_json_delete_object_on_int_match (json, "mcast_rejoin", "count", NULL, mcast_rejoin_count);
_json_delete_object_on_int_match (json, "macst_rejoin", "interval", NULL, mcast_rejoin_interval);
_json_delete_object_on_int_match (json, "runner", "tx_balancer", "balancing_interval",
runner_tx_balancer_interval);
_json_delete_object_on_int_match (json, "runner", "sys_prio", NULL, runner_sys_prio);
_json_delete_object_on_int_match (json, "runner", "min_ports", NULL, runner_min_ports);
_json_delete_object_on_bool_match (json, "runner", "active", NULL, runner_active);
_json_delete_object_on_bool_match (json, "runner", "active", NULL, runner_active);
_json_delete_object_on_bool_match (json, "runner", "fast_rate", NULL, runner_fast_rate);
}
static NMTeamLinkWatcher *
_nm_utils_team_link_watcher_from_json (json_t *json_element)
{
const char *j_key;
json_t *j_val;
gs_free char *name = NULL, *target_host = NULL, *source_host = NULL;
int val1 = 0, val2 = 0, val3 = 3, val4 = -1;
NMTeamLinkWatcherArpPingFlags flags = 0;
g_return_val_if_fail (json_element, NULL);
json_object_foreach (json_element, j_key, j_val) {
if (nm_streq (j_key, "name")) {
g_free (name);
name = strdup (json_string_value (j_val));
} else if (nm_streq (j_key, "target_host")) {
g_free (target_host);
target_host = strdup (json_string_value (j_val));
} else if (nm_streq (j_key, "source_host")) {
g_free (source_host);
source_host = strdup (json_string_value (j_val));
} else if (NM_IN_STRSET (j_key, "delay_up", "init_wait"))
val1 = json_integer_value (j_val);
else if (NM_IN_STRSET (j_key, "delay_down", "interval"))
val2 = json_integer_value (j_val);
else if (nm_streq (j_key, "missed_max"))
val3 = json_integer_value (j_val);
else if (nm_streq (j_key, "vlanid"))
val4 = json_integer_value (j_val);
else if (nm_streq (j_key, "validate_active")) {
if (json_is_true (j_val))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
} else if (nm_streq (j_key, "validate_inactive")) {
if (json_is_true (j_val))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE;
} else if (nm_streq (j_key, "send_always")) {
if (json_is_true (j_val))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
}
}
if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ETHTOOL))
return nm_team_link_watcher_new_ethtool (val1, val2, NULL);
else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, NULL);
else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
return nm_team_link_watcher_new_arp_ping2 (val1, val2, val3, val4, target_host,
source_host, flags, NULL);
} else
return NULL;
}
static json_t *
_nm_utils_team_link_watcher_to_json (NMTeamLinkWatcher *watcher)
{
const char *name;
int int_val;
const char *str_val;
NMTeamLinkWatcherArpPingFlags flags = 0;
json_t *json_element;
g_return_val_if_fail (watcher, NULL);
json_element = json_object ();
name = nm_team_link_watcher_get_name (watcher);
if (!name)
goto fail;
json_object_set_new (json_element, "name", json_string (name));
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
int_val = nm_team_link_watcher_get_delay_up (watcher);
if (int_val)
json_object_set_new (json_element, "delay_up", json_integer (int_val));
int_val = nm_team_link_watcher_get_delay_down (watcher);
if (int_val)
json_object_set_new (json_element, "delay_down", json_integer (int_val));
return json_element;
}
int_val = nm_team_link_watcher_get_init_wait (watcher);
if (int_val)
json_object_set_new (json_element, "init_wait", json_integer (int_val));
int_val = nm_team_link_watcher_get_interval (watcher);
if (int_val)
json_object_set_new (json_element, "interval", json_integer (int_val));
int_val = nm_team_link_watcher_get_missed_max (watcher);
if (int_val != 3)
json_object_set_new (json_element, "missed_max", json_integer (int_val));
str_val = nm_team_link_watcher_get_target_host (watcher);
if (!str_val)
goto fail;
json_object_set_new (json_element, "target_host", json_string (str_val));
if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
return json_element;
int_val = nm_team_link_watcher_get_vlanid (watcher);
if (int_val != -1)
json_object_set_new (json_element, "vlanid", json_integer (int_val));
str_val = nm_team_link_watcher_get_source_host (watcher);
if (!str_val)
goto fail;
json_object_set_new (json_element, "source_host", json_string (str_val));
flags = nm_team_link_watcher_get_flags (watcher);
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE)
json_object_set_new (json_element, "validate_active", json_string ("true"));
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE)
json_object_set_new (json_element, "validate_inactive", json_string ("true"));
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS)
json_object_set_new (json_element, "send_always", json_string ("true"));
return json_element;
fail:
json_decref (json_element);
return NULL;
}
/**
* nm_utils_is_json_object:
* @str: the JSON string to test
@ -5816,6 +5393,7 @@ fail:
gboolean
nm_utils_is_json_object (const char *str, GError **error)
{
#if WITH_JSON_VALIDATION
json_t *json;
json_error_t jerror;
@ -5855,305 +5433,7 @@ nm_utils_is_json_object (const char *str, GError **error)
json_decref (json);
return TRUE;
}
gboolean
_nm_utils_team_config_equal (const char *conf1,
const char *conf2,
gboolean port_config)
{
json_t *json1 = NULL, *json2 = NULL, *json;
gs_free char *dump1 = NULL, *dump2 = NULL;
json_t *value;
json_error_t jerror;
const char *key;
gboolean ret;
void *tmp;
int i;
if (nm_streq0 (conf1, conf2))
return TRUE;
else if (!nm_jansson_load ())
return FALSE;
/* A NULL configuration is equivalent to default value '{}' */
json1 = json_loads (conf1 ?: "{}", JSON_REJECT_DUPLICATES, &jerror);
if (json1)
json2 = json_loads (conf2 ?: "{}", JSON_REJECT_DUPLICATES, &jerror);
if (!json1 || !json2) {
ret = FALSE;
goto out;
}
/* Some properties are added by teamd when missing from the initial
* configuration. Add them with the default value if necessary, depending
* on the configuration type.
*/
for (i = 0, json = json1; i < 2; i++, json = json2)
_json_team_add_defaults (json, port_config, FALSE);
/* Only consider a given subset of nodes, others can change depending on
* current state */
for (i = 0, json = json1; i < 2; i++, json = json2) {
json_object_foreach_safe (json, tmp, key, value) {
if (!NM_IN_STRSET (key, "runner", "link_watch"))
json_object_del (json, key);
}
}
dump1 = json_dumps (json1, JSON_INDENT(0) | JSON_ENSURE_ASCII | JSON_SORT_KEYS);
dump2 = json_dumps (json2, JSON_INDENT(0) | JSON_ENSURE_ASCII | JSON_SORT_KEYS);
ret = nm_streq0 (dump1, dump2);
out:
if (json1)
json_decref (json1);
if (json2)
json_decref (json2);
return ret;
}
GValue *
_nm_utils_team_config_get (const char *conf,
const char *key,
const char *key2,
const char *key3,
gboolean port_config)
{
json_t *json;
json_t *json_element;
GValue *value = NULL;
json_error_t jerror;
if (!key)
return NULL;
if (!nm_jansson_load ())
return NULL;
json = json_loads (conf ?: "{}", JSON_REJECT_DUPLICATES, &jerror);
/* Invalid json in conf */
if (!json)
return NULL;
/* Some properties are added by teamd when missing from the initial
* configuration. Add them with the default value if necessary, depending
* on the configuration type.
* Skip this for port config, as some properties change on the basis of the
* runner specified in the master connection... but we don't want to check
* against properties in another connection. Moreover, for team-port we have
* the link-watchers property only here: and for this compound property it is
* fine to show the default value only if explicitly set.
*/
if (!port_config)
_json_team_add_defaults (json, port_config, TRUE);
/* Now search the property to retrieve */
json_element = json_object_get (json, key);
if (json_element && key2)
json_element = json_object_get (json_element, key2);
if (json_element && key3)
json_element = json_object_get (json_element, key3);
if (json_element) {
value = g_new0 (GValue, 1);
if (json_is_string (json_element)) {
g_value_init (value, G_TYPE_STRING);
g_value_set_string (value, json_string_value (json_element));
} else if (json_is_integer (json_element)) {
g_value_init (value, G_TYPE_INT);
g_value_set_int (value, json_integer_value (json_element));
} else if (json_is_boolean (json_element)) {
g_value_init (value, G_TYPE_BOOLEAN);
g_value_set_boolean (value, json_boolean_value (json_element));
} else if (nm_streq (key, "link_watch")) {
NMTeamLinkWatcher *watcher;
GPtrArray *data = g_ptr_array_new_with_free_func
((GDestroyNotify) nm_team_link_watcher_unref);
if (json_is_array (json_element)) {
json_t *j_watcher;
int index;
json_array_foreach (json_element, index, j_watcher) {
watcher = _nm_utils_team_link_watcher_from_json (j_watcher);
if (watcher)
g_ptr_array_add (data, watcher);
}
} else {
watcher = _nm_utils_team_link_watcher_from_json (json_element);
if (watcher)
g_ptr_array_add (data, watcher);
}
if (data->len) {
g_value_init (value, G_TYPE_PTR_ARRAY);
g_value_take_boxed (value, data);
} else
g_ptr_array_free (data, TRUE);
} else if (json_is_array (json_element)) {
GPtrArray *data = g_ptr_array_new_with_free_func (g_free);
json_t *str_element;
int index;
json_array_foreach (json_element, index, str_element) {
if (json_is_string (str_element))
g_ptr_array_add (data, g_strdup (json_string_value (str_element)));
}
g_ptr_array_add (data, NULL);
g_value_init (value, G_TYPE_STRV);
g_value_take_boxed (value, g_ptr_array_free (data, FALSE));
} else {
g_assert_not_reached ();
g_free (value);
value = NULL;
}
}
if (json)
json_decref (json);
return value;
}
/* if conf is updated in place returns TRUE */
gboolean
_nm_utils_team_config_set (char **conf,
const char *key,
const char *key2,
const char *key3,
const GValue *value)
{
nm_auto_decref_json json_t *json = NULL;
nm_auto_decref_json json_t *json_value = NULL;
json_t *json_element;
json_t *json_link;
json_error_t jerror;
const char *iter_key = key;
gs_free char *conf_new = NULL;
g_return_val_if_fail (key, FALSE);
if (!nm_jansson_load ())
return FALSE;
json = json_loads (*conf?: "{}", JSON_REJECT_DUPLICATES, &jerror);
if (!json)
return FALSE;
if (!value) {
if (!_json_del_object (json, key, key2, key3))
return FALSE;
goto done;
}
if (G_VALUE_HOLDS_STRING (value))
json_value = json_string (g_value_get_string (value));
else if (G_VALUE_HOLDS_INT (value))
json_value = json_integer (g_value_get_int (value));
else if (G_VALUE_HOLDS_BOOLEAN (value))
json_value = json_boolean (g_value_get_boolean (value));
else if (G_VALUE_HOLDS_BOXED (value)) {
if (nm_streq (key, "link_watch")) {
gboolean has_array = FALSE;
GPtrArray *array;
guint i;
array = g_value_get_boxed (value);
if (!array || !array->len)
return FALSE;
for (i = 0; i < array->len; i++) {
json_t *el;
el = _nm_utils_team_link_watcher_to_json (array->pdata[i]);
if (!el)
continue;
/* if there is only one watcher, it is added as-is. If there
* are multiple watchers, they are added in an array. */
if (!json_value) {
json_value = el;
continue;
}
if (!has_array) {
json_t *el_arr;
has_array = TRUE;
el_arr = json_array();
json_array_append_new (el_arr, json_value);
json_value = el_arr;
}
json_array_append_new (json_value, el);
}
} else if ( nm_streq (key, "runner")
&& nm_streq0 (key2, "tx_hash")) {
const char *const*strv;
gsize i;
strv = g_value_get_boxed (value);
if (!strv)
return FALSE;
json_value = json_array ();
for (i = 0; strv[i]; i++)
json_array_append_new (json_value, json_string (strv[i]));
} else {
nm_assert_not_reached ();
return FALSE;
}
} else { /* G_VALUE_HOLDS_? */
nm_assert_not_reached ();
return FALSE;
}
/* Simplest case: first level key only */
json_element = json;
json_link = NULL;
if (key2) {
json_link = json;
json_element = json_object_get (json, iter_key);
if (!json_element) {
json_element = json_object ();
json_object_set_new (json_link, iter_key, json_element);
}
iter_key = key2;
}
if (key3) {
json_link = json_element;
json_element = json_object_get (json_link, iter_key);
if (!json_element) {
json_element = json_object ();
json_object_set_new (json_link, iter_key, json_element);
}
iter_key = key3;
}
json_object_set_new (json_element, iter_key, g_steal_pointer (&json_value));
done:
_json_team_normalize_defaults (json, ( nm_streq0 (key, "runner")
&& nm_streq0 (key2, "name")));
conf_new = json_dumps (json, JSON_PRESERVE_ORDER);
if (nm_streq0 (conf_new, "{}"))
nm_clear_g_free (&conf_new);
if (nm_streq0 (conf_new, *conf))
return FALSE;
g_free (*conf);
*conf = g_steal_pointer (&conf_new);
return TRUE;
}
#else /* !WITH_JSON_VALIDATION */
gboolean
nm_utils_is_json_object (const char *str, GError **error)
{
g_return_val_if_fail (!error || !*error, FALSE);
if (!str || !str[0]) {
@ -6165,239 +5445,7 @@ nm_utils_is_json_object (const char *str, GError **error)
}
return _nm_utils_is_json_object_no_validation (str, error);
}
gboolean
_nm_utils_team_config_equal (const char *conf1,
const char *conf2,
gboolean port_config)
{
return nm_streq0 (conf1, conf2);
}
GValue *
_nm_utils_team_config_get (const char *conf,
const char *key,
const char *key2,
const char *key3,
gboolean port_config)
{
return NULL;
}
gboolean
_nm_utils_team_config_set (char **conf,
const char *key,
const char *key2,
const char *key3,
const GValue *value)
{
return FALSE;
}
#endif
/**
* _nm_utils_team_link_watchers_to_variant:
* @link_watchers: (element-type NMTeamLinkWatcher): array of #NMTeamLinkWatcher
*
* Utility function to convert a #GPtrArray of #NMTeamLinkWatcher objects
* representing link watcher configuration for team devices into a #GVariant
* of type 'aa{sv}' representing an array of link watchers.
*
* Returns: (transfer none): a new floating #GVariant representing link watchers.
**/
GVariant *
_nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers)
{
GVariantBuilder builder;
int i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
if (!link_watchers)
goto end;
for (i = 0; i < link_watchers->len; i++) {
NMTeamLinkWatcher *watcher = link_watchers->pdata[i];
GVariantBuilder watcher_builder;
const char *name;
int int_val;
NMTeamLinkWatcherArpPingFlags flags;
g_variant_builder_init (&watcher_builder, G_VARIANT_TYPE ("a{sv}"));
name = nm_team_link_watcher_get_name (watcher);
g_variant_builder_add (&watcher_builder, "{sv}",
"name",
g_variant_new_string (name));
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
int_val = nm_team_link_watcher_get_delay_up (watcher);
if (int_val) {
g_variant_builder_add (&watcher_builder, "{sv}",
"delay-up",
g_variant_new_int32 (int_val));
}
int_val = nm_team_link_watcher_get_delay_down (watcher);
if (int_val) {
g_variant_builder_add (&watcher_builder, "{sv}",
"delay-down",
g_variant_new_int32 (int_val));
}
g_variant_builder_add (&builder, "a{sv}", &watcher_builder);
continue;
}
/* Common properties for arp_ping and nsna_ping link watchers */
int_val = nm_team_link_watcher_get_init_wait (watcher);
if (int_val) {
g_variant_builder_add (&watcher_builder, "{sv}",
"init-wait",
g_variant_new_int32 (int_val));
}
int_val = nm_team_link_watcher_get_interval (watcher);
if (int_val) {
g_variant_builder_add (&watcher_builder, "{sv}",
"interval",
g_variant_new_int32 (int_val));
}
int_val = nm_team_link_watcher_get_missed_max (watcher);
if (int_val != 3) {
g_variant_builder_add (&watcher_builder, "{sv}",
"missed-max",
g_variant_new_int32 (int_val));
}
g_variant_builder_add (&watcher_builder, "{sv}",
"target-host",
g_variant_new_string (nm_team_link_watcher_get_target_host (watcher)));
if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) {
g_variant_builder_add (&builder, "a{sv}", &watcher_builder);
continue;
}
/* arp_ping watcher only */
int_val = nm_team_link_watcher_get_vlanid (watcher);
if (int_val != -1) {
g_variant_builder_add (&watcher_builder, "{sv}",
"vlanid",
g_variant_new_int32 (int_val));
}
g_variant_builder_add (&watcher_builder, "{sv}",
"source-host",
g_variant_new_string (nm_team_link_watcher_get_source_host (watcher)));
flags = nm_team_link_watcher_get_flags (watcher);
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE) {
g_variant_builder_add (&watcher_builder, "{sv}",
"validate-active",
g_variant_new_boolean (TRUE));
}
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE) {
g_variant_builder_add (&watcher_builder, "{sv}",
"validate-inactive",
g_variant_new_boolean (TRUE));
}
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS) {
g_variant_builder_add (&watcher_builder, "{sv}",
"send-always",
g_variant_new_boolean (TRUE));
}
g_variant_builder_add (&builder, "a{sv}", &watcher_builder);
}
end:
return g_variant_builder_end (&builder);
}
/**
* _nm_utils_team_link_watchers_from_variant:
* @value: a #GVariant of type 'aa{sv}'
*
* Utility function to convert a #GVariant representing a list of team link
* watchers int a #GPtrArray of #NMTeamLinkWatcher objects.
*
* Returns: (transfer full) (element-type NMTeamLinkWatcher): a newly allocated
* #GPtrArray of #NMTeamLinkWatcher objects.
**/
GPtrArray *
_nm_utils_team_link_watchers_from_variant (GVariant *value)
{
GPtrArray *link_watchers;
GVariantIter iter;
GVariant *watcher_var;
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
g_variant_iter_init (&iter, value);
while (g_variant_iter_next (&iter, "@a{sv}", &watcher_var)) {
NMTeamLinkWatcher *watcher;
const char *name;
int val1, val2, val3 = 0, val4 = -1;
const char *target_host = NULL, *source_host = NULL;
gboolean bval;
NMTeamLinkWatcherArpPingFlags flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE;
GError *error = NULL;
if (!g_variant_lookup (watcher_var, "name", "&s", &name))
goto next;
if (!NM_IN_STRSET (name,
NM_TEAM_LINK_WATCHER_ETHTOOL,
NM_TEAM_LINK_WATCHER_ARP_PING,
NM_TEAM_LINK_WATCHER_NSNA_PING)) {
goto next;
}
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
if (!g_variant_lookup (watcher_var, "delay-up", "i", &val1))
val1 = 0;
if (!g_variant_lookup (watcher_var, "delay-down", "i", &val2))
val2 = 0;
watcher = nm_team_link_watcher_new_ethtool (val1, val2, &error);
} else {
if (!g_variant_lookup (watcher_var, "target-host", "&s", &target_host))
goto next;
if (!g_variant_lookup (watcher_var, "init_wait", "i", &val1))
val1 = 0;
if (!g_variant_lookup (watcher_var, "interval", "i", &val2))
val2 = 0;
if (!g_variant_lookup (watcher_var, "missed-max", "i", &val3))
val3 = 3;
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
if (!g_variant_lookup (watcher_var, "vlanid", "i", &val4))
val4 = -1;
if (!g_variant_lookup (watcher_var, "source-host", "&s", &source_host))
goto next;
if (!g_variant_lookup (watcher_var, "validate-active", "b", &bval))
bval = FALSE;
if (bval)
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
if (!g_variant_lookup (watcher_var, "validate-inactive", "b", &bval))
bval = FALSE;
if (bval)
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE;
if (!g_variant_lookup (watcher_var, "send-always", "b", &bval))
bval = FALSE;
if (bval)
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
watcher = nm_team_link_watcher_new_arp_ping2 (val1, val2, val3, val4,
target_host, source_host,
flags, &error);
} else
watcher = nm_team_link_watcher_new_nsna_ping (val1, val2, val3,
target_host, &error);
}
if (!watcher) {
g_clear_error (&error);
goto next;
}
g_ptr_array_add (link_watchers, watcher);
next:
g_variant_unref (watcher_var);
}
return link_watchers;
}
static char *

View file

@ -32,6 +32,7 @@
#include "nm-utils-private.h"
#include "nm-core-internal.h"
#include "nm-core-tests-enum-types.h"
#include "nm-team-utils.h"
#include "nm-setting-8021x.h"
#include "nm-setting-adsl.h"
@ -6807,14 +6808,42 @@ _team_config_equal_check (const char *conf1,
gboolean port_config,
gboolean expected)
{
g_assert_cmpint (_nm_utils_team_config_equal (conf1, conf2, port_config), ==, expected);
nm_auto_free_team_setting NMTeamSetting *team_a = NULL;
nm_auto_free_team_setting NMTeamSetting *team_b = NULL;
gboolean is_same;
if (nmtst_get_rand_bool ())
NMTST_SWAP (conf1, conf2);
if (!nm_streq0 (conf1, conf2)) {
_team_config_equal_check (conf1, conf1, port_config, TRUE);
_team_config_equal_check (conf2, conf2, port_config, TRUE);
}
team_a = nm_team_setting_new (port_config, conf1);
team_b = nm_team_setting_new (port_config, conf2);
is_same = (nm_team_setting_cmp (team_a, team_b, TRUE) == 0);
g_assert_cmpint (is_same, ==, expected);
if (nm_streq0 (conf1, conf2)) {
g_assert_cmpint (nm_team_setting_cmp (team_a, team_b, FALSE), ==, 0);
g_assert (expected);
} else
g_assert_cmpint (nm_team_setting_cmp (team_a, team_b, FALSE), !=, 0);
}
static void
test_nm_utils_team_config_equal (void)
{
#if WITH_JSON_VALIDATION
_team_config_equal_check ("", "", TRUE, TRUE);
_team_config_equal_check ("",
"",
TRUE,
TRUE);
_team_config_equal_check ("",
" ",
TRUE,
TRUE);
_team_config_equal_check ("{}",
"{ }",
TRUE,
@ -6822,7 +6851,15 @@ test_nm_utils_team_config_equal (void)
_team_config_equal_check ("{}",
"{",
TRUE,
FALSE);
TRUE);
_team_config_equal_check ("{ \"a\": 1 }",
"{ \"a\": 1 }",
TRUE,
TRUE);
_team_config_equal_check ("{ \"a\": 1 }",
"{ \"a\": 1 }",
TRUE,
TRUE);
/* team config */
_team_config_equal_check ("{ }",
@ -6832,11 +6869,11 @@ test_nm_utils_team_config_equal (void)
_team_config_equal_check ("{ }",
"{ \"runner\" : { \"name\" : \"random\"} }",
FALSE,
FALSE);
!WITH_JSON_VALIDATION);
_team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }",
"{ \"runner\" : { \"name\" : \"random\"} }",
FALSE,
FALSE);
!WITH_JSON_VALIDATION);
_team_config_equal_check ("{ \"runner\" : { \"name\" : \"random\"} }",
"{ \"runner\" : { \"name\" : \"random\"} }",
FALSE,
@ -6856,11 +6893,11 @@ test_nm_utils_team_config_equal (void)
_team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }",
"{ \"runner\" : { \"name\" : \"roundrobin\", \"tx_hash\" : [ \"eth\", \"ipv4\", \"ipv6\" ] } }",
FALSE,
FALSE);
!WITH_JSON_VALIDATION);
_team_config_equal_check ("{ \"runner\" : { \"name\" : \"lacp\"} }",
"{ \"runner\" : { \"name\" : \"lacp\", \"tx_hash\" : [ \"eth\" ] } }",
FALSE,
FALSE);
!WITH_JSON_VALIDATION);
/* team port config */
_team_config_equal_check ("{ }",
@ -6870,11 +6907,11 @@ test_nm_utils_team_config_equal (void)
_team_config_equal_check ("{ }",
"{ \"link_watch\" : { \"name\" : \"arp_ping\"} }",
TRUE,
FALSE);
TRUE);
_team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"ethtool\"} }",
"{ \"link_watch\" : { \"name\" : \"arp_ping\"} }",
TRUE,
FALSE);
TRUE);
_team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"arp_ping\"} }",
"{ \"link_watch\" : { \"name\" : \"arp_ping\"} }",
TRUE,
@ -6883,13 +6920,6 @@ test_nm_utils_team_config_equal (void)
"{ \"link_watch\" : { \"name\" : \"arp_ping\"}, \"ports\" : { \"eth1\" : {} } }",
TRUE,
TRUE);
#else
/* Without JSON library, strings are compared for equality */
_team_config_equal_check ("", "", TRUE, TRUE);
_team_config_equal_check ("", " ", TRUE, FALSE);
_team_config_equal_check ("{ \"a\": 1 }", "{ \"a\": 1 }", TRUE, TRUE);
_team_config_equal_check ("{ \"a\": 1 }", "{ \"a\": 1 }", TRUE, FALSE);
#endif
}
/*****************************************************************************/

View file

@ -626,11 +626,15 @@ test_team_conf_read_valid (void)
static void
test_team_conf_read_invalid (void)
{
#if WITH_JSON_VALIDATION
GKeyFile *keyfile = NULL;
gs_unref_object NMConnection *con = NULL;
NMSettingTeam *s_team;
if (!WITH_JSON_VALIDATION) {
g_test_skip ("team test requires JSON validation");
return;
}
con = nmtst_create_connection_from_keyfile (
"[connection]\n"
"type=team\n"
@ -645,7 +649,6 @@ test_team_conf_read_invalid (void)
g_assert (nm_setting_team_get_config (s_team) == NULL);
CLEAR (&con, &keyfile);
#endif
}
/*****************************************************************************/

View file

@ -45,6 +45,15 @@
/*****************************************************************************/
/* assert that the define is just a plain integer (boolean). */
G_STATIC_ASSERT ( (WITH_JSON_VALIDATION) == 1
|| (WITH_JSON_VALIDATION) == 0);
_nm_unused static const int _with_json_validation = WITH_JSON_VALIDATION;
/*****************************************************************************/
/* converts @dict to a connection. In this case, @dict must be good, without warnings, so that
* NM_SETTING_PARSE_FLAGS_STRICT and NM_SETTING_PARSE_FLAGS_BEST_EFFORT yield the exact same results. */
static NMConnection *
@ -966,7 +975,6 @@ test_dcb_bandwidth_sums (void)
/*****************************************************************************/
#if WITH_JSON_VALIDATION
static void
_test_team_config_sync (const char *team_config,
int notify_peer_count,
@ -989,26 +997,31 @@ _test_team_config_sync (const char *team_config,
guint i, j;
gboolean found;
if (!WITH_JSON_VALIDATION) {
g_test_skip ("team test requires JSON validation");
return;
}
s_team = (NMSettingTeam *) nm_setting_team_new ();
g_assert (s_team);
g_object_set (s_team, NM_SETTING_TEAM_CONFIG, team_config, NULL);
g_assert (nm_setting_team_get_notify_peers_count (s_team) == notify_peer_count);
g_assert (nm_setting_team_get_notify_peers_interval (s_team) == notify_peers_interval);
g_assert (nm_setting_team_get_mcast_rejoin_count (s_team) == mcast_rejoin_count);
g_assert (nm_setting_team_get_mcast_rejoin_interval (s_team) == mcast_rejoin_interval);
g_assert (nm_setting_team_get_runner_tx_balancer_interval (s_team) == runner_tx_balancer_interval);
g_assert (nm_setting_team_get_runner_active (s_team) == runner_active);
g_assert (nm_setting_team_get_runner_fast_rate (s_team) == runner_fast_rate);
g_assert (nm_setting_team_get_runner_sys_prio (s_team) == runner_sys_prio);
g_assert (nm_setting_team_get_runner_min_ports (s_team) == runner_min_ports);
g_assert (nm_streq0 (nm_setting_team_get_runner (s_team), runner));
g_assert (nm_streq0 (nm_setting_team_get_runner_hwaddr_policy (s_team), runner_hwaddr_policy));
g_assert (nm_streq0 (nm_setting_team_get_runner_tx_balancer (s_team), runner_tx_balancer));
g_assert (nm_streq0 (nm_setting_team_get_runner_agg_select_policy (s_team), runner_agg_select_policy));
g_assert_cmpint (nm_setting_team_get_notify_peers_count (s_team), ==, notify_peer_count);
g_assert_cmpint (nm_setting_team_get_notify_peers_interval (s_team), ==, notify_peers_interval);
g_assert_cmpint (nm_setting_team_get_mcast_rejoin_count (s_team), ==, mcast_rejoin_count);
g_assert_cmpint (nm_setting_team_get_mcast_rejoin_interval (s_team), ==, mcast_rejoin_interval);
g_assert_cmpint (nm_setting_team_get_runner_tx_balancer_interval (s_team), ==, runner_tx_balancer_interval);
g_assert_cmpint (nm_setting_team_get_runner_active (s_team), ==, runner_active);
g_assert_cmpint (nm_setting_team_get_runner_fast_rate (s_team), ==, runner_fast_rate);
g_assert_cmpint (nm_setting_team_get_runner_sys_prio (s_team), ==, runner_sys_prio);
g_assert_cmpint (nm_setting_team_get_runner_min_ports (s_team), ==, runner_min_ports);
g_assert_cmpstr (nm_setting_team_get_runner (s_team), ==, runner);
g_assert_cmpstr (nm_setting_team_get_runner_hwaddr_policy (s_team), ==, runner_hwaddr_policy);
g_assert_cmpstr (nm_setting_team_get_runner_tx_balancer (s_team), ==, runner_tx_balancer);
g_assert_cmpstr (nm_setting_team_get_runner_agg_select_policy (s_team), ==, runner_agg_select_policy);
if (runner_tx_hash) {
g_assert (runner_tx_hash->len == nm_setting_team_get_num_runner_tx_hash (s_team));
g_assert_cmpint (runner_tx_hash->len, ==, nm_setting_team_get_num_runner_tx_hash (s_team));
for (i = 0; i < runner_tx_hash->len; i++) {
found = FALSE;
for (j = 0; j < nm_setting_team_get_num_runner_tx_hash (s_team); j++) {
@ -1023,7 +1036,7 @@ _test_team_config_sync (const char *team_config,
}
if (link_watchers) {
g_assert (link_watchers->len == nm_setting_team_get_num_link_watchers (s_team));
g_assert_cmpint (link_watchers->len, ==, nm_setting_team_get_num_link_watchers (s_team));
for (i = 0; i < link_watchers->len; i++) {
found = FALSE;
for (j = 0; j < nm_setting_team_get_num_link_watchers (s_team); j++) {
@ -1250,6 +1263,11 @@ _test_team_port_config_sync (const char *team_port_config,
guint i, j;
gboolean found;
if (!WITH_JSON_VALIDATION) {
g_test_skip ("team test requires JSON validation");
return;
}
s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new ();
g_assert (s_team_port);
@ -1354,7 +1372,134 @@ test_team_port_full_config (void)
"\"send_always\": true}]}",
10, 20, true, 30, 40, NULL);
}
#endif
/*****************************************************************************/
static void
_check_team_setting (NMSetting *setting)
{
gs_unref_object NMSetting *setting2 = NULL;
gs_unref_object NMSetting *setting_clone = NULL;
gboolean is_port = NM_IS_SETTING_TEAM_PORT (setting);
gs_unref_variant GVariant *variant2 = NULL;
gs_unref_variant GVariant *variant3 = NULL;
g_assert (NM_IS_SETTING_TEAM (setting) || is_port);
setting_clone = nm_setting_duplicate (setting);
if (!is_port) {
if (nm_setting_team_get_runner (NM_SETTING_TEAM (setting)) == NULL) {
/* such a setting is invalid. We must first coerce it so that it becomes
* valid. */
setting = setting_clone;
g_object_set (setting,
NM_SETTING_TEAM_RUNNER,
NM_SETTING_TEAM_RUNNER_DEFAULT,
NULL);
}
}
setting2 = g_object_new (G_OBJECT_TYPE (setting),
is_port
? NM_SETTING_TEAM_PORT_CONFIG
: NM_SETTING_TEAM_CONFIG,
is_port
? nm_setting_team_port_get_config (NM_SETTING_TEAM_PORT (setting))
: nm_setting_team_get_config (NM_SETTING_TEAM (setting)),
NULL);
if (WITH_JSON_VALIDATION)
nmtst_assert_setting_is_equal (setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT);
g_clear_object (&setting2);
nmtst_assert_setting_dbus_roundtrip (setting);
/* OK, now parse the setting only from the D-Bus variant, but removing the JSON config.
* For that, we have to "drop" the JSON and we do that by resetting the property.
* This causes JSON to be regenerated and it's in a normalized form that will compare
* equal. */
setting = setting_clone;
if (is_port) {
g_object_set (setting,
NM_SETTING_TEAM_PORT_STICKY,
nm_setting_team_port_get_sticky (NM_SETTING_TEAM_PORT (setting)),
NULL);
} else {
g_object_set (setting,
NM_SETTING_TEAM_RUNNER_SYS_PRIO,
nm_setting_team_get_runner_sys_prio (NM_SETTING_TEAM (setting)),
NULL);
}
variant2 = _nm_setting_to_dbus (setting, NULL, NM_CONNECTION_SERIALIZE_ALL);
variant3 = nm_utils_gvariant_vardict_filter_drop_one (variant2, "config");
setting2 = nmtst_assert_setting_dbus_new (G_OBJECT_TYPE (setting), variant3);
nmtst_assert_setting_is_equal (setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT);
}
static void
test_team_setting (void)
{
gs_unref_variant GVariant *variant = nmtst_variant_from_string (G_VARIANT_TYPE_VARDICT,
"{'config': <'{\"link_watch\": {\"name\": \"ethtool\"}}'>, 'interface-name': <'nm-team'>, 'link-watchers': <[{'name': <'ethtool'>}]>, 'runner': <'roundrobin'>, 'runner-min-ports': <-1>, 'runner-sys-prio': <-1>, 'runner-tx-balancer-interval': <-1>}");
gs_free_error GError *error = NULL;
gs_unref_object NMSetting *setting = NULL;
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher1 = nm_team_link_watcher_new_nsna_ping (1, 3, 4, "bbb", NULL);
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher2 = nm_team_link_watcher_new_arp_ping2 (1, 3, 4, -1, "ccc", "ddd", 0, NULL);
g_assert (watcher1);
g_assert (watcher2);
setting = _nm_setting_new_from_dbus (NM_TYPE_SETTING_TEAM,
variant,
NULL,
NM_SETTING_PARSE_FLAGS_STRICT,
&error);
nmtst_assert_success (setting, error);
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}}");
g_assert_cmpint (nm_setting_team_get_num_link_watchers (NM_SETTING_TEAM (setting)), ==, 1);
g_object_set (setting,
NM_SETTING_TEAM_RUNNER_SYS_PRIO,
(int) 10,
NULL);
_check_team_setting (setting);
g_assert_cmpint (nm_setting_team_get_num_link_watchers (NM_SETTING_TEAM (setting)), ==, 1);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"ethtool\"} }");
nm_setting_team_remove_link_watcher (NM_SETTING_TEAM (setting), 0);
_check_team_setting (setting);
g_assert_cmpint (nm_setting_team_get_num_link_watchers (NM_SETTING_TEAM (setting)), ==, 0);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 } }");
nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher1);
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4} }");
nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher2);
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": [ { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4}, { \"name\": \"arp_ping\", \"target_host\": \"ccc\", \"source_host\": \"ddd\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4} ] }");
nm_setting_team_remove_link_watcher (NM_SETTING_TEAM (setting), 0);
nm_setting_team_remove_link_watcher (NM_SETTING_TEAM (setting), 0);
g_object_set (setting,
NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL,
(int) 5,
NULL);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"tx_balancer\": { \"balancing_interval\": 5 }, \"sys_prio\": 10 } }");
g_object_set (setting,
NM_SETTING_TEAM_RUNNER,
NULL,
NULL);
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"tx_balancer\": { \"balancing_interval\": 5 }, \"sys_prio\": 10 } }");
}
/*****************************************************************************/
@ -3189,7 +3334,6 @@ main (int argc, char **argv)
g_test_add_func ("/libnm/settings/bridge/vlans", test_bridge_vlans);
#if WITH_JSON_VALIDATION
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",
@ -3218,7 +3362,6 @@ main (int argc, char **argv)
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);
#endif
g_test_add_data_func ("/libnm/settings/roundtrip-conversion/general/0", GINT_TO_POINTER (0), test_roundtrip_conversion);
g_test_add_data_func ("/libnm/settings/roundtrip-conversion/wireguard/1", GINT_TO_POINTER (1), test_roundtrip_conversion);
@ -3229,5 +3372,7 @@ main (int argc, char **argv)
g_test_add_func ("/libnm/parse-tc-handle", test_parse_tc_handle);
g_test_add_func ("/libnm/test_team_setting", test_team_setting);
return g_test_run ();
}

View file

@ -165,6 +165,8 @@ def get_default_value(setting, pspec, propxml):
default_value = '[]'
elif str(default_value).startswith('<'):
default_value = None
elif str(default_value).startswith('['):
default_value = None
return default_value

View file

@ -102,6 +102,7 @@ libnm-core/nm-setting-wireless-security.c
libnm-core/nm-setting-wireless.c
libnm-core/nm-setting-wpan.c
libnm-core/nm-setting.c
libnm-core/nm-team-utils.c
libnm-core/nm-utils.c
libnm-core/nm-vpn-editor-plugin.c
libnm-core/nm-vpn-plugin-info.c
@ -173,3 +174,4 @@ src/nm-logging.c
src/nm-manager.c
src/settings/plugins/ibft/nms-ibft-plugin.c
src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c

View file

@ -145,6 +145,7 @@ shared_nm_glib_aux = static_library(
'nm-glib-aux/nm-errno.c',
'nm-glib-aux/nm-hash-utils.c',
'nm-glib-aux/nm-io-utils.c',
'nm-glib-aux/nm-json-aux.c',
'nm-glib-aux/nm-keyfile-aux.c',
'nm-glib-aux/nm-random-utils.c',
'nm-glib-aux/nm-secret-utils.c',

View file

@ -44,6 +44,106 @@
NM_AUTO_DEFINE_FCN0 (json_t *, _nm_auto_decref_json, json_decref)
#define nm_auto_decref_json nm_auto(_nm_auto_decref_json)
/*****************************************************************************/
static inline int
nm_jansson_json_as_bool (const json_t *elem,
bool *out_val)
{
if (!elem)
return 0;
if (!json_is_boolean (elem))
return -EINVAL;
NM_SET_OUT (out_val, json_boolean_value (elem));
return 1;
}
static inline int
nm_jansson_json_as_int32 (const json_t *elem,
gint32 *out_val)
{
json_int_t v;
if (!elem)
return 0;
if (!json_is_integer (elem))
return -EINVAL;
v = json_integer_value (elem);
if ( v < (gint64) G_MININT32
|| v > (gint64) G_MAXINT32)
return -ERANGE;
NM_SET_OUT (out_val, v);
return 1;
}
static inline int
nm_jansson_json_as_int (const json_t *elem,
int *out_val)
{
json_int_t v;
if (!elem)
return 0;
if (!json_is_integer (elem))
return -EINVAL;
v = json_integer_value (elem);
if ( v < (gint64) G_MININT
|| v > (gint64) G_MAXINT)
return -ERANGE;
NM_SET_OUT (out_val, v);
return 1;
}
static inline int
nm_jansson_json_as_string (const json_t *elem,
const char **out_val)
{
if (!elem)
return 0;
if (!json_is_string (elem))
return -EINVAL;
NM_SET_OUT (out_val, json_string_value (elem));
return 1;
}
/*****************************************************************************/
#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS
#include "nm-value-type.h"
static inline gboolean
nm_value_type_from_json (NMValueType value_type,
const json_t *elem,
gpointer out_val)
{
switch (value_type) {
case NM_VALUE_TYPE_BOOL: return (nm_jansson_json_as_bool (elem, out_val) > 0);
case NM_VALUE_TYPE_INT32: return (nm_jansson_json_as_int32 (elem, out_val) > 0);
case NM_VALUE_TYPE_INT: return (nm_jansson_json_as_int (elem, out_val) > 0);
/* warning: this overwrites/leaks the previous value. You better have *out_val
* point to uninitialized memory or NULL. */
case NM_VALUE_TYPE_STRING: return (nm_jansson_json_as_string (elem, out_val) > 0);
case NM_VALUE_TYPE_UNSPEC:
break;
}
nm_assert_not_reached ();
return FALSE;
}
#endif
/*****************************************************************************/
#endif /* WITH_JANSON */
#endif /* __NM_JANSSON_H__ */

View file

@ -0,0 +1,149 @@
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2019 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-json-aux.h"
/*****************************************************************************/
static void
_gstr_append_string_len (GString *gstr,
const char *str,
gsize len)
{
g_string_append_c (gstr, '\"');
while (len > 0) {
gsize n;
const char *end;
gboolean valid;
nm_assert (len > 0);
valid = g_utf8_validate (str, len, &end);
nm_assert ( end
&& end >= str
&& end <= &str[len]);
if (end > str) {
const char *s;
for (s = str; s < end; s++) {
nm_assert (s[0] != '\0');
if (s[0] < 0x20) {
const char *text;
switch (s[0]) {
case '\\': text = "\\\\"; break;
case '\"': text = "\\\""; break;
case '\b': text = "\\b"; break;
case '\f': text = "\\f"; break;
case '\n': text = "\\n"; break;
case '\r': text = "\\r"; break;
case '\t': text = "\\t"; break;
default:
g_string_append_printf (gstr, "\\u%04X", (guint) s[0]);
continue;
}
g_string_append (gstr, text);
continue;
}
if (NM_IN_SET (s[0], '\\', '\"'))
g_string_append_c (gstr, '\\');
g_string_append_c (gstr, s[0]);
}
} else
nm_assert (!valid);
if (valid) {
nm_assert (end == &str[len]);
break;
}
nm_assert (end < &str[len]);
if (end[0] == '\0') {
/* there is a NUL byte in the string. Technically this is valid UTF-8, so we
* encode it there. However, this will likely result in a truncated string when
* parsing. */
g_string_append (gstr, "\\u0000");
} else {
/* the character is not valid UTF-8. There is nothing we can do about it, because
* JSON can only contain UTF-8 and even the escape sequences can only escape Unicode
* codepoints (but not binary).
*
* The argument is not a a string (in any known encoding), hence we cannot represent
* it as a JSON string (which are unicode strings).
*
* Print an underscore instead of the invalid char :) */
g_string_append_c (gstr, '_');
}
n = str - end;
nm_assert (n < len);
n++;
str += n;
len -= n;
}
g_string_append_c (gstr, '\"');
}
void
nm_json_aux_gstr_append_string_len (GString *gstr,
const char *str,
gsize n)
{
g_return_if_fail (gstr);
_gstr_append_string_len (gstr, str, n);
}
void
nm_json_aux_gstr_append_string (GString *gstr,
const char *str)
{
g_return_if_fail (gstr);
if (!str)
g_string_append (gstr, "null");
else
_gstr_append_string_len (gstr, str, strlen (str));
}
void
nm_json_aux_gstr_append_obj_name (GString *gstr,
const char *key,
char start_container)
{
g_return_if_fail (gstr);
g_return_if_fail (key);
nm_json_aux_gstr_append_string (gstr, key);
if (start_container != '\0') {
nm_assert (NM_IN_SET (start_container, '[', '{'));
g_string_append_printf (gstr, ": %c ", start_container);
} else
g_string_append (gstr, ": ");
}

View file

@ -0,0 +1,83 @@
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2019 Red Hat, Inc.
*/
#ifndef __NM_JSON_AUX_H__
#define __NM_JSON_AUX_H__
/*****************************************************************************/
static inline GString *
nm_json_aux_gstr_append_delimiter (GString *gstr)
{
g_string_append (gstr, ", ");
return gstr;
}
void nm_json_aux_gstr_append_string_len (GString *gstr,
const char *str,
gsize n);
void nm_json_aux_gstr_append_string (GString *gstr,
const char *str);
static inline void
nm_json_aux_gstr_append_bool (GString *gstr,
gboolean v)
{
g_string_append (gstr, v ? "true" : "false");
}
static inline void
nm_json_aux_gstr_append_int64 (GString *gstr,
gint64 v)
{
g_string_append_printf (gstr, "%"G_GINT64_FORMAT, v);
}
void nm_json_aux_gstr_append_obj_name (GString *gstr,
const char *key,
char start_container);
/*****************************************************************************/
#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS
#include "nm-value-type.h"
static inline void
nm_value_type_to_json (NMValueType value_type,
GString *gstr,
gconstpointer p_field)
{
nm_assert (p_field);
nm_assert (gstr);
switch (value_type) {
case NM_VALUE_TYPE_BOOL: nm_json_aux_gstr_append_bool (gstr, *((const bool *) p_field)); return;
case NM_VALUE_TYPE_INT32: nm_json_aux_gstr_append_int64 (gstr, *((const gint32 *) p_field)); return;
case NM_VALUE_TYPE_INT: nm_json_aux_gstr_append_int64 (gstr, *((const int *) p_field)); return;
case NM_VALUE_TYPE_STRING: nm_json_aux_gstr_append_string (gstr, *((const char *const *) p_field)); return;
case NM_VALUE_TYPE_UNSPEC:
break;
}
nm_assert_not_reached ();
}
#endif
/*****************************************************************************/
#endif /* __NM_JSON_AUX_H__ */

View file

@ -865,6 +865,28 @@ fcn (void) \
/*****************************************************************************/
static inline int
nm_strcmp0 (const char *s1, const char *s2)
{
int c;
/* like g_strcmp0(), but this is inlinable.
*
* Also, it is guaranteed to return either -1, 0, or 1. */
if (s1 == s2)
return 0;
if (!s1)
return -1;
if (!s2)
return 1;
c = strcmp (s1, s2);
if (c < 0)
return -1;
if (c > 0)
return 1;
return 0;
}
static inline gboolean
nm_streq (const char *s1, const char *s2)
{
@ -989,10 +1011,9 @@ typedef enum { \
} _PropertyEnums; \
static GParamSpec *obj_properties[_PROPERTY_ENUMS_LAST] = { NULL, }
#define NM_GOBJECT_PROPERTIES_DEFINE(obj_type, ...) \
NM_GOBJECT_PROPERTIES_DEFINE_BASE (__VA_ARGS__); \
#define NM_GOBJECT_PROPERTIES_DEFINE_NOTIFY(obj_type, obj_properties, property_enums_type, prop_0) \
static inline void \
_nm_gobject_notify_together_impl (obj_type *obj, guint n, const _PropertyEnums *props) \
_nm_gobject_notify_together_impl (obj_type *obj, guint n, const property_enums_type *props) \
{ \
const gboolean freeze_thaw = (n > 1); \
\
@ -1002,9 +1023,9 @@ _nm_gobject_notify_together_impl (obj_type *obj, guint n, const _PropertyEnums *
if (freeze_thaw) \
g_object_freeze_notify ((GObject *) obj); \
while (n-- > 0) { \
const _PropertyEnums prop = *props++; \
const property_enums_type prop = *props++; \
\
if (prop != PROP_0) { \
if (prop != prop_0) { \
nm_assert ((gsize) prop < G_N_ELEMENTS (obj_properties)); \
nm_assert (obj_properties[prop]); \
g_object_notify_by_pspec ((GObject *) obj, obj_properties[prop]); \
@ -1015,11 +1036,15 @@ _nm_gobject_notify_together_impl (obj_type *obj, guint n, const _PropertyEnums *
} \
\
static inline void \
_notify (obj_type *obj, _PropertyEnums prop) \
_notify (obj_type *obj, property_enums_type prop) \
{ \
_nm_gobject_notify_together_impl (obj, 1, &prop); \
} \
#define NM_GOBJECT_PROPERTIES_DEFINE(obj_type, ...) \
NM_GOBJECT_PROPERTIES_DEFINE_BASE (__VA_ARGS__); \
NM_GOBJECT_PROPERTIES_DEFINE_NOTIFY (obj_type, obj_properties, _PropertyEnums, PROP_0)
/* invokes _notify() for all arguments (of type _PropertyEnums). Note, that if
* there are more than one prop arguments, this will involve a freeze/thaw
* of GObject property notifications. */

View file

@ -2288,7 +2288,7 @@ nm_utils_strv_make_deep_copied (const char **strv)
{
gsize i;
/* it takes a strv dictionary, and copies each
/* it takes a strv list, and copies each
* strings. Note that this updates @strv *in-place*
* and returns it. */
@ -2300,6 +2300,23 @@ nm_utils_strv_make_deep_copied (const char **strv)
return (char **) strv;
}
char **
nm_utils_strv_make_deep_copied_n (const char **strv, gsize len)
{
gsize i;
/* it takes a strv array with len elements, and copies each
* strings. Note that this updates @strv *in-place*
* and returns it. */
if (!strv)
return NULL;
for (i = 0; i < len; i++)
strv[i] = g_strdup (strv[i]);
return (char **) strv;
}
/*****************************************************************************/
gssize
@ -3029,3 +3046,64 @@ fail:
NM_SET_OUT (out_len, 0);
return NULL;
}
/*****************************************************************************/
GVariant *
nm_utils_gvariant_vardict_filter (GVariant *src,
gboolean (*filter_fcn) (const char *key,
GVariant *val,
char **out_key,
GVariant **out_val,
gpointer user_data),
gpointer user_data)
{
GVariantIter iter;
GVariantBuilder builder;
const char *key;
GVariant *val;
g_return_val_if_fail (src && g_variant_is_of_type (src, G_VARIANT_TYPE_VARDICT), NULL);
g_return_val_if_fail (filter_fcn, NULL);
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
g_variant_iter_init (&iter, src);
while (g_variant_iter_next (&iter, "{&sv}", &key, &val)) {
_nm_unused gs_unref_variant GVariant *val_free = val;
gs_free char *key2 = NULL;
gs_unref_variant GVariant *val2 = NULL;
if (filter_fcn (key,
val,
&key2,
&val2,
user_data)) {
g_variant_builder_add (&builder,
"{sv}",
key2 ?: key,
val2 ?: val);
}
}
return g_variant_builder_end (&builder);
}
static gboolean
_gvariant_vardict_filter_drop_one (const char *key,
GVariant *val,
char **out_key,
GVariant **out_val,
gpointer user_data)
{
return !nm_streq (key, user_data);
}
GVariant *
nm_utils_gvariant_vardict_filter_drop_one (GVariant *src,
const char *key)
{
return nm_utils_gvariant_vardict_filter (src,
_gvariant_vardict_filter_drop_one,
(gpointer) key);
}

View file

@ -171,6 +171,13 @@ nm_ip4_addr_is_localhost (in_addr_t addr4)
return _cc < 0 ? -1 : 1; \
} G_STMT_END
#define NM_CMP_RETURN_DIRECT(c) \
G_STMT_START { \
const int _cc = (c); \
if (_cc) \
return _cc; \
} G_STMT_END
#define NM_CMP_SELF(a, b) \
G_STMT_START { \
typeof (a) _a = (a); \
@ -197,7 +204,7 @@ nm_ip4_addr_is_localhost (in_addr_t addr4)
NM_CMP_RETURN (memcmp ((a), (b), (size)))
#define NM_CMP_DIRECT_STRCMP0(a, b) \
NM_CMP_RETURN (g_strcmp0 ((a), (b)))
NM_CMP_RETURN_DIRECT (nm_strcmp0 ((a), (b)))
#define NM_CMP_DIRECT_IN6ADDR(a, b) \
G_STMT_START { \
@ -229,12 +236,12 @@ nm_ip4_addr_is_localhost (in_addr_t addr4)
const char *_b = ((b)->field); \
\
if (_a != _b) { \
NM_CMP_RETURN (g_strcmp0 (_a, _b)); \
NM_CMP_RETURN_DIRECT (nm_strcmp0 (_a, _b)); \
} \
} G_STMT_END
#define NM_CMP_FIELD_STR0(a, b, field) \
NM_CMP_RETURN (g_strcmp0 (((a)->field), ((b)->field)))
NM_CMP_RETURN_DIRECT (nm_strcmp0 (((a)->field), ((b)->field)))
#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \
NM_CMP_RETURN (memcmp (&((a)->field), &((b)->field), \
@ -305,6 +312,20 @@ GVariant *nm_utils_gbytes_to_variant_ay (GBytes *bytes);
/*****************************************************************************/
GVariant *nm_utils_gvariant_vardict_filter (GVariant *src,
gboolean (*filter_fcn) (const char *key,
GVariant *val,
char **out_key,
GVariant **out_val,
gpointer user_data),
gpointer user_data);
GVariant *
nm_utils_gvariant_vardict_filter_drop_one (GVariant *src,
const char *key);
/*****************************************************************************/
static inline int
nm_utils_hexchar_to_int (char ch)
{
@ -944,6 +965,8 @@ nm_utils_strdict_get_keys (const GHashTable *hash,
char **nm_utils_strv_make_deep_copied (const char **strv);
char **nm_utils_strv_make_deep_copied_n (const char **strv, gsize len);
static inline char **
nm_utils_strv_make_deep_copied_nonnull (const char **strv)
{

View file

@ -0,0 +1,206 @@
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2019 Red Hat, Inc.
*/
#ifndef __NM_VALUE_TYPE_H__
#define __NM_VALUE_TYPE_H__
typedef enum {
NM_VALUE_TYPE_UNSPEC = 1,
NM_VALUE_TYPE_BOOL = 2,
NM_VALUE_TYPE_INT32 = 3,
NM_VALUE_TYPE_INT = 4,
NM_VALUE_TYPE_STRING = 5,
} NMValueType;
/*****************************************************************************/
#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS
typedef union {
bool v_bool;
gint32 v_int32;
int v_int;
const char *v_string;
/* for convenience, also let the union contain other pointer types. These are
* for NM_VALUE_TYPE_UNSPEC. */
gconstpointer *v_ptr;
const GPtrArray *v_ptrarray;
} NMValueTypUnion;
/* Set the NMValueTypUnion. You can also assign the member directly.
* The only purpose of this is that it also returns a pointer to the
* union. So, you can do
*
* ptr = NM_VALUE_TYP_UNION_SET (&value_typ_union_storage, v_bool, TRUE);
*/
#define NM_VALUE_TYP_UNION_SET(_arg, _type, _val) \
({ \
NMValueTypUnion *const _arg2 = (_arg); \
\
*_arg2 = (NMValueTypUnion) { \
._type = (_val), \
}; \
_arg2; \
})
typedef struct {
bool has;
NMValueTypUnion val;
} NMValueTypUnioMaybe;
#define NM_VALUE_TYP_UNIO_MAYBE_SET(_arg, _type, _val) \
({ \
NMValueTypUnioMaybe *const _arg2 = (_arg); \
\
*_arg2 = (NMValueTypUnioMaybe) { \
.has = TRUE, \
.val._type = (_val), \
}; \
_arg2; \
})
/*****************************************************************************/
static inline int
nm_value_type_cmp (NMValueType value_type,
gconstpointer p_a,
gconstpointer p_b)
{
switch (value_type) {
case NM_VALUE_TYPE_BOOL: NM_CMP_DIRECT (*((const bool *) p_a), *((const bool *) p_b)); return 0;
case NM_VALUE_TYPE_INT32: NM_CMP_DIRECT (*((const gint32 *) p_a), *((const gint32 *) p_b)); return 0;
case NM_VALUE_TYPE_INT: NM_CMP_DIRECT (*((const int *) p_a), *((const int *) p_b)); return 0;
case NM_VALUE_TYPE_STRING: return nm_strcmp0 (*((const char *const*) p_a), *((const char *const*) p_b));
case NM_VALUE_TYPE_UNSPEC:
break;
}
nm_assert_not_reached ();
return 0;
}
static inline gboolean
nm_value_type_equal (NMValueType value_type,
gconstpointer p_a,
gconstpointer p_b)
{
return nm_value_type_cmp (value_type, p_a, p_b) == 0;
}
static inline void
nm_value_type_copy (NMValueType value_type,
gpointer dst,
gconstpointer src)
{
switch (value_type) {
case NM_VALUE_TYPE_BOOL: (*((bool *) dst) = *((const bool *) src)); return;
case NM_VALUE_TYPE_INT32: (*((gint32 *) dst) = *((const gint32 *) src)); return;
case NM_VALUE_TYPE_INT: (*((int *) dst) = *((const int *) src)); return;
case NM_VALUE_TYPE_STRING:
/* self assignment safe! */
if (*((char **) dst) != *((const char *const*) src)) {
g_free (*((char **) dst));
*((char **) dst) = g_strdup (*((const char *const*) src));
}
return;
case NM_VALUE_TYPE_UNSPEC:
break;
}
nm_assert_not_reached ();
}
static inline void
nm_value_type_get_from_variant (NMValueType value_type,
gpointer dst,
GVariant *variant,
gboolean clone)
{
switch (value_type) {
case NM_VALUE_TYPE_BOOL: *((bool *) dst) = g_variant_get_boolean (variant); return;
case NM_VALUE_TYPE_INT32: *((gint32 *) dst) = g_variant_get_int32 (variant); return;
case NM_VALUE_TYPE_STRING:
if (clone) {
g_free (*((char **) dst));
*((char **) dst) = g_variant_dup_string (variant, NULL);
} else {
/* we don't clone the string, nor free the previous value. */
*((const char **) dst) = g_variant_get_string (variant, NULL);
}
return;
case NM_VALUE_TYPE_INT:
/* "int" also does not have a define variant type, because it's not
* clear how many bits we would need. */
/* fall-through */
case NM_VALUE_TYPE_UNSPEC:
break;
}
nm_assert_not_reached ();
}
static inline GVariant *
nm_value_type_to_variant (NMValueType value_type,
gconstpointer src)
{
const char *v_string;
switch (value_type) {
case NM_VALUE_TYPE_BOOL: return g_variant_new_boolean (*((const bool *) src));
case NM_VALUE_TYPE_INT32: return g_variant_new_int32 (*((const gint32 *) src));;
case NM_VALUE_TYPE_STRING:
v_string = *((const char *const*) src);
return v_string ? g_variant_new_string (v_string) : NULL;
case NM_VALUE_TYPE_INT:
/* "int" also does not have a define variant type, because it's not
* clear how many bits we would need. */
/* fall-through */
case NM_VALUE_TYPE_UNSPEC:
break;
}
nm_assert_not_reached ();
}
static inline const GVariantType *
nm_value_type_get_variant_type (NMValueType value_type)
{
switch (value_type) {
case NM_VALUE_TYPE_BOOL: return G_VARIANT_TYPE_BOOLEAN;
case NM_VALUE_TYPE_INT32: return G_VARIANT_TYPE_INT32;
case NM_VALUE_TYPE_STRING: return G_VARIANT_TYPE_STRING;
case NM_VALUE_TYPE_INT:
/* "int" also does not have a define variant type, because it's not
* clear how many bits we would need. */
/* fall-through */
case NM_VALUE_TYPE_UNSPEC:
break;
}
nm_assert_not_reached ();
}
/*****************************************************************************/
#endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */
#endif /* __NM_VALUE_TYPE_H__ */

View file

@ -45,9 +45,9 @@ typedef struct {
NMTeamLinkWatcherType watcher_type;
KeyType key_type;
union {
int (*fint) (NMTeamLinkWatcher *watcher);
gboolean (*fbool) (NMTeamLinkWatcher *watcher);
const char *(*fstring) (NMTeamLinkWatcher *watcher);
int (*fint) (const NMTeamLinkWatcher *watcher);
gboolean (*fbool) (const NMTeamLinkWatcher *watcher);
const char *(*fstring) (const NMTeamLinkWatcher *watcher);
} get_fcn;
union {
int vint;
@ -56,19 +56,19 @@ typedef struct {
} TeamLinkWatcherKeyInfo;
static gboolean
_team_link_watcher_validate_active (NMTeamLinkWatcher *watcher)
_team_link_watcher_validate_active (const NMTeamLinkWatcher *watcher)
{
return NM_FLAGS_HAS (nm_team_link_watcher_get_flags (watcher), NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE);
}
static gboolean
_team_link_watcher_validate_inactive (NMTeamLinkWatcher *watcher)
_team_link_watcher_validate_inactive (const NMTeamLinkWatcher *watcher)
{
return NM_FLAGS_HAS (nm_team_link_watcher_get_flags (watcher), NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE);
}
static gboolean
_team_link_watcher_send_always (NMTeamLinkWatcher *watcher)
_team_link_watcher_send_always (const NMTeamLinkWatcher *watcher)
{
return NM_FLAGS_HAS (nm_team_link_watcher_get_flags (watcher), NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS);
}
@ -142,7 +142,7 @@ _parse_data_get_bool (const ParseData parse_data[static _NM_TEAM_LINK_WATCHER_KE
}
char *
nm_utils_team_link_watcher_to_string (NMTeamLinkWatcher *watcher)
nm_utils_team_link_watcher_to_string (const NMTeamLinkWatcher *watcher)
{
nm_auto_free_gstring GString *str = NULL;
const char *name;
@ -348,12 +348,12 @@ nm_utils_team_link_watcher_from_string (const char *str,
}
#if NM_MORE_ASSERTS > 5
{
if (watcher) {
gs_free char *str2 = NULL;
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher2 = NULL;
static _nm_thread_local int recursive;
nm_assert (watcher);
nm_assert (!error || !*error);
if (recursive == 0) {
recursive = 1;
str2 = nm_utils_team_link_watcher_to_string (watcher);
@ -365,7 +365,8 @@ nm_utils_team_link_watcher_from_string (const char *str,
nm_assert (recursive == 1);
recursive = 0;
}
}
} else
nm_assert (!error || *error);
#endif
return watcher;

View file

@ -46,7 +46,7 @@ typedef enum {
_NM_TEAM_LINK_WATCHER_KEY_NUM,
} NMTeamLinkWatcherKeyId;
char *nm_utils_team_link_watcher_to_string (NMTeamLinkWatcher *watcher);
char *nm_utils_team_link_watcher_to_string (const NMTeamLinkWatcher *watcher);
NMTeamLinkWatcher *nm_utils_team_link_watcher_from_string (const char *str,
GError **error);

View file

@ -1927,6 +1927,69 @@ nmtst_assert_setting_verify_fails (NMSetting *setting,
g_clear_error (&error);
}
static inline void
nmtst_assert_setting_is_equal (gconstpointer /* const NMSetting * */ a,
gconstpointer /* const NMSetting * */ b,
NMSettingCompareFlags flags)
{
gs_unref_hashtable GHashTable *hash = NULL;
guint32 r = nmtst_get_rand_int ();
g_assert (NM_IS_SETTING (a));
g_assert (NM_IS_SETTING (b));
if (NM_FLAGS_HAS (r, 0x4))
NMTST_SWAP (a, b);
g_assert (nm_setting_compare ((NMSetting *) a,
(NMSetting *) b,
flags));
if (NM_FLAGS_HAS (r, 0x8))
NMTST_SWAP (a, b);
g_assert (nm_setting_diff ((NMSetting *) a,
(NMSetting *) b,
flags,
NM_FLAGS_HAS (r, 0x1),
&hash));
g_assert (!hash);
}
#endif
#ifdef __NM_SETTING_PRIVATE_H__
static inline NMSetting *
nmtst_assert_setting_dbus_new (GType gtype, GVariant *variant)
{
NMSetting *setting;
gs_free_error GError *error = NULL;
g_assert (g_type_is_a (gtype, NM_TYPE_SETTING));
g_assert (gtype != NM_TYPE_SETTING);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, NM_VARIANT_TYPE_SETTING));
setting = _nm_setting_new_from_dbus (gtype,
variant,
NULL,
NM_SETTING_PARSE_FLAGS_STRICT,
&error);
nmtst_assert_success (setting, error);
return setting;
}
static inline void
nmtst_assert_setting_dbus_roundtrip (gconstpointer /* const NMSetting * */ setting)
{
gs_unref_object NMSetting *setting2 = NULL;
gs_unref_variant GVariant *variant = NULL;
g_assert (NM_IS_SETTING (setting));
variant = _nm_setting_to_dbus ((NMSetting *) setting, NULL, NM_CONNECTION_SERIALIZE_ALL);
setting2 = nmtst_assert_setting_dbus_new (G_OBJECT_TYPE (setting), variant);
nmtst_assert_setting_is_equal (setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT);
}
#endif
#ifdef __NM_UTILS_H__
@ -2140,6 +2203,25 @@ typedef enum {
#endif /* __NM_CONNECTION_H__ */
static inline GVariant *
nmtst_variant_from_string (const GVariantType *variant_type,
const char *variant_str)
{
GVariant *variant;
GError *error = NULL;
g_assert (variant_type);
g_assert (variant_str);
variant = g_variant_parse (variant_type,
variant_str,
NULL,
NULL,
&error);
nmtst_assert_success (variant, error);
return variant;
}
/*****************************************************************************/
static inline void

View file

@ -4862,62 +4862,27 @@ bond_connection_from_ifcfg (const char *file,
return connection;
}
/* Check 'error' for errors. Missing config (NULL return value) is a valid case. */
static char *
read_team_config (shvarFile *ifcfg, const char *key, GError **error)
{
gs_free_error GError *local_error = NULL;
gs_free char *value = NULL;
size_t l;
value = svGetValueStr_cp (ifcfg, key);
if (!value)
return NULL;
l = strlen (value);
if (l > 1*1024*1024) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"%s too long (size %zd)", key, l);
return NULL;
}
if (!nm_utils_is_json_object (value, &local_error)) {
PARSE_WARNING ("ignoring invalid team configuration: %s", local_error->message);
return NULL;
}
return g_steal_pointer (&value);
}
static NMSetting *
make_team_setting (shvarFile *ifcfg,
const char *file,
GError **error)
{
NMSettingTeam *s_team;
char *value;
GError *local_err = NULL;
NMSetting *s_team;
gs_free char *value_device = NULL;
gs_free char *value = NULL;
value = svGetValueStr_cp (ifcfg, "DEVICE");
if (!value) {
if (!svGetValueStr (ifcfg, "DEVICE", &value_device)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"mandatory DEVICE keyword missing");
return NULL;
}
g_free (value);
value = read_team_config (ifcfg, "TEAM_CONFIG", &local_err);
if (local_err) {
g_propagate_error (error, local_err);
return NULL;
}
s_team = NM_SETTING_TEAM (nm_setting_team_new ());
g_object_set (s_team, NM_SETTING_TEAM_CONFIG, value, NULL);
g_free (value);
return (NMSetting *) s_team;
s_team = nm_setting_team_new ();
g_object_set (s_team,
NM_SETTING_TEAM_CONFIG,
svGetValue (ifcfg, "TEAM_CONFIG", &value),
NULL);
return s_team;
}
static NMConnection *
@ -5276,20 +5241,18 @@ make_bridge_port_setting (shvarFile *ifcfg)
static NMSetting *
make_team_port_setting (shvarFile *ifcfg)
{
NMSetting *s_port = NULL;
char *value;
GError *error = NULL;
NMSetting *s_port;
gs_free char *value = NULL;
value = read_team_config (ifcfg, "TEAM_PORT_CONFIG", &error);
if (value) {
s_port = nm_setting_team_port_new ();
g_object_set (s_port, NM_SETTING_TEAM_PORT_CONFIG, value, NULL);
g_free (value);
} else if (error) {
PARSE_WARNING ("%s", error->message);
g_error_free (error);
}
value = svGetValueStr_cp (ifcfg, "TEAM_PORT_CONFIG");
if (!value)
return NULL;
s_port = nm_setting_team_port_new ();
g_object_set (s_port,
NM_SETTING_TEAM_PORT_CONFIG,
value,
NULL);
return s_port;
}
@ -5902,12 +5865,10 @@ connection_from_file_full (const char *filename,
if (s_match)
nm_connection_add_setting (connection, s_match);
/* Bridge port? */
s_port = make_bridge_port_setting (main_ifcfg);
if (s_port)
nm_connection_add_setting (connection, s_port);
/* Team port? */
s_port = make_team_port_setting (main_ifcfg);
if (s_port)
nm_connection_add_setting (connection, s_port);

View file

@ -8938,25 +8938,16 @@ static void
test_read_team_master_invalid (gconstpointer user_data)
{
const char *const PATH_NAME = user_data;
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingTeam *s_team;
gs_free_error GError *error = NULL;
gs_unref_object NMConnection *connection = NULL;
NMTST_EXPECT_NM_WARN ("*ignoring invalid team configuration*");
connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
g_test_assert_expected_messages ();
if (WITH_JSON_VALIDATION) {
_connection_from_file_fail (PATH_NAME, NULL, TYPE_ETHERNET, &error);
g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "team0");
s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_TEAM_SETTING_NAME);
s_team = nm_connection_get_setting_team (connection);
g_assert (s_team);
g_assert (nm_setting_team_get_config (s_team) == NULL);
g_object_unref (connection);
g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
g_assert (strstr (error->message, _("invalid json")));
} else
connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
}
static void