summaryrefslogtreecommitdiff
path: root/libnm-core
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-core')
-rw-r--r--libnm-core/nm-core-internal.h13
-rw-r--r--libnm-core/nm-setting-team-port.c344
-rw-r--r--libnm-core/nm-setting-team.c694
-rw-r--r--libnm-core/nm-team-utils.c1990
-rw-r--r--libnm-core/nm-team-utils.h246
-rw-r--r--libnm-core/nm-utils-private.h112
-rw-r--r--libnm-core/nm-utils.c752
-rw-r--r--libnm-core/tests/test-general.c59
-rw-r--r--libnm-core/tests/test-setting.c86
9 files changed, 2717 insertions, 1579 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 95b50d03a0..ef5f9a6959 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -547,19 +547,6 @@ gboolean nm_team_link_watchers_equal (const GPtrArray *a,
const GPtrArray *b,
gboolean ignore_order);
-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);
-
-gboolean _nm_utils_team_config_set (char **conf,
- const char *key,
- const char *key2,
- const char *key3,
- const GValue *value);
-
/*****************************************************************************/
guint32 _nm_utils_parse_tc_handle (const char *str,
diff --git a/libnm-core/nm-setting-team-port.c b/libnm-core/nm-setting-team-port.c
index d083943ed6..220a8c4186 100644
--- a/libnm-core/nm-setting-team-port.c
+++ b/libnm-core/nm-setting-team-port.c
@@ -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_ref (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 *
@@ -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,
+ 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,26 +437,25 @@ 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));
- break;
- case PROP_QUEUE_ID:
- g_value_set_int (value, priv->queue_id);
- break;
- case PROP_PRIO:
- g_value_set_int (value, priv->prio);
+ case NM_TEAM_ATTRIBUTE_CONFIG:
+ g_value_set_string (value,
+ nm_team_setting_config_get (priv->team_setting));
break;
- case PROP_STICKY:
- g_value_set_boolean (value, priv->sticky);
+ 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_LACP_PRIO:
- g_value_set_int (value, priv->lacp_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_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,
+ 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;
@@ -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);
- 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;
- 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_CONFIG:
+ changed = nm_team_setting_config_set (priv->team_setting, g_value_get_string (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;
+ 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_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;
+ 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_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_ref,
- (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);
diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c
index 663d7d819c..01a1a12232 100644
--- a/libnm-core/nm-setting-team.c
+++ b/libnm-core/nm-setting-team.c
@@ -27,6 +27,7 @@
#include "nm-utils.h"
#include "nm-utils-private.h"
+#include "nm-team-utils.h"
#include "nm-connection-private.h"
/**
@@ -721,61 +722,10 @@ nm_team_link_watcher_get_flags (const NMTeamLinkWatcher *watcher)
/*****************************************************************************/
-NM_GOBJECT_PROPERTIES_DEFINE (NMSettingTeam,
- PROP_CONFIG,
- PROP_NOTIFY_PEERS_COUNT,
- PROP_NOTIFY_PEERS_INTERVAL,
- PROP_MCAST_REJOIN_COUNT,
- PROP_MCAST_REJOIN_INTERVAL,
- PROP_RUNNER,
- PROP_RUNNER_HWADDR_POLICY,
- PROP_RUNNER_TX_HASH,
- PROP_RUNNER_TX_BALANCER,
- PROP_RUNNER_TX_BALANCER_INTERVAL,
- PROP_RUNNER_ACTIVE,
- PROP_RUNNER_FAST_RATE,
- PROP_RUNNER_SYS_PRIO,
- PROP_RUNNER_MIN_PORTS,
- PROP_RUNNER_AGG_SELECT_POLICY,
- PROP_LINK_WATCHERS,
-);
-
-static const _NMUtilsTeamPropertyKeys _prop_to_keys[_PROPERTY_ENUMS_LAST] = {
- [PROP_CONFIG] = { },
- [PROP_NOTIFY_PEERS_COUNT] = { .key1 = "notify_peers", .key2 = "count", },
- [PROP_NOTIFY_PEERS_INTERVAL] = { .key1 = "notify_peers", .key2 = "interval", },
- [PROP_MCAST_REJOIN_COUNT] = { .key1 = "mcast_rejoin", .key2 = "count", },
- [PROP_MCAST_REJOIN_INTERVAL] = { .key1 = "mcast_rejoin", .key2 = "interval", },
- [PROP_RUNNER] = { .key1 = "runner", .key2 = "name", .default_str = NM_SETTING_TEAM_RUNNER_DEFAULT, },
- [PROP_RUNNER_HWADDR_POLICY] = { .key1 = "runner", .key2 = "hwaddr_policy", },
- [PROP_RUNNER_TX_HASH] = { .key1 = "runner", .key2 = "tx_hash", },
- [PROP_RUNNER_TX_BALANCER] = { .key1 = "runner", .key2 = "tx_balancer", .key3 = "name", },
- [PROP_RUNNER_TX_BALANCER_INTERVAL] = { .key1 = "runner", .key2 = "tx_balancer", .key3 = "balancing_interval", .default_int = -1 },
- [PROP_RUNNER_ACTIVE] = { .key1 = "runner", .key2 = "active", },
- [PROP_RUNNER_FAST_RATE] = { .key1 = "runner", .key2 = "fast_rate", },
- [PROP_RUNNER_SYS_PRIO] = { .key1 = "runner", .key2 = "sys_prio", .default_int = -1, },
- [PROP_RUNNER_MIN_PORTS] = { .key1 = "runner", .key2 = "min_ports", .default_int = -1, },
- [PROP_RUNNER_AGG_SELECT_POLICY] = { .key1 = "runner", .key2 = "agg_select_policy", },
- [PROP_LINK_WATCHERS] = { .key1 = "link_watch", },
-};
+static GParamSpec *obj_properties[_NM_TEAM_ATTRIBUTE_MASTER_NUM] = { NULL, };
typedef struct {
- char *config;
- int notify_peers_count;
- int notify_peers_interval;
- int mcast_rejoin_count;
- int mcast_rejoin_interval;
- char *runner;
- char *runner_hwaddr_policy;
- GPtrArray *runner_tx_hash;
- char *runner_tx_balancer;
- int runner_tx_balancer_interval;
- gboolean runner_active;
- gboolean runner_fast_rate;
- int runner_sys_prio;
- int runner_min_ports;
- char *runner_agg_select_policy;
- GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */
+ NMTeamSetting *team_setting;
} NMSettingTeamPrivate;
G_DEFINE_TYPE (NMSettingTeam, nm_setting_team, NM_TYPE_SETTING)
@@ -784,6 +734,15 @@ G_DEFINE_TYPE (NMSettingTeam, nm_setting_team, NM_TYPE_SETTING)
/*****************************************************************************/
+#define _maybe_changed(self, changed) \
+ nm_team_setting_maybe_changed (NM_SETTING (_NM_ENSURE_TYPE (NMSettingTeam *, 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_get_config:
* @setting: the #NMSettingTeam
@@ -795,7 +754,7 @@ nm_setting_team_get_config (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->config;
+ return nm_team_setting_config_get (NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting);
}
/**
@@ -811,7 +770,7 @@ nm_setting_team_get_notify_peers_count (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->notify_peers_count;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.notify_peers_count;
}
/**
@@ -827,7 +786,7 @@ nm_setting_team_get_notify_peers_interval (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->notify_peers_interval;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.notify_peers_interval;
}
/**
@@ -843,7 +802,7 @@ nm_setting_team_get_mcast_rejoin_count (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->mcast_rejoin_count;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.mcast_rejoin_count;
}
/**
@@ -859,7 +818,7 @@ nm_setting_team_get_mcast_rejoin_interval (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->mcast_rejoin_interval;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.mcast_rejoin_interval;
}
/**
@@ -875,7 +834,7 @@ nm_setting_team_get_runner (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner;
}
/**
@@ -891,7 +850,7 @@ nm_setting_team_get_runner_hwaddr_policy (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner_hwaddr_policy;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_hwaddr_policy;
}
/**
@@ -907,7 +866,7 @@ nm_setting_team_get_runner_tx_balancer (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner_tx_balancer;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_tx_balancer;
}
/**
@@ -923,7 +882,7 @@ nm_setting_team_get_runner_tx_balancer_interval (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner_tx_balancer_interval;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_tx_balancer_interval;
}
/**
@@ -939,7 +898,7 @@ nm_setting_team_get_runner_active (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), FALSE);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner_active;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_active;
}
/**
@@ -955,7 +914,7 @@ nm_setting_team_get_runner_fast_rate (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), FALSE);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner_fast_rate;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_fast_rate;
}
/**
@@ -971,7 +930,7 @@ nm_setting_team_get_runner_sys_prio (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner_sys_prio;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_sys_prio;
}
/**
@@ -987,7 +946,7 @@ nm_setting_team_get_runner_min_ports (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner_min_ports;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_min_ports;
}
/**
@@ -1003,7 +962,7 @@ nm_setting_team_get_runner_agg_select_policy (NMSettingTeam *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL);
- return NM_SETTING_TEAM_GET_PRIVATE (setting)->runner_agg_select_policy;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_agg_select_policy;
}
/**
@@ -1019,19 +978,22 @@ nm_setting_team_get_runner_agg_select_policy (NMSettingTeam *setting)
**/
gboolean
nm_setting_team_remove_runner_tx_hash_by_value (NMSettingTeam *setting,
- const char *txhash)
+ const char *txhash)
{
NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+ const GPtrArray *arr;
guint i;
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), FALSE);
g_return_val_if_fail (txhash != NULL, FALSE);
- if (priv->runner_tx_hash) {
- for (i = 0; i < priv->runner_tx_hash->len; i++) {
- if (nm_streq (txhash, priv->runner_tx_hash->pdata[i])) {
- g_ptr_array_remove_index (priv->runner_tx_hash, i);
- _notify (setting, PROP_RUNNER_TX_HASH);
+ arr = priv->team_setting->d.master.runner_tx_hash;
+ if (arr) {
+ for (i = 0; i < arr->len; i++) {
+ if (nm_streq (txhash, arr->pdata[i])) {
+ _maybe_changed_with_assert (setting,
+ nm_team_setting_value_master_runner_tx_hash_remove (priv->team_setting,
+ i));
return TRUE;
}
}
@@ -1050,11 +1012,12 @@ nm_setting_team_remove_runner_tx_hash_by_value (NMSettingTeam *setting,
guint
nm_setting_team_get_num_runner_tx_hash (NMSettingTeam *setting)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+ const GPtrArray *arr;
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return priv->runner_tx_hash ? priv->runner_tx_hash->len : 0;
+ arr = NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_tx_hash;
+ return arr ? arr->len : 0u;
}
/**
@@ -1069,13 +1032,16 @@ nm_setting_team_get_num_runner_tx_hash (NMSettingTeam *setting)
const char *
nm_setting_team_get_runner_tx_hash (NMSettingTeam *setting, guint idx)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+ const GPtrArray *arr;
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL);
- g_return_val_if_fail (priv->runner_tx_hash, NULL);
- g_return_val_if_fail (idx < priv->runner_tx_hash->len, NULL);
- return priv->runner_tx_hash->pdata[idx];
+ arr = NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.master.runner_tx_hash;
+
+ g_return_val_if_fail (arr, NULL);
+ g_return_val_if_fail (idx < arr->len, NULL);
+
+ return arr->pdata[idx];
}
/**
@@ -1090,14 +1056,18 @@ nm_setting_team_get_runner_tx_hash (NMSettingTeam *setting, guint idx)
void
nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, guint idx)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+ NMSettingTeamPrivate *priv;
g_return_if_fail (NM_IS_SETTING_TEAM (setting));
- g_return_if_fail (priv->runner_tx_hash);
- g_return_if_fail (idx < priv->runner_tx_hash->len);
- g_ptr_array_remove_index (priv->runner_tx_hash, idx);
- _notify (setting, PROP_RUNNER_TX_HASH);
+ priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+
+ g_return_if_fail (priv->team_setting->d.master.runner_tx_hash);
+ g_return_if_fail (idx < priv->team_setting->d.master.runner_tx_hash->len);
+
+ _maybe_changed_with_assert (setting,
+ nm_team_setting_value_master_runner_tx_hash_remove (priv->team_setting,
+ idx));
}
/**
@@ -1115,23 +1085,12 @@ nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, guint idx)
gboolean
nm_setting_team_add_runner_tx_hash (NMSettingTeam *setting, const char *txhash)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
- guint i;
-
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), FALSE);
- g_return_val_if_fail (txhash != NULL, FALSE);
- g_return_val_if_fail (txhash[0] != '\0', FALSE);
+ g_return_val_if_fail (txhash, FALSE);
- if (!priv->runner_tx_hash)
- priv->runner_tx_hash = g_ptr_array_new_with_free_func (g_free);
- for (i = 0; i < priv->runner_tx_hash->len; i++) {
- if (nm_streq (txhash, priv->runner_tx_hash->pdata[i]))
- return FALSE;
- }
-
- g_ptr_array_add (priv->runner_tx_hash, g_strdup (txhash));
- _notify (setting, PROP_RUNNER_TX_HASH);
- return TRUE;
+ return _maybe_changed (setting,
+ nm_team_setting_value_master_runner_tx_hash_add (NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting,
+ txhash));
}
/**
@@ -1145,11 +1104,9 @@ nm_setting_team_add_runner_tx_hash (NMSettingTeam *setting, const char *txhash)
guint
nm_setting_team_get_num_link_watchers (NMSettingTeam *setting)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
-
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0);
- return priv->link_watchers->len;
+ return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.link_watchers->len;
}
/**
@@ -1164,12 +1121,15 @@ nm_setting_team_get_num_link_watchers (NMSettingTeam *setting)
NMTeamLinkWatcher *
nm_setting_team_get_link_watcher (NMSettingTeam *setting, guint idx)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+ const GPtrArray *arr;
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL);
- g_return_val_if_fail (idx < priv->link_watchers->len, NULL);
- return priv->link_watchers->pdata[idx];
+ arr = NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting->d.link_watchers;
+
+ g_return_val_if_fail (idx < arr->len, NULL);
+
+ return arr->pdata[idx];
}
/**
@@ -1188,20 +1148,12 @@ gboolean
nm_setting_team_add_link_watcher (NMSettingTeam *setting,
NMTeamLinkWatcher *link_watcher)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
- guint i;
-
g_return_val_if_fail (NM_IS_SETTING_TEAM (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_ref (link_watcher));
- _notify (setting, PROP_LINK_WATCHERS);
- return TRUE;
+ return _maybe_changed (setting,
+ nm_team_setting_value_link_watchers_add (NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting,
+ link_watcher));
}
/**
@@ -1216,13 +1168,17 @@ nm_setting_team_add_link_watcher (NMSettingTeam *setting,
void
nm_setting_team_remove_link_watcher (NMSettingTeam *setting, guint idx)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+ NMSettingTeamPrivate *priv;
g_return_if_fail (NM_IS_SETTING_TEAM (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_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));
}
/**
@@ -1240,19 +1196,12 @@ gboolean
nm_setting_team_remove_link_watcher_by_value (NMSettingTeam *setting,
NMTeamLinkWatcher *link_watcher)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
- guint i;
-
g_return_val_if_fail (NM_IS_SETTING_TEAM (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_GET_PRIVATE (setting)->team_setting,
+ link_watcher));
}
/**
@@ -1264,15 +1213,14 @@ nm_setting_team_remove_link_watcher_by_value (NMSettingTeam *setting,
* Since: 1.12
**/
void
-nm_setting_team_clear_link_watchers (NMSettingTeam *setting) {
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
-
+nm_setting_team_clear_link_watchers (NMSettingTeam *setting)
+{
g_return_if_fail (NM_IS_SETTING_TEAM (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_GET_PRIVATE (setting)->team_setting,
+ NULL,
+ 0));
}
static GVariant *
@@ -1292,90 +1240,12 @@ static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
- guint i;
if (!_nm_connection_verify_required_interface_name (connection, error))
return FALSE;
- 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_SETTING_NAME,
- NM_SETTING_TEAM_CONFIG);
- return FALSE;
- }
-
- if (!nm_utils_is_json_object (priv->config, error)) {
- g_prefix_error (error,
- "%s.%s: ",
- NM_SETTING_TEAM_SETTING_NAME,
- NM_SETTING_TEAM_CONFIG);
- /* We treat an empty string as no config for compatibility. */
- return *priv->config ? FALSE : NM_SETTING_VERIFY_NORMALIZABLE;
- }
- }
-
- if ( priv->runner
- && g_ascii_strcasecmp (priv->runner, NM_SETTING_TEAM_RUNNER_BROADCAST)
- && g_ascii_strcasecmp (priv->runner, NM_SETTING_TEAM_RUNNER_ROUNDROBIN)
- && g_ascii_strcasecmp (priv->runner, NM_SETTING_TEAM_RUNNER_RANDOM)
- && g_ascii_strcasecmp (priv->runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)
- && g_ascii_strcasecmp (priv->runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE)
- && g_ascii_strcasecmp (priv->runner, NM_SETTING_TEAM_RUNNER_LACP)) {
- g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
- _("invalid runner \"%s\""), priv->runner);
-
- g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_TEAM_RUNNER);
+ if (!nm_team_setting_verify (priv->team_setting, error))
return FALSE;
- }
-
- /* Validate link watchers */
- for (i = 0; i < priv->link_watchers->len; i++) {
- NMTeamLinkWatcher *link_watcher = priv->link_watchers->pdata[i];
- const char *name = nm_team_link_watcher_get_name (link_watcher);
-
- if (!name) {
- g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
- _("missing link watcher name"));
- g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting),
- NM_SETTING_TEAM_LINK_WATCHERS);
- return FALSE;
- }
- if (!NM_IN_STRSET (name,
- NM_TEAM_LINK_WATCHER_ETHTOOL,
- NM_TEAM_LINK_WATCHER_ARP_PING,
- NM_TEAM_LINK_WATCHER_NSNA_PING)) {
- g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
- _("unknown link watcher \"%s\""), name);
- g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting),
- NM_SETTING_TEAM_LINK_WATCHERS);
- return FALSE;
- }
-
- if (NM_IN_STRSET (name,
- NM_TEAM_LINK_WATCHER_ARP_PING,
- NM_TEAM_LINK_WATCHER_NSNA_PING)
- && !nm_team_link_watcher_get_target_host (link_watcher)) {
- g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
- _("missing target host"));
- g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting),
- NM_SETTING_TEAM_LINK_WATCHERS);
- return FALSE;
- }
- if (nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING)
- && !nm_team_link_watcher_get_source_host (link_watcher)) {
- g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
- _("missing source address"));
- g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting),
- NM_SETTING_TEAM_LINK_WATCHERS);
- return FALSE;
- }
- }
- /* NOTE: normalizable/normalizable-errors must appear at the end with decreasing severity.
- * Take care to properly order statements with priv->config above. */
return TRUE;
}
@@ -1398,27 +1268,26 @@ compare_property (const NMSettInfoSetting *sett_info,
return TRUE;
a_priv = NM_SETTING_TEAM_GET_PRIVATE (set_a);
b_priv = NM_SETTING_TEAM_GET_PRIVATE (set_b);
- return nm_team_link_watchers_equal (a_priv->link_watchers,
- b_priv->link_watchers,
+ 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_CONFIG)) {
if (set_b) {
- a_priv = NM_SETTING_TEAM_GET_PRIVATE (set_a);
- b_priv = NM_SETTING_TEAM_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_GET_PRIVATE (set_a);
+ b_priv = NM_SETTING_TEAM_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;
@@ -1433,56 +1302,38 @@ compare_property (const NMSettInfoSetting *sett_info,
flags);
}
-#define JSON_TO_VAL(typ, id) _nm_utils_json_extract_##typ (priv->config, _prop_to_keys[id], FALSE)
-
static void
-_align_team_properties (NMSettingTeam *setting)
+duplicate_copy_properties (const NMSettInfoSetting *sett_info,
+ NMSetting *src,
+ NMSetting *dst)
{
- NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
- char **strv;
- gsize i;
-
- priv->notify_peers_count = JSON_TO_VAL (int, PROP_NOTIFY_PEERS_COUNT);
- priv->notify_peers_interval = JSON_TO_VAL (int, PROP_NOTIFY_PEERS_INTERVAL);
- priv->mcast_rejoin_count = JSON_TO_VAL (int, PROP_MCAST_REJOIN_COUNT);
- priv->mcast_rejoin_interval = JSON_TO_VAL (int, PROP_MCAST_REJOIN_INTERVAL);
- priv->runner_tx_balancer_interval = JSON_TO_VAL (int, PROP_RUNNER_TX_BALANCER_INTERVAL);
- priv->runner_sys_prio = JSON_TO_VAL (int, PROP_RUNNER_SYS_PRIO);
- priv->runner_min_ports = JSON_TO_VAL (int, PROP_RUNNER_MIN_PORTS);
-
- priv->runner_active = JSON_TO_VAL (boolean, PROP_RUNNER_ACTIVE);
- priv->runner_fast_rate = JSON_TO_VAL (boolean, PROP_RUNNER_FAST_RATE);
-
- g_free (priv->runner);
- g_free (priv->runner_hwaddr_policy);
- g_free (priv->runner_tx_balancer);
- g_free (priv->runner_agg_select_policy);
- priv->runner = JSON_TO_VAL (string, PROP_RUNNER);
- priv->runner_hwaddr_policy = JSON_TO_VAL (string, PROP_RUNNER_HWADDR_POLICY);
- priv->runner_tx_balancer = JSON_TO_VAL (string, PROP_RUNNER_TX_BALANCER);
- priv->runner_agg_select_policy = JSON_TO_VAL (string, PROP_RUNNER_AGG_SELECT_POLICY);
-
- strv = JSON_TO_VAL (strv, PROP_RUNNER_TX_HASH);
- if (_nm_utils_strv_cmp_n (( priv->runner_tx_hash
- ? (const char *const*) priv->runner_tx_hash->pdata
- : NULL),
- ( priv->runner_tx_hash
- ? (gssize) priv->runner_tx_hash->len
- : (gssize) -1),
- NM_CAST_STRV_CC (strv),
- -1) != 0) {
- nm_clear_pointer (&priv->runner_tx_hash, g_ptr_array_unref);
- if (strv) {
- priv->runner_tx_hash = g_ptr_array_new_full (NM_PTRARRAY_LEN (strv), g_free);
- for (i = 0; strv[i]; i++)
- g_ptr_array_add (priv->runner_tx_hash, strv[i]);
- nm_clear_g_free (&strv);
- }
- }
- nm_clear_pointer (&strv, g_strfreev);
+ _maybe_changed (NM_SETTING_TEAM (dst),
+ nm_team_setting_reset (NM_SETTING_TEAM_GET_PRIVATE (dst)->team_setting,
+ NM_SETTING_TEAM_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;
- g_ptr_array_unref (priv->link_watchers);
- priv->link_watchers = JSON_TO_VAL (ptr_array, PROP_LINK_WATCHERS);
+ if (keys)
+ g_hash_table_remove (keys, "interface-name");
+
+ success = nm_team_setting_reset_from_dbus (NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting,
+ setting_dict,
+ keys,
+ &changed,
+ parse_flags,
+ error);
+ _maybe_changed (NM_SETTING_TEAM (setting), changed);
+ return success;
}
/*****************************************************************************/
@@ -1493,58 +1344,47 @@ get_property (GObject *object, guint prop_id,
{
NMSettingTeam *setting = NM_SETTING_TEAM (object);
NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+ const GPtrArray *v_ptrarr;
switch (prop_id) {
- case PROP_CONFIG:
- g_value_set_string (value, nm_setting_team_get_config (setting));
- break;
- case PROP_NOTIFY_PEERS_COUNT:
- g_value_set_int (value, priv->notify_peers_count);
+ case NM_TEAM_ATTRIBUTE_CONFIG:
+ g_value_set_string (value,
+ nm_team_setting_config_get (priv->team_setting));
break;
- case PROP_NOTIFY_PEERS_INTERVAL:
- g_value_set_int (value, priv->notify_peers_interval);
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE:
+ g_value_set_boolean (value,
+ nm_team_setting_value_get_bool (priv->team_setting,
+ prop_id));
break;
- case PROP_MCAST_REJOIN_COUNT:
- g_value_set_int (value, priv->mcast_rejoin_count);
+ case NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT:
+ case NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL:
+ case NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT:
+ case NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS:
+ g_value_set_int (value,
+ nm_team_setting_value_get_int32 (priv->team_setting,
+ prop_id));
break;
- case PROP_MCAST_REJOIN_INTERVAL:
- g_value_set_int (value, priv->mcast_rejoin_interval);
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY:
+ g_value_set_string (value,
+ nm_team_setting_value_get_string (priv->team_setting,
+ prop_id));
break;
- case PROP_RUNNER:
- g_value_set_string (value, nm_setting_team_get_runner (setting));
- break;
- case PROP_RUNNER_HWADDR_POLICY:
- g_value_set_string (value, nm_setting_team_get_runner_hwaddr_policy (setting));
- break;
- case PROP_RUNNER_TX_HASH:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH:
+ v_ptrarr = priv->team_setting->d.master.runner_tx_hash;
g_value_take_boxed (value,
- priv->runner_tx_hash
- ? _nm_utils_ptrarray_to_strv (priv->runner_tx_hash)
+ v_ptrarr
+ ? _nm_utils_ptrarray_to_strv ((GPtrArray *) v_ptrarr)
: NULL);
break;
- case PROP_RUNNER_TX_BALANCER:
- g_value_set_string (value, nm_setting_team_get_runner_tx_balancer (setting));
- break;
- case PROP_RUNNER_TX_BALANCER_INTERVAL:
- g_value_set_int (value, priv->runner_tx_balancer_interval);
- break;
- case PROP_RUNNER_ACTIVE:
- g_value_set_boolean (value, nm_setting_team_get_runner_active (setting));
- break;
- case PROP_RUNNER_FAST_RATE:
- g_value_set_boolean (value, nm_setting_team_get_runner_fast_rate (setting));
- break;
- case PROP_RUNNER_SYS_PRIO:
- g_value_set_int (value, priv->runner_sys_prio);
- break;
- case PROP_RUNNER_MIN_PORTS:
- g_value_set_int (value, priv->runner_min_ports);
- break;
- case PROP_RUNNER_AGG_SELECT_POLICY:
- g_value_set_string (value, nm_setting_team_get_runner_agg_select_policy (setting));
- break;
- case PROP_LINK_WATCHERS:
- g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers,
+ 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;
@@ -1560,141 +1400,56 @@ set_property (GObject *object, guint prop_id,
{
NMSettingTeam *setting = NM_SETTING_TEAM (object);
NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (object);
- const GValue *align_value = NULL;
- gboolean align_config = FALSE;
- char **strv;
+ guint32 changed;
+ const GPtrArray *v_ptrarr;
switch (prop_id) {
- case PROP_CONFIG:
- g_free (priv->config);
- priv->config = g_value_dup_string (value);
- _align_team_properties (setting);
+ case NM_TEAM_ATTRIBUTE_CONFIG:
+ changed = nm_team_setting_config_set (priv->team_setting, g_value_get_string (value));
break;
- case PROP_NOTIFY_PEERS_COUNT:
- if (priv->notify_peers_count == g_value_get_int (value))
- break;
- priv->notify_peers_count = g_value_get_int (value);
- align_value = value;
- align_config = TRUE;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE:
+ changed = nm_team_setting_value_set_bool (priv->team_setting,
+ prop_id,
+ g_value_get_boolean (value));
break;
- case PROP_NOTIFY_PEERS_INTERVAL:
- if (priv->notify_peers_interval == g_value_get_int (value))
- break;
- priv->notify_peers_interval = g_value_get_int (value);
- align_value = value;
- align_config = TRUE;
+ case NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT:
+ case NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL:
+ case NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT:
+ case NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS:
+ changed = nm_team_setting_value_set_int32 (priv->team_setting,
+ prop_id,
+ g_value_get_int (value));
break;
- case PROP_MCAST_REJOIN_COUNT:
- if (priv->mcast_rejoin_count == g_value_get_int (value))
- break;
- priv->mcast_rejoin_count = g_value_get_int (value);
- align_value = value;
- align_config = TRUE;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY:
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY:
+ changed = nm_team_setting_value_set_string (priv->team_setting,
+ prop_id,
+ g_value_get_string (value));
break;
- case PROP_MCAST_REJOIN_INTERVAL:
- if (priv->mcast_rejoin_interval == g_value_get_int (value))
- break;
- priv->mcast_rejoin_interval = g_value_get_int (value);
- align_value = value;
- align_config = TRUE;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH:
+ v_ptrarr = g_value_get_boxed (value);
+ changed = nm_team_setting_value_master_runner_tx_hash_set_list (priv->team_setting,
+ v_ptrarr ? (const char *const*) v_ptrarr->pdata : NULL,
+ v_ptrarr ? v_ptrarr->len : 0u);
break;
- case PROP_RUNNER:
- if ( !g_value_get_string (value)
- || nm_streq (priv->runner, g_value_get_string (value)))
- break;
- g_free (priv->runner);
- priv->runner = g_value_dup_string (value);
- _nm_utils_json_append_gvalue (&priv->config, _prop_to_keys[prop_id], value);
- _align_team_properties (setting);
- break;
- case PROP_RUNNER_HWADDR_POLICY:
- if (nm_streq0 (priv->runner_hwaddr_policy, g_value_get_string (value)))
- break;
- g_free (priv->runner_hwaddr_policy);
- priv->runner_hwaddr_policy = g_value_dup_string (value);
- align_value = value;
- align_config = TRUE;
- break;
- case PROP_RUNNER_TX_HASH:
- if (priv->runner_tx_hash)
- g_ptr_array_unref (priv->runner_tx_hash);
- strv = g_value_get_boxed (value);
- if (strv && strv[0]) {
- priv->runner_tx_hash = _nm_utils_strv_to_ptrarray (strv);
- align_value = value;
- } else
- priv->runner_tx_hash = NULL;
- align_config = TRUE;
- break;
- case PROP_RUNNER_TX_BALANCER:
- if (nm_streq0 (priv->runner_tx_balancer, g_value_get_string (value)))
- break;
- g_free (priv->runner_tx_balancer);
- priv->runner_tx_balancer = g_value_dup_string (value);
- align_value = value;
- align_config = TRUE;
- break;
- case PROP_RUNNER_TX_BALANCER_INTERVAL:
- if (priv->runner_tx_balancer_interval == g_value_get_int (value))
- break;
- priv->runner_tx_balancer_interval = g_value_get_int (value);
- align_value = value;
- align_config = TRUE;
- break;
- case PROP_RUNNER_ACTIVE:
- if (priv->runner_active == g_value_get_boolean (value))
- break;
- priv->runner_active = g_value_get_boolean (value);
- align_value = value;
- align_config = TRUE;
- break;
- case PROP_RUNNER_FAST_RATE:
- if (priv->runner_fast_rate == g_value_get_boolean (value))
- break;
- priv->runner_fast_rate = g_value_get_boolean (value);
- align_value = value;
- align_config = TRUE;
- break;
- case PROP_RUNNER_SYS_PRIO:
- if (priv->runner_sys_prio == g_value_get_int (value))
- break;
- priv->runner_sys_prio = g_value_get_int (value);
- align_value = value;
- align_config = TRUE;
- break;
- case PROP_RUNNER_MIN_PORTS:
- if (priv->runner_min_ports == g_value_get_int (value))
- break;
- priv->runner_min_ports = g_value_get_int (value);
- align_value = value;
- align_config = TRUE;
- break;
- case PROP_RUNNER_AGG_SELECT_POLICY:
- if (nm_streq0 (priv->runner_agg_select_policy, g_value_get_string (value)))
- break;
- g_free (priv->runner_agg_select_policy);
- priv->runner_agg_select_policy = g_value_dup_string (value);
- 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_ref,
- (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);
- _align_team_properties (setting);
- }
+ _maybe_changed (setting, changed & ~(((guint32) 1) << prop_id));
}
/*****************************************************************************/
@@ -1704,11 +1459,7 @@ nm_setting_team_init (NMSettingTeam *setting)
{
NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
- priv->runner = g_strdup (NM_SETTING_TEAM_RUNNER_ROUNDROBIN);
- priv->runner_tx_balancer_interval = -1;
- priv->runner_sys_prio = -1;
- priv->runner_min_ports = -1;
- priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
+ priv->team_setting = nm_team_setting_new (FALSE, NULL);
}
/**
@@ -1729,14 +1480,7 @@ finalize (GObject *object)
{
NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (object);
- g_free (priv->config);
- g_free (priv->runner);
- g_free (priv->runner_hwaddr_policy);
- g_free (priv->runner_tx_balancer);
- g_free (priv->runner_agg_select_policy);
- if (priv->runner_tx_hash)
- g_ptr_array_unref (priv->runner_tx_hash);
- g_ptr_array_unref (priv->link_watchers);
+ nm_team_setting_free (priv->team_setting);
G_OBJECT_CLASS (nm_setting_team_parent_class)->finalize (object);
}
@@ -1754,8 +1498,10 @@ nm_setting_team_class_init (NMSettingTeamClass *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;
/**
* NMSettingTeam:config:
@@ -1771,7 +1517,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
* description: Team 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_CONFIG, "", "",
NULL,
G_PARAM_READWRITE |
@@ -1785,7 +1531,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_NOTIFY_PEERS_COUNT] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT] =
g_param_spec_int (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@@ -1798,7 +1544,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_NOTIFY_PEERS_INTERVAL] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL] =
g_param_spec_int (NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@@ -1811,7 +1557,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_MCAST_REJOIN_COUNT] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT] =
g_param_spec_int (NM_SETTING_TEAM_MCAST_REJOIN_COUNT, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@@ -1824,7 +1570,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_MCAST_REJOIN_INTERVAL] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL] =
g_param_spec_int (NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@@ -1836,14 +1582,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
* 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).
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER] =
g_param_spec_string (NM_SETTING_TEAM_RUNNER, "", "",
NULL,
G_PARAM_READWRITE |
@@ -1856,7 +1598,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_HWADDR_POLICY] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY] =
g_param_spec_string (NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, "", "",
NULL,
G_PARAM_READWRITE |
@@ -1869,7 +1611,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_TX_HASH] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH] =
g_param_spec_boxed (NM_SETTING_TEAM_RUNNER_TX_HASH, "", "",
G_TYPE_STRV,
G_PARAM_READWRITE |
@@ -1883,7 +1625,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_TX_BALANCER] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER] =
g_param_spec_string (NM_SETTING_TEAM_RUNNER_TX_BALANCER, "", "",
NULL,
G_PARAM_READWRITE |
@@ -1896,7 +1638,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_TX_BALANCER_INTERVAL] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL] =
g_param_spec_int (NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@@ -1909,7 +1651,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_ACTIVE] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE] =
g_param_spec_boolean (NM_SETTING_TEAM_RUNNER_ACTIVE, "", "",
FALSE,
G_PARAM_READWRITE |
@@ -1922,7 +1664,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_FAST_RATE] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE] =
g_param_spec_boolean (NM_SETTING_TEAM_RUNNER_FAST_RATE, "", "",
FALSE,
G_PARAM_READWRITE |
@@ -1935,7 +1677,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_SYS_PRIO] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO] =
g_param_spec_int (NM_SETTING_TEAM_RUNNER_SYS_PRIO, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@@ -1948,7 +1690,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_MIN_PORTS] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS] =
g_param_spec_int (NM_SETTING_TEAM_RUNNER_MIN_PORTS, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@@ -1961,7 +1703,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_RUNNER_AGG_SELECT_POLICY] =
+ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY] =
g_param_spec_string (NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, "", "",
NULL,
G_PARAM_READWRITE |
@@ -1981,14 +1723,14 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
*
* Since: 1.12
**/
- obj_properties[PROP_LINK_WATCHERS] =
+ obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS] =
g_param_spec_boxed (NM_SETTING_TEAM_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);
@@ -2007,7 +1749,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
_nm_setting_get_deprecated_virtual_interface_name,
NULL);
- 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,
NULL, properties_override);
diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c
index 95aa4691d2..9d437f8a1f 100644
--- a/libnm-core/nm-team-utils.c
+++ b/libnm-core/nm-team-utils.c
@@ -17,6 +17,1996 @@
* Copyright 2019 Red Hat, Inc.
*/
+#define NM_VALUE_TYPE_DEFINE_FUNCTIONS
+
#include "nm-default.h"
#include "nm-team-utils.h"
+
+#include "nm-errors.h"
+#include "nm-utils-private.h"
+#include "nm-json.h"
+#include "nm-glib-aux/nm-json-aux.h"
+#include "nm-core-internal.h"
+#include "nm-setting-team.h"
+#include "nm-setting-team-port.h"
+
+/*****************************************************************************/
+
+/* we rely on "config" being the first. At various places we iterate over attribute types,
+ * starting after "config".*/
+G_STATIC_ASSERT (_NM_TEAM_ATTRIBUTE_0 == 0);
+G_STATIC_ASSERT (NM_TEAM_ATTRIBUTE_CONFIG == 1);
+
+typedef struct {
+ const char *const*js_keys;
+ const char *dbus_name;
+ NMValueTypUnion default_val;
+ NMTeamAttribute team_attr;
+ NMValueType value_type;
+ guint8 field_offset;
+ guint8 js_keys_len;
+ bool for_master:1;
+ bool for_port:1;
+} TeamAttrData;
+
+#define TEAM_ATTR_IDX(_is_port, _team_attr) \
+ (( (!(_is_port) || (_team_attr) < _NM_TEAM_ATTRIBUTE_START) \
+ ? (int) (_team_attr) \
+ : (((int) (_NM_TEAM_ATTRIBUTE_MASTER_NUM - _NM_TEAM_ATTRIBUTE_START)) + ((int) (_team_attr)))) - 1)
+
+#define TEAM_ATTR_IDX_CONFIG (TEAM_ATTR_IDX (FALSE, NM_TEAM_ATTRIBUTE_CONFIG))
+
+static const TeamAttrData team_attr_datas[] = {
+
+#define _JS_KEYS(...) \
+ .js_keys = NM_MAKE_STRV (__VA_ARGS__), \
+ .js_keys_len = NM_NARG (__VA_ARGS__)
+
+#define _INIT(_is_port, _team_attr, field, _value_type, _dbus_name, ...) \
+ [TEAM_ATTR_IDX (_is_port, _team_attr)] = { \
+ .for_master = (_team_attr) < _NM_TEAM_ATTRIBUTE_START || !(_is_port), \
+ .for_port = (_team_attr) < _NM_TEAM_ATTRIBUTE_START || (_is_port), \
+ .team_attr = (_team_attr), \
+ .field_offset = G_STRUCT_OFFSET (NMTeamSetting, _data_priv.field), \
+ .value_type = (_value_type), \
+ .dbus_name = ""_dbus_name"", \
+ __VA_ARGS__ \
+ }
+
+ _INIT (0, NM_TEAM_ATTRIBUTE_CONFIG, _js_str, NM_VALUE_TYPE_UNSPEC, NM_SETTING_TEAM_CONFIG, ),
+
+ _INIT (0, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, link_watchers, NM_VALUE_TYPE_UNSPEC, NM_SETTING_TEAM_LINK_WATCHERS, _JS_KEYS ("link_watch"), ),
+
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT, master.notify_peers_count, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, _JS_KEYS ("notify_peers", "count"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL, master.notify_peers_interval, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, _JS_KEYS ("notify_peers", "interval"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT, master.mcast_rejoin_count, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_MCAST_REJOIN_COUNT, _JS_KEYS ("mcast_rejoin", "count"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL, master.mcast_rejoin_interval, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, _JS_KEYS ("mcast_rejoin", "interval"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER, master.runner, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER, _JS_KEYS ("runner", "name"), .default_val.v_string = NM_SETTING_TEAM_RUNNER_DEFAULT, ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY, master.runner_hwaddr_policy, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, _JS_KEYS ("runner", "hwaddr_policy"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, master.runner_tx_hash, NM_VALUE_TYPE_UNSPEC, NM_SETTING_TEAM_RUNNER_TX_HASH, _JS_KEYS ("runner", "tx_hash"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER, master.runner_tx_balancer, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER_TX_BALANCER, _JS_KEYS ("runner", "tx_balancer", "name"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL, master.runner_tx_balancer_interval, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, _JS_KEYS ("runner", "tx_balancer", "balancing_interval"), .default_val.v_int32 = -1 ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE, master.runner_active, NM_VALUE_TYPE_BOOL, NM_SETTING_TEAM_RUNNER_ACTIVE, _JS_KEYS ("runner", "active"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE, master.runner_fast_rate, NM_VALUE_TYPE_BOOL, NM_SETTING_TEAM_RUNNER_FAST_RATE, _JS_KEYS ("runner", "fast_rate"), ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO, master.runner_sys_prio, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_RUNNER_SYS_PRIO, _JS_KEYS ("runner", "sys_prio"), .default_val.v_int32 = -1, ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS, master.runner_min_ports, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_RUNNER_MIN_PORTS, _JS_KEYS ("runner", "min_ports"), .default_val.v_int32 = -1, ),
+ _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY, master.runner_agg_select_policy, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, _JS_KEYS ("runner", "agg_select_policy"), ),
+
+ _INIT (1, NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID, port.queue_id, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_QUEUE_ID, _JS_KEYS ("queue_id"), .default_val.v_int32 = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT, ),
+ _INIT (1, NM_TEAM_ATTRIBUTE_PORT_PRIO, port.prio, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_PRIO, _JS_KEYS ("prio"), ),
+ _INIT (1, NM_TEAM_ATTRIBUTE_PORT_STICKY, port.sticky, NM_VALUE_TYPE_BOOL, NM_SETTING_TEAM_PORT_STICKY, _JS_KEYS ("sticky"), ),
+ _INIT (1, NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO, port.lacp_prio, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_LACP_PRIO, _JS_KEYS ("lacp_prio"), .default_val.v_int32 = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT, ),
+ _INIT (1, NM_TEAM_ATTRIBUTE_PORT_LACP_KEY, port.lacp_key, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_LACP_KEY, _JS_KEYS ("lacp_key"), ),
+
+#undef _INIT
+
+};
+
+/*****************************************************************************/
+
+typedef enum {
+ LINK_WATCHER_ATTRIBUTE_NAME,
+ LINK_WATCHER_ATTRIBUTE_TARGET_HOST,
+ LINK_WATCHER_ATTRIBUTE_SOURCE_HOST,
+ LINK_WATCHER_ATTRIBUTE_DELAY_UP,
+ LINK_WATCHER_ATTRIBUTE_DELAY_DOWN,
+ LINK_WATCHER_ATTRIBUTE_INIT_WAIT,
+ LINK_WATCHER_ATTRIBUTE_INTERVAL,
+ LINK_WATCHER_ATTRIBUTE_MISSED_MAX,
+ LINK_WATCHER_ATTRIBUTE_VLANID,
+ LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE,
+ LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE,
+ LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS,
+} LinkWatcherAttribute;
+
+typedef struct {
+ const char *js_key;
+ NMValueTypUnion default_val;
+ LinkWatcherAttribute link_watcher_attr;
+ NMValueType value_type;
+} LinkWatcherAttrData;
+
+static const LinkWatcherAttrData link_watcher_attr_datas[] = {
+#define _INIT(_link_watcher_attr, _js_key, _value_type, ...) \
+ [_link_watcher_attr] = { \
+ .link_watcher_attr = (_link_watcher_attr), \
+ .value_type = (_value_type), \
+ .js_key = (""_js_key""), \
+ __VA_ARGS__ \
+ }
+ _INIT (LINK_WATCHER_ATTRIBUTE_NAME, "name", NM_VALUE_TYPE_STRING, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_TARGET_HOST, "target_host", NM_VALUE_TYPE_STRING, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, "source_host", NM_VALUE_TYPE_STRING, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_DELAY_UP, "delay_up", NM_VALUE_TYPE_INT, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_DELAY_DOWN, "delay_down", NM_VALUE_TYPE_INT, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_INIT_WAIT, "init_wait", NM_VALUE_TYPE_INT, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_INTERVAL, "interval", NM_VALUE_TYPE_INT, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_MISSED_MAX, "missed_max", NM_VALUE_TYPE_INT, .default_val.v_int = 3, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_VLANID, "vlanid", NM_VALUE_TYPE_INT, .default_val.v_int = -1, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, "validate_active", NM_VALUE_TYPE_BOOL, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, "validate_inactive", NM_VALUE_TYPE_BOOL, ),
+ _INIT (LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS, "send_always", NM_VALUE_TYPE_BOOL, ),
+#undef _INIT
+};
+
+/*****************************************************************************/
+
+static const TeamAttrData *_team_attr_data_get (gboolean is_port,
+ NMTeamAttribute team_attr);
+static gpointer _team_setting_get_field (const NMTeamSetting *self,
+ const TeamAttrData *attr_data);
+static gboolean _team_setting_verify (const NMTeamSetting *self,
+ GError **error);
+static void _link_watcher_to_json (const NMTeamLinkWatcher *link_watcher,
+ GString *gstr);
+
+/*****************************************************************************/
+
+static void
+_team_attr_data_ASSERT (const TeamAttrData *attr_data)
+{
+#if NM_MORE_ASSERTS > 5
+ nm_assert (attr_data);
+ if (attr_data->for_port)
+ nm_assert (attr_data == _team_attr_data_get (TRUE, attr_data->team_attr));
+ if (attr_data->for_master)
+ nm_assert (attr_data == _team_attr_data_get (FALSE, attr_data->team_attr));
+ nm_assert ((attr_data - team_attr_datas) == TEAM_ATTR_IDX (attr_data->for_port, attr_data->team_attr));
+ nm_assert (attr_data->value_type > 0);
+ nm_assert (attr_data->field_offset < sizeof (NMTeamSetting));
+ nm_assert (attr_data->js_keys_len == NM_PTRARRAY_LEN (attr_data->js_keys));
+ nm_assert (attr_data->dbus_name);
+ {
+ static int checked = 0;
+
+ if (checked == 0) {
+ checked = 1;
+
+ for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++)
+ _team_attr_data_ASSERT (attr_data);
+ }
+ }
+#endif
+}
+
+static gboolean
+_team_attr_data_is_relevant (const TeamAttrData *attr_data,
+ gboolean is_port)
+{
+ return is_port
+ ? attr_data->for_port
+ : attr_data->for_master;
+}
+
+static const TeamAttrData *
+_team_attr_data_get (gboolean is_port,
+ NMTeamAttribute team_attr)
+{
+ const int idx = TEAM_ATTR_IDX (is_port, team_attr);
+
+ nm_assert ( idx >= 0
+ && idx < G_N_ELEMENTS (team_attr_datas));
+ nm_assert (team_attr_datas[idx].team_attr == team_attr);
+ nm_assert (_team_attr_data_is_relevant (&team_attr_datas[idx], is_port));
+
+ return &team_attr_datas[idx];
+}
+
+static const TeamAttrData *
+_team_attr_data_find_for_dbus_name (gboolean is_port,
+ const char *dbus_name)
+{
+ const TeamAttrData *attr_data;
+
+ for (attr_data = team_attr_datas; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) {
+ if ( _team_attr_data_is_relevant (attr_data, is_port)
+ && nm_streq (dbus_name, attr_data->dbus_name))
+ return attr_data;
+ }
+ return NULL;
+}
+
+static const NMValueTypUnion *
+_team_attr_data_get_default (const TeamAttrData *attr_data,
+ gboolean is_port,
+ const char *v_master_runner,
+ NMValueTypUnion *value_tmp)
+{
+ GPtrArray *v_ptrarray;
+
+ /* unfortunately, the default certain values depends on other values :(
+ *
+ * For examle, master attributes depend on the "runner" setting.
+ * and port settings default to the ethtool link-watcher. */
+
+ if (is_port) {
+
+ switch (attr_data->team_attr) {
+ case NM_TEAM_ATTRIBUTE_LINK_WATCHERS: {
+ static GPtrArray *volatile gl_arr = NULL;
+
+again_port_link_watchers:
+ v_ptrarray = g_atomic_pointer_get (&gl_arr);
+ if (G_UNLIKELY (!v_ptrarray)) {
+ v_ptrarray = g_ptr_array_new_full (1, (GDestroyNotify) nm_team_link_watcher_unref);
+ g_ptr_array_add (v_ptrarray, nm_team_link_watcher_new_ethtool (0, 0, NULL));
+ if (!g_atomic_pointer_compare_and_exchange (&gl_arr, NULL, v_ptrarray)) {
+ g_ptr_array_unref (v_ptrarray);
+ goto again_port_link_watchers;
+ }
+ }
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_ptrarray, v_ptrarray);
+ }
+ default:
+ break;
+ }
+
+ } else {
+
+ if (NM_IN_STRSET (v_master_runner, NULL,
+ NM_SETTING_TEAM_RUNNER_DEFAULT)) {
+ /* a runner %NULL is the same as NM_SETTING_TEAM_RUNNER_DEFAULT ("roundrobin").
+ * In this case, the settings in attr_data are accurate. */
+ return &attr_data->default_val;
+ }
+
+ switch (attr_data->team_attr) {
+ case NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT:
+ if (nm_streq (v_master_runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP))
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_int32, NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT);
+ break;
+ case NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT:
+ if (nm_streq (v_master_runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP))
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_int32, NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT);
+ break;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY:
+ if (nm_streq (v_master_runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP))
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_string, "same_all");
+ break;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH:
+ if (NM_IN_STRSET (v_master_runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE,
+ NM_SETTING_TEAM_RUNNER_LACP)) {
+ static GPtrArray *volatile gl_arr = NULL;
+
+again_master_runner_tx_hash:
+ v_ptrarray = g_atomic_pointer_get (&gl_arr);
+ if (G_UNLIKELY (!v_ptrarray)) {
+ v_ptrarray = g_ptr_array_sized_new (3);
+ g_ptr_array_add (v_ptrarray, "eth");
+ g_ptr_array_add (v_ptrarray, "ipv4");
+ g_ptr_array_add (v_ptrarray, "ipv6");
+ if (!g_atomic_pointer_compare_and_exchange (&gl_arr, NULL, v_ptrarray)) {
+ g_ptr_array_unref (v_ptrarray);
+ goto again_master_runner_tx_hash;
+ }
+ }
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_ptrarray, v_ptrarray);
+ }
+ break;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL:
+ if (NM_IN_STRSET (v_master_runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE,
+ NM_SETTING_TEAM_RUNNER_LACP))
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_int32, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT);
+ break;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE:
+ if (nm_streq (v_master_runner, NM_SETTING_TEAM_RUNNER_LACP))
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_bool, TRUE);
+ break;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO:
+ if (nm_streq (v_master_runner, NM_SETTING_TEAM_RUNNER_LACP))
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_int32, NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT);
+ break;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS:
+ if (nm_streq (v_master_runner, NM_SETTING_TEAM_RUNNER_LACP))
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_int32, 0);
+ break;
+ case NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY:
+ if (nm_streq (v_master_runner, NM_SETTING_TEAM_RUNNER_LACP))
+ return NM_VALUE_TYP_UNION_SET (value_tmp, v_string, NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return &attr_data->default_val;
+}
+static int
+_team_attr_data_cmp (const TeamAttrData *attr_data,
+ gboolean is_port,
+ gconstpointer val_a,
+ gconstpointer val_b)
+{
+ const GPtrArray *v_ptrarray_a;
+ const GPtrArray *v_ptrarray_b;
+ guint len;
+
+ _team_attr_data_ASSERT (attr_data);
+ nm_assert (val_a);
+ nm_assert (val_b);
+
+ if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC)
+ NM_CMP_RETURN (nm_value_type_cmp (attr_data->value_type, val_a, val_b));
+ else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) {
+ v_ptrarray_a = *((const GPtrArray *const*) val_a);
+ v_ptrarray_b = *((const GPtrArray *const*) val_b);
+ len = v_ptrarray_a ? v_ptrarray_a->len : 0u;
+ NM_CMP_DIRECT (len, (v_ptrarray_b ? v_ptrarray_b->len : 0u));
+ if (len > 0) {
+ NM_CMP_RETURN (nm_team_link_watchers_cmp ((const NMTeamLinkWatcher *const*) v_ptrarray_a->pdata,
+ (const NMTeamLinkWatcher *const*) v_ptrarray_b->pdata,
+ len,
+ FALSE));
+ }
+ } else if ( !is_port
+ && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) {
+ v_ptrarray_a = *((const GPtrArray *const*) val_a);
+ v_ptrarray_b = *((const GPtrArray *const*) val_b);
+ NM_CMP_RETURN (_nm_utils_strv_cmp_n (v_ptrarray_a ? (const char *const*) v_ptrarray_a->pdata : NULL,
+ v_ptrarray_a ? v_ptrarray_a->len : 0u,
+ v_ptrarray_b ? (const char *const*) v_ptrarray_b->pdata : NULL,
+ v_ptrarray_b ? v_ptrarray_b->len : 0u));
+ } else
+ nm_assert_not_reached ();
+ return 0;
+}
+
+static gboolean
+_team_attr_data_equal (const TeamAttrData *attr_data,
+ gboolean is_port,
+ gconstpointer val_a,
+ gconstpointer val_b)
+{
+ return _team_attr_data_cmp (attr_data, is_port, val_a, val_b) == 0;
+}
+
+static void
+_team_attr_data_copy (const TeamAttrData *attr_data,
+ gboolean is_port,
+ gpointer dst,
+ gconstpointer src)
+{
+ GPtrArray *v_ptrarray_dst;
+ const GPtrArray *v_ptrarray_src;
+ GPtrArray *dst_array;
+ guint i, len;
+
+ if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC)
+ nm_value_type_copy (attr_data->value_type, dst, src);
+ else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) {
+ v_ptrarray_src = *((const GPtrArray *const *) src);
+ v_ptrarray_dst = *((GPtrArray **) dst);
+ len = (v_ptrarray_src ? v_ptrarray_src->len : 0u);
+
+ if (len == 0) {
+ if (v_ptrarray_dst)
+ g_ptr_array_set_size (v_ptrarray_dst, 0);
+ } else {
+ dst_array = g_ptr_array_new_full (len, (GDestroyNotify) nm_team_link_watcher_unref);
+ for (i = 0; i < len; i++) {
+ if (v_ptrarray_src->pdata[i]) {
+ nm_team_link_watcher_ref (v_ptrarray_src->pdata[i]);
+ g_ptr_array_add (dst_array,v_ptrarray_src->pdata[i]);
+ }
+ }
+ if (v_ptrarray_dst)
+ g_ptr_array_unref (v_ptrarray_dst);
+ *((GPtrArray **) dst) = dst_array;
+ }
+ } else if ( !is_port
+ && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) {
+ v_ptrarray_src = *((const GPtrArray *const *) src);
+ v_ptrarray_dst = *((GPtrArray **) dst);
+ len = (v_ptrarray_src ? v_ptrarray_src->len : 0u);
+
+ if ( v_ptrarray_src
+ && v_ptrarray_src->len > 0) {
+ dst_array = g_ptr_array_new_full (v_ptrarray_src->len, g_free);
+ for (i = 0; i < v_ptrarray_src->len; i++)
+ g_ptr_array_add (dst_array, g_strdup (v_ptrarray_src->pdata[i]));
+ } else
+ dst_array = NULL;
+ if (v_ptrarray_dst)
+ g_ptr_array_unref (v_ptrarray_dst);
+ *((GPtrArray **) dst) = dst_array;
+ } else
+ nm_assert_not_reached ();
+}
+
+static gboolean
+_team_attr_data_is_default (const TeamAttrData *attr_data,
+ gboolean is_port,
+ const char *v_master_runner,
+ gconstpointer p_field)
+{
+ const NMValueTypUnion *default_value;
+ NMValueTypUnion value_tmp;
+
+ _team_attr_data_ASSERT (attr_data);
+ nm_assert (p_field);
+
+ default_value = _team_attr_data_get_default (attr_data,
+ is_port,
+ v_master_runner,
+ &value_tmp);
+ if (_team_attr_data_equal (attr_data,
+ is_port,
+ default_value,
+ p_field))
+ return TRUE;
+
+ if ( attr_data->value_type == NM_VALUE_TYPE_STRING
+ && default_value->v_string) {
+ const char *str0 = NULL;
+
+ /* this is a string value, whose default is not NULL. In such a case,
+ * NULL is also treated like the default. */
+ if (_team_attr_data_equal (attr_data,
+ is_port,
+ &str0,
+ p_field))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+_team_attr_data_to_json (const TeamAttrData *attr_data,
+ gboolean is_port,
+ GString *gstr,
+ gconstpointer p_field)
+{
+ guint i;
+
+ _team_attr_data_ASSERT (attr_data);
+ nm_assert (p_field);
+
+ nm_json_aux_gstr_append_obj_name (gstr,
+ attr_data->js_keys[attr_data->js_keys_len - 1],
+ '\0');
+
+ if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) {
+ nm_value_type_to_json (attr_data->value_type, gstr, p_field);
+ return;
+ }
+
+ if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) {
+ const GPtrArray *v_ptrarray = *((const GPtrArray *const*) p_field);
+
+ if (!v_ptrarray)
+ g_string_append (gstr, "null");
+ else if (v_ptrarray->len == 0)
+ g_string_append (gstr, "[ ]");
+ else if (v_ptrarray->len == 1)
+ _link_watcher_to_json (v_ptrarray->pdata[0], gstr);
+ else {
+ g_string_append (gstr, "[ ");
+ for (i = 0; i < v_ptrarray->len; i++) {
+ if (i > 0)
+ nm_json_aux_gstr_append_delimiter (gstr);
+ _link_watcher_to_json (v_ptrarray->pdata[i], gstr);
+ }
+ g_string_append (gstr, " ]");
+ }
+ return;
+ }
+
+ if ( !is_port
+ && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) {
+ const GPtrArray *v_ptrarray = *((const GPtrArray *const*) p_field);
+
+ if (!v_ptrarray)
+ g_string_append (gstr, "null");
+ else {
+ g_string_append (gstr, "[ ");
+ for (i = 0; i < v_ptrarray->len; i++) {
+ if (i > 0)
+ nm_json_aux_gstr_append_delimiter (gstr);
+ nm_json_aux_gstr_append_string (gstr, v_ptrarray->pdata[i]);
+ }
+ g_string_append (gstr, i > 0 ? " ]" : "]");
+ }
+ return;
+ }
+
+ nm_assert_not_reached ();
+}
+
+/*****************************************************************************/
+
+static void
+_team_setting_ASSERT (const NMTeamSetting *self)
+{
+ nm_assert (self);
+ nm_assert (!self->d._js_str_need_synthetize || !self->d._js_str);
+#if NM_MORE_ASSERTS > 2
+ if (!self->d.strict_validated) {
+ nm_assert (!self->d._js_str_need_synthetize);
+ nm_assert (self->d._js_str);
+ }
+ nm_assert (self->d.link_watchers);
+ nm_assert ( self->d.is_port
+ || !self->d.master.runner_tx_hash
+ || self->d.master.runner_tx_hash->len > 0);
+#endif
+}
+
+static gpointer
+_team_setting_get_field (const NMTeamSetting *self,
+ const TeamAttrData *attr_data)
+{
+ _team_setting_ASSERT (self);
+ _team_attr_data_ASSERT (attr_data);
+ nm_assert (_team_attr_data_is_relevant (attr_data, self->d.is_port));
+
+#if NM_MORE_ASSERTS > 5
+ if ( attr_data->for_master
+ && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO )
+ nm_assert ((gpointer) (((char *) self) + attr_data->field_offset) == &self->d.master.runner_sys_prio);
+#endif
+
+ return (((char *) self) + attr_data->field_offset);
+}
+
+static guint32
+_team_setting_attribute_changed (NMTeamSetting *self,
+ NMTeamAttribute team_attr,
+ gboolean changed)
+{
+ guint32 changed_flags;
+
+ nm_assert (_team_attr_data_get (self->d.is_port, team_attr));
+
+ if (!changed) {
+ /* a regular attribute was set, but the value did not change.
+ *
+ * If we previously were in non-strict mode, then
+ *
+ * - switch to strict-mode. Clearly the user set a regular attribute
+ * and hence now we want to validate the setting.
+ *
+ * - clear the JSON string. We need to regenerate it.
+ */
+ if (self->_data_priv.strict_validated)
+ return 0;
+ changed_flags = nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG);
+ } else {
+ changed_flags = nm_team_attribute_to_flags (team_attr)
+ | nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG);
+ }
+
+ nm_clear_g_free ((char **) &self->_data_priv._js_str);
+ self->_data_priv.strict_validated = TRUE;
+ self->_data_priv._js_str_need_synthetize = TRUE;
+
+ return changed_flags;
+}
+
+static void
+_team_setting_field_to_json (const NMTeamSetting *self,
+ GString *gstr,
+ gboolean prepend_delimiter,
+ NMTeamAttribute team_attr)
+{
+ const TeamAttrData *attr_data = _team_attr_data_get (self->d.is_port, team_attr);
+
+ if (prepend_delimiter)
+ nm_json_aux_gstr_append_delimiter (gstr);
+ _team_attr_data_to_json (attr_data,
+ self->d.is_port,
+ gstr,
+ _team_setting_get_field (self, attr_data));
+}
+
+static gboolean
+_team_setting_fields_to_json_maybe (const NMTeamSetting *self,
+ GString *gstr,
+ gboolean prepend_delimiter,
+ const bool is_default_lst[static _NM_TEAM_ATTRIBUTE_NUM],
+ const NMTeamAttribute *team_attrs_lst,
+ gsize team_attrs_lst_len)
+{
+ gsize i;
+ gboolean any_added = FALSE;
+
+ for (i = 0; i < team_attrs_lst_len; i++) {
+ NMTeamAttribute team_attr = team_attrs_lst[i];
+
+ if (is_default_lst[team_attr])
+ continue;
+
+ _team_setting_field_to_json (self, gstr, prepend_delimiter, team_attr);
+ any_added = TRUE;
+ prepend_delimiter = TRUE;
+ }
+ return any_added;
+}
+
+static guint32
+_team_setting_set (NMTeamSetting *self,
+ gboolean modify,
+ const bool *has_lst,
+ const NMValueTypUnion *val_lst)
+{
+ guint32 changed_flags = 0;
+ const TeamAttrData *attr_data;
+ const char *v_master_runner;
+
+ nm_assert ((!has_lst) == (!val_lst));
+
+ if (!self->d.is_port) {
+ if ( has_lst
+ && has_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER])
+ v_master_runner = val_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER].v_string;
+ else {
+ nm_assert (nm_streq0 (_team_attr_data_get (FALSE, NM_TEAM_ATTRIBUTE_MASTER_RUNNER)->default_val.v_string,
+ NM_SETTING_TEAM_RUNNER_DEFAULT));
+ v_master_runner = NM_SETTING_TEAM_RUNNER_DEFAULT;
+ }
+ } else
+ v_master_runner = NULL;
+
+ for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) {
+ NMValueTypUnion value_tmp;
+ const NMValueTypUnion *p_val;
+ gconstpointer p_field;
+
+ if (!_team_attr_data_is_relevant (attr_data, self->d.is_port))
+ continue;
+
+ if ( has_lst
+ && has_lst[attr_data->team_attr])
+ p_val = &val_lst[attr_data->team_attr];
+ else {
+ p_val = _team_attr_data_get_default (attr_data,
+ self->d.is_port,
+ v_master_runner,
+ &value_tmp);
+ }
+
+ p_field = _team_setting_get_field (self, attr_data);
+
+ if (!_team_attr_data_equal (attr_data,
+ self->d.is_port,
+ p_val,
+ p_field)) {
+ if (modify) {
+ _team_attr_data_copy (attr_data,
+ self->d.is_port,
+ (gpointer) p_field,
+ p_val);
+ }
+ changed_flags |= nm_team_attribute_to_flags (attr_data->team_attr);
+ }
+ }
+
+ return changed_flags;
+}
+
+static guint32
+_team_setting_check_default (const NMTeamSetting *self)
+{
+ return _team_setting_set ((NMTeamSetting *) self, FALSE, NULL, NULL);
+}
+
+static guint32
+_team_setting_set_default (NMTeamSetting *self)
+{
+ return _team_setting_set (self, TRUE, NULL, NULL);
+}
+
+/*****************************************************************************/
+
+gconstpointer
+_nm_team_setting_value_get (const NMTeamSetting *self,
+ NMTeamAttribute team_attr,
+ NMValueType value_type)
+{
+ const TeamAttrData *attr_data = _team_attr_data_get (self->d.is_port, team_attr);
+
+ nm_assert (value_type == attr_data->value_type);
+
+ return _team_setting_get_field (self, attr_data);
+}
+
+static guint32
+_team_setting_value_set (NMTeamSetting *self,
+ NMTeamAttribute team_attr,
+ NMValueType value_type,
+ gconstpointer val)
+{
+ const TeamAttrData *attr_data;
+ gpointer p_field;
+
+ nm_assert (self);
+
+ attr_data = _team_attr_data_get (self->d.is_port, team_attr);
+
+ nm_assert (val);
+ nm_assert (value_type == attr_data->value_type);
+
+ p_field = _team_setting_get_field (self, attr_data);
+
+ if (nm_value_type_equal (attr_data->value_type, p_field, val))
+ return 0u;
+ nm_value_type_copy (attr_data->value_type, p_field, val);
+ return nm_team_attribute_to_flags (team_attr);
+}
+
+guint32
+_nm_team_setting_value_set (NMTeamSetting *self,
+ NMTeamAttribute team_attr,
+ NMValueType value_type,
+ gconstpointer val)
+{
+ return _team_setting_attribute_changed (self,
+ team_attr,
+ (_team_setting_value_set (self,
+ team_attr,
+ value_type,
+ val) != 0u));
+}
+
+guint32
+nm_team_setting_value_link_watchers_add (NMTeamSetting *self,
+ const NMTeamLinkWatcher *link_watcher)
+{
+ guint i;
+
+ for (i = 0; i < self->d.link_watchers->len; i++) {
+ if (nm_team_link_watcher_equal (self->d.link_watchers->pdata[i], link_watcher))
+ return _team_setting_attribute_changed (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, FALSE);
+ }
+ g_ptr_array_add ((GPtrArray *) self->d.link_watchers,
+ _nm_team_link_watcher_ref ((NMTeamLinkWatcher *) link_watcher));
+ return _team_setting_attribute_changed (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, TRUE);
+}
+
+guint32
+nm_team_setting_value_link_watchers_remove_by_value (NMTeamSetting *self,
+ const NMTeamLinkWatcher *link_watcher)
+{
+ guint i;
+
+ for (i = 0; i < self->d.link_watchers->len; i++) {
+ if (nm_team_link_watcher_equal (self->d.link_watchers->pdata[i],
+ link_watcher))
+ return nm_team_setting_value_link_watchers_remove (self, i);
+ }
+ return _team_setting_attribute_changed (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, FALSE);
+}
+
+guint32
+nm_team_setting_value_link_watchers_remove (NMTeamSetting *self,
+ guint idx)
+{
+ g_ptr_array_remove_index ((GPtrArray *) self->d.link_watchers, idx);
+ return _team_setting_attribute_changed (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, TRUE);
+}
+
+static guint32
+_team_setting_value_link_watchers_set_list (NMTeamSetting *self,
+ const NMTeamLinkWatcher *const*arr,
+ guint len)
+{
+ if ( self->d.link_watchers->len == len
+ && nm_team_link_watchers_cmp ((const NMTeamLinkWatcher *const*) self->d.link_watchers->pdata,
+ arr,
+ len,
+ FALSE) == 0)
+ return 0;
+
+ if (len == 0)
+ g_ptr_array_set_size ((GPtrArray *) self->d.link_watchers, 0);
+ else {
+ _nm_unused gs_unref_ptrarray GPtrArray *old_val_destroy = NULL;
+ guint i;
+
+ old_val_destroy = (GPtrArray *) g_steal_pointer (&self->_data_priv.link_watchers);
+
+ self->_data_priv.link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
+
+ for (i = 0; i < len; i++) {
+ if (arr[i]) {
+ g_ptr_array_add ((GPtrArray *) self->d.link_watchers,
+ _nm_team_link_watcher_ref ((NMTeamLinkWatcher *) arr[i]));
+ }
+ }
+ }
+
+ return nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_LINK_WATCHERS);
+}
+
+guint32
+nm_team_setting_value_link_watchers_set_list (NMTeamSetting *self,
+ const NMTeamLinkWatcher *const*arr,
+ guint len)
+{
+ return _team_setting_attribute_changed (self,
+ NM_TEAM_ATTRIBUTE_LINK_WATCHERS,
+ (_team_setting_value_link_watchers_set_list (self,
+ arr,
+ len) != 0u));
+}
+
+/*****************************************************************************/
+
+guint32
+nm_team_setting_value_master_runner_tx_hash_add (NMTeamSetting *self,
+ const char *txhash)
+{
+ guint i;
+
+ if (!self->d.master.runner_tx_hash)
+ self->_data_priv.master.runner_tx_hash = g_ptr_array_new_with_free_func (g_free);
+ else {
+ for (i = 0; i < self->d.master.runner_tx_hash->len; i++) {
+ if (nm_streq (txhash, self->d.master.runner_tx_hash->pdata[i]))
+ return _team_setting_attribute_changed (self, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, FALSE);
+ }
+ }
+ g_ptr_array_add ((GPtrArray *) self->d.master.runner_tx_hash, g_strdup (txhash));
+ return _team_setting_attribute_changed (self, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, TRUE);
+}
+
+guint32
+nm_team_setting_value_master_runner_tx_hash_remove (NMTeamSetting *self,
+ guint idx)
+{
+ g_ptr_array_remove_index ((GPtrArray *) self->d.master.runner_tx_hash, idx);
+ return _team_setting_attribute_changed (self, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, TRUE);
+}
+
+static guint32
+_team_setting_value_master_runner_tx_hash_set_list (NMTeamSetting *self,
+ const char *const*arr,
+ guint len)
+{
+ _nm_unused gs_unref_ptrarray GPtrArray *old_val_destroy = NULL;
+ guint i;
+
+ if (_nm_utils_strv_cmp_n (self->d.master.runner_tx_hash ? (const char *const*) self->d.master.runner_tx_hash->pdata : NULL,
+ self->d.master.runner_tx_hash ? self->d.master.runner_tx_hash->len : 0u,
+ arr,
+ len) == 0)
+ return 0u;
+
+ old_val_destroy = (GPtrArray *) g_steal_pointer (&self->_data_priv.master.runner_tx_hash);
+
+ for (i = 0; i < len; i++) {
+ if (!arr[i])
+ continue;
+ if (!self->d.master.runner_tx_hash)
+ self->_data_priv.master.runner_tx_hash = g_ptr_array_new_with_free_func (g_free);
+ g_ptr_array_add ((GPtrArray *) self->d.master.runner_tx_hash, g_strdup (arr[i]));
+ }
+
+ return nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH);
+}
+
+guint32
+nm_team_setting_value_master_runner_tx_hash_set_list (NMTeamSetting *self,
+ const char *const*arr,
+ guint len)
+{
+ return _team_setting_attribute_changed (self,
+ NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH,
+ (_team_setting_value_master_runner_tx_hash_set_list (self,
+ arr,
+ len) != 0u));
+}
+
+/*****************************************************************************/
+
+#define _LINK_WATCHER_ATTR_GET(args, link_watcher_attribute, _value_type) \
+ ({ \
+ const NMValueTypUnioMaybe *const _args = (args); \
+ \
+ nm_assert (link_watcher_attr_datas[(link_watcher_attribute)].value_type == (_value_type)); \
+ \
+ _args[(link_watcher_attribute)].has \
+ ? &_args[(link_watcher_attribute)].val \
+ : &link_watcher_attr_datas[(link_watcher_attribute)].default_val; \
+ })
+#define _LINK_WATCHER_ATTR_GET_BOOL(args, link_watcher_attribute) (_LINK_WATCHER_ATTR_GET (args, link_watcher_attribute, NM_VALUE_TYPE_BOOL )->v_bool)
+#define _LINK_WATCHER_ATTR_GET_INT(args, link_watcher_attribute) (_LINK_WATCHER_ATTR_GET (args, link_watcher_attribute, NM_VALUE_TYPE_INT )->v_int)
+#define _LINK_WATCHER_ATTR_GET_STRING(args, link_watcher_attribute) (_LINK_WATCHER_ATTR_GET (args, link_watcher_attribute, NM_VALUE_TYPE_STRING )->v_string)
+
+#define _LINK_WATCHER_ATTR_SET(args, link_watcher_attribute, _value_type, c_type, val) \
+ ({ \
+ nm_assert (link_watcher_attr_datas[(link_watcher_attribute)].value_type == (_value_type)); \
+ \
+ NM_VALUE_TYP_UNIO_MAYBE_SET (&(args)[(link_watcher_attribute)], c_type, (val)); \
+ })
+#define _LINK_WATCHER_ATTR_SET_BOOL(args, link_watcher_attribute, val) _LINK_WATCHER_ATTR_SET((args), (link_watcher_attribute), NM_VALUE_TYPE_BOOL, v_bool, (val))
+#define _LINK_WATCHER_ATTR_SET_INT(args, link_watcher_attribute, val) _LINK_WATCHER_ATTR_SET((args), (link_watcher_attribute), NM_VALUE_TYPE_INT, v_int, (val))
+#define _LINK_WATCHER_ATTR_SET_STRING(args, link_watcher_attribute, val) _LINK_WATCHER_ATTR_SET((args), (link_watcher_attribute), NM_VALUE_TYPE_STRING, v_string, (val))
+
+static void
+_link_watcher_to_json (const NMTeamLinkWatcher *link_watcher,
+ GString *gstr)
+{
+ NMValueTypUnioMaybe args[G_N_ELEMENTS (link_watcher_attr_datas)] = { };
+ NMTeamLinkWatcherArpPingFlags v_arp_ping_flags;
+ const char *v_name;
+ int i;
+
+ if (!link_watcher) {
+ g_string_append (gstr, "null");
+ return;
+ }
+
+ v_name = nm_team_link_watcher_get_name (link_watcher);
+
+ g_string_append (gstr, "{ ");
+
+ nm_json_aux_gstr_append_obj_name (gstr, "name", '\0');
+ nm_json_aux_gstr_append_string (gstr, v_name);
+
+ if (nm_streq (v_name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
+ _LINK_WATCHER_ATTR_SET_INT (args, LINK_WATCHER_ATTRIBUTE_DELAY_UP, nm_team_link_watcher_get_delay_up (link_watcher));
+ _LINK_WATCHER_ATTR_SET_INT (args, LINK_WATCHER_ATTRIBUTE_DELAY_DOWN, nm_team_link_watcher_get_delay_down (link_watcher));
+ } else if (NM_IN_STRSET (v_name, NM_TEAM_LINK_WATCHER_NSNA_PING,
+ NM_TEAM_LINK_WATCHER_ARP_PING)) {
+ _LINK_WATCHER_ATTR_SET_INT (args, LINK_WATCHER_ATTRIBUTE_INIT_WAIT, nm_team_link_watcher_get_init_wait (link_watcher));
+ _LINK_WATCHER_ATTR_SET_INT (args, LINK_WATCHER_ATTRIBUTE_INTERVAL, nm_team_link_watcher_get_interval (link_watcher));
+ _LINK_WATCHER_ATTR_SET_INT (args, LINK_WATCHER_ATTRIBUTE_MISSED_MAX, nm_team_link_watcher_get_missed_max (link_watcher));
+ _LINK_WATCHER_ATTR_SET_STRING (args, LINK_WATCHER_ATTRIBUTE_TARGET_HOST, nm_team_link_watcher_get_target_host (link_watcher));
+ if (nm_streq (v_name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
+ v_arp_ping_flags = nm_team_link_watcher_get_flags (link_watcher);
+ _LINK_WATCHER_ATTR_SET_INT (args, LINK_WATCHER_ATTRIBUTE_VLANID, nm_team_link_watcher_get_vlanid (link_watcher));
+ _LINK_WATCHER_ATTR_SET_STRING (args, LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, nm_team_link_watcher_get_source_host (link_watcher));
+ _LINK_WATCHER_ATTR_SET_BOOL (args, LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, NM_FLAGS_HAS (v_arp_ping_flags, NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE));
+ _LINK_WATCHER_ATTR_SET_BOOL (args, LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, NM_FLAGS_HAS (v_arp_ping_flags, NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE));
+ _LINK_WATCHER_ATTR_SET_BOOL (args, LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS, NM_FLAGS_HAS (v_arp_ping_flags, NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS));
+ }
+ }
+
+ for (i = 0; i < (int) G_N_ELEMENTS (link_watcher_attr_datas); i++) {
+ const NMValueTypUnioMaybe *p_val = &args[i];
+ const LinkWatcherAttrData *attr_data = &link_watcher_attr_datas[i];
+
+ if (!p_val->has)
+ continue;
+ if (nm_value_type_equal (attr_data->value_type, &attr_data->default_val, &p_val->val))
+ continue;
+ nm_json_aux_gstr_append_delimiter (gstr);
+ nm_json_aux_gstr_append_obj_name (gstr, attr_data->js_key, '\0');
+ nm_value_type_to_json (attr_data->value_type, gstr, &p_val->val);
+ }
+
+ g_string_append (gstr, "}");
+}
+
+#if WITH_JSON_VALIDATION
+static NMTeamLinkWatcher *
+_link_watcher_from_json (const json_t *root_js_obj,
+ gboolean *out_unrecognized_content)
+{
+ NMValueTypUnioMaybe args[G_N_ELEMENTS (link_watcher_attr_datas)] = { };
+ const char *j_key;
+ json_t *j_val;
+ const char *v_name;
+ NMTeamLinkWatcher *result = NULL;
+
+ if (!json_is_object (root_js_obj))
+ goto fail;
+
+ json_object_foreach ((json_t *) root_js_obj, j_key, j_val) {
+ const LinkWatcherAttrData *attr_data = NULL;
+ NMValueTypUnioMaybe *parse_result;
+
+ if (j_key) {
+ int i;
+
+ for (i = 0; i < (int) G_N_ELEMENTS (link_watcher_attr_datas); i++) {
+ if (nm_streq (link_watcher_attr_datas[i].js_key, j_key)) {
+ attr_data = &link_watcher_attr_datas[i];
+ break;
+ }
+ }
+ }
+ if (!attr_data) {
+ *out_unrecognized_content = TRUE;
+ continue;
+ }
+
+ parse_result = &args[attr_data->link_watcher_attr];
+
+ if (parse_result->has)
+ *out_unrecognized_content = TRUE;
+
+ if (!nm_value_type_from_json (attr_data->value_type, j_val, &parse_result->val))
+ *out_unrecognized_content = TRUE;
+ else
+ parse_result->has = TRUE;
+ }
+
+#define _PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES(_parse_results, ...) \
+ ({ \
+ int _i; \
+ \
+ for (_i = 0; _i < (int) G_N_ELEMENTS ((_parse_results)); _i++) { \
+ if ( (_parse_results)[_i].has \
+ && !NM_IN_SET ((LinkWatcherAttribute) _i, LINK_WATCHER_ATTRIBUTE_NAME, \
+ __VA_ARGS__)) \
+ break; \
+ } \
+ \
+ (_i == (int) G_N_ELEMENTS ((_parse_results))); \
+ })
+
+ v_name = _LINK_WATCHER_ATTR_GET_STRING (args, LINK_WATCHER_ATTRIBUTE_NAME);
+
+ if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
+ if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args,
+ LINK_WATCHER_ATTRIBUTE_DELAY_UP,
+ LINK_WATCHER_ATTRIBUTE_DELAY_DOWN))
+ *out_unrecognized_content = TRUE;
+ result = nm_team_link_watcher_new_ethtool (_LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_DELAY_UP),
+ _LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_DELAY_DOWN),
+ NULL);
+ } else if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_NSNA_PING)) {
+ if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args,
+ LINK_WATCHER_ATTRIBUTE_INIT_WAIT,
+ LINK_WATCHER_ATTRIBUTE_INTERVAL,
+ LINK_WATCHER_ATTRIBUTE_MISSED_MAX,
+ LINK_WATCHER_ATTRIBUTE_TARGET_HOST))
+ *out_unrecognized_content = TRUE;
+ result = nm_team_link_watcher_new_nsna_ping (_LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_INIT_WAIT),
+ _LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_INTERVAL),
+ _LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_MISSED_MAX),
+ _LINK_WATCHER_ATTR_GET_STRING (args, LINK_WATCHER_ATTRIBUTE_TARGET_HOST),
+ NULL);
+ } else if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
+ NMTeamLinkWatcherArpPingFlags v_flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE;
+
+ if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args,
+ LINK_WATCHER_ATTRIBUTE_INIT_WAIT,
+ LINK_WATCHER_ATTRIBUTE_INTERVAL,
+ LINK_WATCHER_ATTRIBUTE_MISSED_MAX,
+ LINK_WATCHER_ATTRIBUTE_VLANID,
+ LINK_WATCHER_ATTRIBUTE_TARGET_HOST,
+ LINK_WATCHER_ATTRIBUTE_SOURCE_HOST,
+ LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE,
+ LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE,
+ LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS))
+ *out_unrecognized_content = TRUE;
+
+ if (_LINK_WATCHER_ATTR_GET_BOOL (args, LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE))
+ v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
+ if (_LINK_WATCHER_ATTR_GET_BOOL (args, LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE))
+ v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE;
+ if (_LINK_WATCHER_ATTR_GET_BOOL (args, LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS))
+ v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
+
+ result = nm_team_link_watcher_new_arp_ping2 (_LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_INIT_WAIT),
+ _LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_INTERVAL),
+ _LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_MISSED_MAX),
+ _LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_VLANID),
+ _LINK_WATCHER_ATTR_GET_STRING (args, LINK_WATCHER_ATTRIBUTE_TARGET_HOST),
+ _LINK_WATCHER_ATTR_GET_STRING (args, LINK_WATCHER_ATTRIBUTE_SOURCE_HOST),
+ v_flags,
+ NULL);
+ }
+
+ if (result)
+ return result;
+fail:
+ *out_unrecognized_content = TRUE;
+ return NULL;
+}
+#endif
+
+/*****************************************************************************/
+
+const char *
+nm_team_setting_config_get (const NMTeamSetting *self)
+{
+ char *js_str;
+
+ nm_assert (self);
+
+ if (G_LIKELY (!self->d._js_str_need_synthetize))
+ return self->d._js_str;
+
+ nm_assert (!self->d._js_str);
+ nm_assert (self->d.strict_validated);
+
+ if (_team_setting_check_default (self) == 0) {
+ /* the default is set. We signal this as a NULL JSON string.
+ * Nothing to do. */
+ js_str = NULL;
+ } else {
+ const TeamAttrData *attr_data;
+ GString *gstr;
+ bool is_default_lst[_NM_TEAM_ATTRIBUTE_NUM] = { FALSE, };
+ gboolean list_is_empty = TRUE;
+ const char *v_master_runner;
+
+ gstr = g_string_new (NULL);
+
+ g_string_append (gstr, "{ ");
+
+ v_master_runner = self->d.is_port
+ ? NULL
+ : self->d.master.runner;
+
+ for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) {
+ if (_team_attr_data_is_relevant (attr_data, self->d.is_port)) {
+ is_default_lst[attr_data->team_attr] = _team_attr_data_is_default (attr_data,
+ self->d.is_port,
+ v_master_runner,
+ _team_setting_get_field (self, attr_data));
+ }
+ }
+
+ if (self->d.is_port) {
+ static const NMTeamAttribute attr_lst_port[] = {
+ NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID,
+ NM_TEAM_ATTRIBUTE_PORT_PRIO,
+ NM_TEAM_ATTRIBUTE_PORT_STICKY,
+ NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO,
+ NM_TEAM_ATTRIBUTE_PORT_LACP_KEY,
+ };
+
+ if (_team_setting_fields_to_json_maybe (self, gstr, !list_is_empty, is_default_lst, attr_lst_port, G_N_ELEMENTS (attr_lst_port)))
+ list_is_empty = FALSE;
+ } else {
+
+ if ( !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY]) {
+ static const NMTeamAttribute attr_lst_runner_pt1[] = {
+ NM_TEAM_ATTRIBUTE_MASTER_RUNNER,
+ NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY,
+ NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH,
+ };
+ static const NMTeamAttribute attr_lst_runner_pt2[] = {
+ NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER,
+ NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL,
+ };
+ static const NMTeamAttribute attr_lst_runner_pt3[] = {
+ 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,
+ };
+ gboolean list_is_empty2 = TRUE;
+
+ if (!list_is_empty)
+ nm_json_aux_gstr_append_delimiter (gstr);
+ nm_json_aux_gstr_append_obj_name (gstr, "runner", '{');
+
+ if (_team_setting_fields_to_json_maybe (self, gstr, !list_is_empty2, is_default_lst, attr_lst_runner_pt1, G_N_ELEMENTS (attr_lst_runner_pt1)))
+ list_is_empty2 = FALSE;
+
+ if ( !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL]) {
+ if (!list_is_empty2)
+ nm_json_aux_gstr_append_delimiter (gstr);
+ nm_json_aux_gstr_append_obj_name (gstr, "tx_balancer", '{');
+ if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, is_default_lst, attr_lst_runner_pt2, G_N_ELEMENTS (attr_lst_runner_pt2)))
+ nm_assert_not_reached ();
+ g_string_append (gstr, " }");
+ list_is_empty2 = FALSE;
+ }
+
+ if (_team_setting_fields_to_json_maybe (self, gstr, !list_is_empty2, is_default_lst, attr_lst_runner_pt3, G_N_ELEMENTS (attr_lst_runner_pt3)))
+ list_is_empty2 = FALSE;
+
+ nm_assert (!list_is_empty2);
+ g_string_append (gstr, " }");
+ list_is_empty = FALSE;
+ }
+
+ if ( !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL]) {
+ static const NMTeamAttribute attr_lst_notify_peers[] = {
+ NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT,
+ NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL,
+ };
+
+ if (!list_is_empty)
+ nm_json_aux_gstr_append_delimiter (gstr);
+ nm_json_aux_gstr_append_obj_name (gstr, "notify_peers", '{');
+ if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, is_default_lst, attr_lst_notify_peers, G_N_ELEMENTS (attr_lst_notify_peers)))
+ nm_assert_not_reached ();
+ g_string_append (gstr, " }");
+ list_is_empty = FALSE;
+ }
+
+ if ( !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT]
+ || !is_default_lst[NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL]) {
+ static const NMTeamAttribute attr_lst_notify_peers[] = {
+ NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT,
+ NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL,
+ };
+
+ if (!list_is_empty)
+ nm_json_aux_gstr_append_delimiter (gstr);
+ nm_json_aux_gstr_append_obj_name (gstr, "mcast_rejoin", '{');
+ if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, is_default_lst, attr_lst_notify_peers, G_N_ELEMENTS (attr_lst_notify_peers)))
+ nm_assert_not_reached ();
+ g_string_append (gstr, " }");
+ list_is_empty = FALSE;
+ }
+ }
+
+ if (!is_default_lst[NM_TEAM_ATTRIBUTE_LINK_WATCHERS]) {
+ _team_setting_field_to_json (self, gstr, !list_is_empty, NM_TEAM_ATTRIBUTE_LINK_WATCHERS);
+ list_is_empty = FALSE;
+ }
+ if (!list_is_empty)
+ g_string_append (gstr, " }");
+
+ js_str = g_string_free (gstr, list_is_empty);;
+ }
+
+ /* mutate the constant object. In C++ speak, these fields are "mutable".
+ * That is because we construct the JSON string lazily/on-demand. */
+ *((char **) &self->_data_priv._js_str) = js_str;
+ *((bool *) &self->_data_priv._js_str_need_synthetize) = FALSE;
+
+ return self->d._js_str;
+}
+
+/*****************************************************************************/
+
+#if WITH_JSON_VALIDATION
+static gboolean
+_attr_data_match_keys (const TeamAttrData *attr_data,
+ const char *const*keys,
+ guint8 n_keys)
+{
+ guint8 i;
+
+ _team_attr_data_ASSERT (attr_data);
+ nm_assert (keys);
+ nm_assert (n_keys > 0);
+ nm_assert (({
+ gboolean all_non_null = TRUE;
+
+ for (i = 0; i < n_keys; i++)
+ all_non_null = all_non_null && keys[i] && keys[i][0] != '\0';
+ all_non_null;
+ }));
+
+ if (attr_data->js_keys_len < n_keys)
+ return FALSE;
+ for (i = 0; i < n_keys; i++) {
+ if (!nm_streq (keys[i], attr_data->js_keys[i]))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static const TeamAttrData *
+_attr_data_find_by_json_key (gboolean is_port,
+ const char *const*keys,
+ guint8 n_keys)
+{
+ const TeamAttrData *attr_data;
+
+ for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) {
+ if ( _team_attr_data_is_relevant (attr_data, is_port)
+ && _attr_data_match_keys (attr_data, keys, n_keys))
+ return attr_data;
+ }
+
+ return NULL;
+}
+
+static void
+_js_parse_locate_keys (NMTeamSetting *self,
+ json_t *root_js_obj,
+ json_t *found_keys[static _NM_TEAM_ATTRIBUTE_NUM],
+ gboolean *out_unrecognized_content)
+{
+ const char *keys[3];
+ const char *cur_key1;
+ const char *cur_key2;
+ const char *cur_key3;
+ json_t *cur_val1;
+ json_t *cur_val2;
+ json_t *cur_val3;
+
+#define _handle(_self, _cur_key, _cur_val, _keys, _level, _found_keys, _out_unrecognized_content) \
+ ({ \
+ const TeamAttrData *_attr_data; \
+ gboolean _handled = FALSE; \
+ \
+ (_keys)[(_level) - 1] = (_cur_key); \
+ _attr_data = _attr_data_find_by_json_key ((_self)->d.is_port, (_keys), (_level)); \
+ if ( _attr_data \
+ && _attr_data->js_keys_len == (_level)) { \
+ if ((_found_keys)[_attr_data->team_attr]) \
+ *(_out_unrecognized_content) = TRUE; \
+ (_found_keys)[_attr_data->team_attr] = (_cur_val); \
+ _handled = TRUE; \
+ } else if ( !_attr_data \
+ || !json_is_object ((_cur_val))) { \
+ *(_out_unrecognized_content) = TRUE; \
+ _handled = TRUE; \
+ } \
+ _handled; \
+ })
+
+ json_object_foreach (root_js_obj, cur_key1, cur_val1) {
+ if (!_handle (self, cur_key1, cur_val1, keys, 1, found_keys, out_unrecognized_content)) {
+ json_object_foreach (cur_val1, cur_key2, cur_val2) {
+ if (!_handle (self, cur_key2, cur_val2, keys, 2, found_keys, out_unrecognized_content)) {
+ json_object_foreach (cur_val2, cur_key3, cur_val3) {
+ if (!_handle (self, cur_key3, cur_val3, keys, 3, found_keys, out_unrecognized_content))
+ *out_unrecognized_content = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+#undef _handle
+}
+
+static void
+_js_parse_unpack (gboolean is_port,
+ json_t *found_keys[static _NM_TEAM_ATTRIBUTE_NUM],
+ bool out_has_lst[static _NM_TEAM_ATTRIBUTE_NUM],
+ NMValueTypUnion out_val_lst[static _NM_TEAM_ATTRIBUTE_NUM],
+ gboolean *out_unrecognized_content,
+ GPtrArray **out_ptr_array_link_watchers_free,
+ GPtrArray **out_ptr_array_master_runner_tx_hash_free)
+{
+ const TeamAttrData *attr_data;
+
+ for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) {
+ NMValueTypUnion *p_out_val;
+ gboolean valid = FALSE;
+ json_t *arg_js_obj;
+
+ if (!_team_attr_data_is_relevant (attr_data, is_port))
+ continue;
+
+ nm_assert (!out_has_lst[attr_data->team_attr]);
+
+ arg_js_obj = found_keys[attr_data->team_attr];
+ if (!arg_js_obj)
+ continue;
+
+ p_out_val = &out_val_lst[attr_data->team_attr];
+
+ if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC)
+ valid = nm_value_type_from_json (attr_data->value_type, arg_js_obj, p_out_val);
+ else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) {
+ GPtrArray *link_watchers = NULL;
+ NMTeamLinkWatcher *link_watcher;
+
+ nm_assert (out_ptr_array_link_watchers_free && !*out_ptr_array_link_watchers_free);
+ if (json_is_array (arg_js_obj)) {
+ gsize i, len;
+
+ len = json_array_size (arg_js_obj);
+ link_watchers = g_ptr_array_new_full (len, (GDestroyNotify) nm_team_link_watcher_unref);
+ for (i = 0; i < len; i++) {
+ link_watcher = _link_watcher_from_json (json_array_get (arg_js_obj, i),
+ out_unrecognized_content);
+ if (link_watcher)
+ g_ptr_array_add (link_watchers, link_watcher);
+ }
+ } else {
+ link_watcher = _link_watcher_from_json (arg_js_obj,
+ out_unrecognized_content);
+ if (link_watcher) {
+ link_watchers = g_ptr_array_new_full (1, (GDestroyNotify) nm_team_link_watcher_unref);
+ g_ptr_array_add (link_watchers, link_watcher);
+ }
+ }
+ if (link_watchers) {
+ valid = TRUE;
+ p_out_val->v_ptrarray = link_watchers;
+ *out_ptr_array_link_watchers_free = link_watchers;
+ }
+ } else if ( !is_port
+ && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) {
+ GPtrArray *strv = NULL;
+
+ nm_assert (out_ptr_array_master_runner_tx_hash_free && !*out_ptr_array_master_runner_tx_hash_free);
+ if (json_is_array (arg_js_obj)) {
+ gsize i, len;
+
+ len = json_array_size (arg_js_obj);
+ if (len > 0) {
+ strv = g_ptr_array_sized_new (len);
+ for (i = 0; i < len; i++) {
+ const char *v_string;
+
+ if ( nm_jansson_json_as_string (json_array_get (arg_js_obj, i),
+ &v_string) <= 0
+ || !v_string
+ || v_string[0] == '\0') {
+ /* we remember that there was some invalid content, but parts of the
+ * list could still be parsed. */
+ *out_unrecognized_content = TRUE;
+ continue;
+ }
+ g_ptr_array_add (strv, (char *) v_string);
+ }
+ }
+ valid = TRUE;
+ *out_ptr_array_master_runner_tx_hash_free = strv;
+ }
+ p_out_val->v_ptrarray = strv;
+ } else
+ nm_assert_not_reached ();
+
+ out_has_lst[attr_data->team_attr] = valid;
+ if (!valid)
+ *out_unrecognized_content = TRUE;
+ }
+}
+#endif
+
+guint32
+nm_team_setting_config_set (NMTeamSetting *self, const char *js_str)
+{
+ guint32 changed_flags = 0;
+ gboolean do_set_default = TRUE;
+ gboolean new_strict_validated = FALSE;
+ gboolean new_js_str_invalid = FALSE;
+
+ _team_setting_ASSERT (self);
+
+ if ( !js_str
+ || js_str[0] == '\0') {
+ changed_flags = _team_setting_set_default (self);
+ if ( changed_flags != 0
+ || !nm_streq0 (js_str, self->d._js_str))
+ changed_flags |= nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG);
+ nm_clear_g_free ((char **) &self->_data_priv._js_str);
+ self->_data_priv._js_str = g_strdup (js_str);
+ self->_data_priv._js_str_need_synthetize = FALSE;
+ self->_data_priv.strict_validated = TRUE;
+ self->_data_priv.js_str_invalid = FALSE;
+ return changed_flags;
+ }
+
+ if ( self->d._js_str
+ && nm_streq (js_str, self->d._js_str))
+ return 0;
+
+ changed_flags |= nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG);
+
+#if WITH_JSON_VALIDATION
+ if (js_str[0] != '\0') {
+ nm_auto_decref_json json_t *root_js_obj = NULL;
+
+ if (nm_jansson_load ())
+ root_js_obj = json_loads (js_str, 0, NULL);
+
+ if ( !root_js_obj
+ || !json_is_object (root_js_obj))
+ new_js_str_invalid = TRUE;
+ else {
+ gboolean unrecognized_content = FALSE;
+ bool has_lst[_NM_TEAM_ATTRIBUTE_NUM] = { FALSE, };
+ NMValueTypUnion val_lst[_NM_TEAM_ATTRIBUTE_NUM];
+ json_t *found_keys[_NM_TEAM_ATTRIBUTE_NUM] = { NULL, };
+ gs_unref_ptrarray GPtrArray *ptr_array_master_runner_tx_hash_free = NULL;
+ gs_unref_ptrarray GPtrArray *ptr_array_link_watchers_free = NULL;
+
+ _js_parse_locate_keys (self,
+ root_js_obj,
+ found_keys,
+ &unrecognized_content);
+
+ _js_parse_unpack (self->d.is_port,
+ found_keys,
+ has_lst,
+ val_lst,
+ &unrecognized_content,
+ &ptr_array_link_watchers_free,
+ &ptr_array_master_runner_tx_hash_free);
+
+ do_set_default = FALSE;
+
+ changed_flags |= _team_setting_set (self,
+ TRUE,
+ has_lst,
+ val_lst);
+
+ if ( !unrecognized_content
+ && _team_setting_verify (self, NULL)) {
+ /* if we could parse everything without unexpected/unknown data,
+ * we switch into strictly validating mode. */
+ new_strict_validated = TRUE;
+ }
+ }
+ }
+
+#endif
+
+ if (do_set_default)
+ changed_flags |= _team_setting_set_default (self);
+
+ self->_data_priv.strict_validated = new_strict_validated;
+ self->_data_priv._js_str_need_synthetize = FALSE;
+ self->_data_priv.js_str_invalid = new_js_str_invalid;
+ g_free ((char *) self->_data_priv._js_str);
+ self->_data_priv._js_str = g_strdup (js_str);
+
+ return changed_flags;
+}
+
+/*****************************************************************************/
+
+static void
+_team_setting_prefix_error (const NMTeamSetting *self,
+ GError **error,
+ const char *prop_name_master,
+ const char *prop_name_port)
+{
+ _team_setting_ASSERT (self);
+ nm_assert ( self->d.is_port
+ ? (!!prop_name_port)
+ : (!!prop_name_master));
+ g_prefix_error (error,
+ "%s.%s: ",
+ self->d.is_port
+ ? NM_SETTING_TEAM_PORT_SETTING_NAME
+ : NM_SETTING_TEAM_SETTING_NAME,
+ self->d.is_port
+ ? prop_name_master
+ : prop_name_port);
+}
+
+static gboolean
+_team_setting_verify (const NMTeamSetting *self,
+ GError **error)
+{
+ guint i;
+ const char *js_str;
+
+ if (!self->d.is_port) {
+ if (!self->d.master.runner) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
+ _("missing runner"));
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_RUNNER, NULL);
+ return FALSE;
+ }
+ if ( self->d.master.runner
+ && g_ascii_strcasecmp (self->d.master.runner, NM_SETTING_TEAM_RUNNER_BROADCAST) != 0
+ && g_ascii_strcasecmp (self->d.master.runner, NM_SETTING_TEAM_RUNNER_ROUNDROBIN) != 0
+ && g_ascii_strcasecmp (self->d.master.runner, NM_SETTING_TEAM_RUNNER_RANDOM) != 0
+ && g_ascii_strcasecmp (self->d.master.runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP) != 0
+ && g_ascii_strcasecmp (self->d.master.runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE) != 0
+ && g_ascii_strcasecmp (self->d.master.runner, NM_SETTING_TEAM_RUNNER_LACP) != 0) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
+ _("invalid runner \"%s\""), self->d.master.runner);
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_RUNNER, NULL);
+ return FALSE;
+ }
+
+ if (self->d.master.runner_tx_hash) {
+ for (i = 0; i < self->d.master.runner_tx_hash->len; i++) {
+ const char *val = self->d.master.runner_tx_hash->pdata[i];
+
+ if (!val[0]) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
+ _("invalid runner.tx-hash"));
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_RUNNER_TX_HASH, NULL);
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < self->d.link_watchers->len; i++) {
+ NMTeamLinkWatcher *link_watcher = self->d.link_watchers->pdata[i];
+ const char *name = nm_team_link_watcher_get_name (link_watcher);
+
+ if (!NM_IN_STRSET (name,
+ NM_TEAM_LINK_WATCHER_ETHTOOL,
+ NM_TEAM_LINK_WATCHER_ARP_PING,
+ NM_TEAM_LINK_WATCHER_NSNA_PING)) {
+ if (!name) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
+ _("missing link watcher name"));
+ } else {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
+ _("unknown link watcher \"%s\""), name);
+ }
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_LINK_WATCHERS, NM_SETTING_TEAM_PORT_LINK_WATCHERS);
+ return FALSE;
+ }
+
+ if ( NM_IN_STRSET (name,
+ NM_TEAM_LINK_WATCHER_ARP_PING,
+ NM_TEAM_LINK_WATCHER_NSNA_PING)
+ && !nm_team_link_watcher_get_target_host (link_watcher)) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
+ _("missing target host"));
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_LINK_WATCHERS, NM_SETTING_TEAM_PORT_LINK_WATCHERS);
+ return FALSE;
+ }
+ if ( nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING)
+ && !nm_team_link_watcher_get_source_host (link_watcher)) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
+ _("missing source address"));
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_LINK_WATCHERS, NM_SETTING_TEAM_PORT_LINK_WATCHERS);
+ return FALSE;
+ }
+ }
+
+ /* we always materialize the JSON string. That is because we want to validate the
+ * string length of the resulting JSON. */
+ js_str = nm_team_setting_config_get (self);
+
+ if (js_str) {
+ if (strlen (js_str) > 1*1024*1024) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("team config exceeds size limit"));
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_CONFIG, NM_SETTING_TEAM_PORT_CONFIG);
+ return FALSE;
+ }
+ if (!g_utf8_validate (js_str, -1, NULL)) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("team config is not valid UTF-8"));
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_CONFIG, NM_SETTING_TEAM_PORT_CONFIG);
+ return FALSE;
+ }
+ if (self->d.js_str_invalid) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("invalid json"));
+ _team_setting_prefix_error (self, error, NM_SETTING_TEAM_CONFIG, NM_SETTING_TEAM_PORT_CONFIG);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
+nm_team_setting_verify (const NMTeamSetting *self,
+ GError **error)
+{
+ return _team_setting_verify (self, error);
+}
+
+/*****************************************************************************/
+
+int
+nm_team_setting_cmp (const NMTeamSetting *self_a,
+ const NMTeamSetting *self_b,
+ gboolean ignore_js_str)
+{
+ const TeamAttrData *attr_data;
+
+ NM_CMP_SELF (self_a, self_b);
+
+ NM_CMP_FIELD_UNSAFE (self_a, self_b, d.is_port);
+
+ for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) {
+ if (_team_attr_data_is_relevant (attr_data, self_a->d.is_port)) {
+ NM_CMP_RETURN (_team_attr_data_cmp (attr_data,
+ self_a->d.is_port,
+ _team_setting_get_field (self_a, attr_data),
+ _team_setting_get_field (self_b, attr_data)));
+ }
+ }
+
+ if (!ignore_js_str) {
+ NM_CMP_DIRECT_STRCMP0 (nm_team_setting_config_get (self_a),
+ nm_team_setting_config_get (self_b));
+ }
+
+ return 0;
+}
+
+guint32
+nm_team_setting_reset (NMTeamSetting *self,
+ const NMTeamSetting *src)
+{
+ const TeamAttrData *attr_data;
+ guint32 changed;
+
+ _team_setting_ASSERT (self);
+ _team_setting_ASSERT (src);
+ nm_assert (self->d.is_port == src->d.is_port);
+
+ if (self == src)
+ return 0;
+
+ changed = 0;
+
+ for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) {
+ if (!_team_attr_data_is_relevant (attr_data, self->d.is_port))
+ continue;
+ if (_team_attr_data_equal (attr_data,
+ self->d.is_port,
+ _team_setting_get_field (self, attr_data),
+ _team_setting_get_field (src, attr_data)))
+ continue;
+ _team_attr_data_copy (attr_data,
+ self->d.is_port,
+ _team_setting_get_field (self, attr_data),
+ _team_setting_get_field (src, attr_data));
+ changed |= nm_team_attribute_to_flags (attr_data->team_attr);
+ }
+
+ if (!nm_streq0 (self->d._js_str, src->d._js_str)) {
+ g_free ((char *) self->_data_priv._js_str);
+ self->_data_priv._js_str = g_strdup (src->d._js_str);
+ changed |= nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG);
+ } else if (changed != 0)
+ changed |= nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG);
+
+ self->_data_priv._js_str_need_synthetize = src->d._js_str_need_synthetize;
+ self->_data_priv.strict_validated = src->d.strict_validated;
+ self->_data_priv.js_str_invalid = src->d.js_str_invalid;
+
+ return changed;
+}
+
+static void
+_variants_list_unref_auto (GVariant *(*p_variants)[])
+{
+ int i;
+
+ for (i = 0; i < _NM_TEAM_ATTRIBUTE_NUM; i++)
+ nm_g_variant_unref ((*p_variants)[i]);
+}
+
+gboolean
+nm_team_setting_reset_from_dbus (NMTeamSetting *self,
+ GVariant *setting_dict,
+ GHashTable *keys,
+ guint32 *out_changed,
+ guint /* NMSettingParseFlags */ parse_flags,
+ GError **error)
+{
+ nm_auto (_variants_list_unref_auto) GVariant *variants[_NM_TEAM_ATTRIBUTE_NUM] = { NULL, };
+ gs_unref_ptrarray GPtrArray *v_link_watchers = NULL;
+ const TeamAttrData *attr_data;
+ GVariantIter iter;
+ const char *v_key;
+ GVariant *v_val;
+
+ *out_changed = 0;
+
+ g_variant_iter_init (&iter, setting_dict);
+ while (g_variant_iter_next (&iter, "{&sv}", &v_key, &v_val)) {
+ _nm_unused gs_unref_variant GVariant *v_val_free = v_val;
+ const GVariantType *variant_type = NULL;
+
+ attr_data = _team_attr_data_find_for_dbus_name (self->d.is_port, v_key);
+ if (!attr_data) {
+ /* _nm_setting_new_from_dbus() already checks for unknown keys. Don't
+ * do that here. */
+ continue;
+ }
+
+ if (keys)
+ g_hash_table_remove (keys, v_key);
+
+ if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC)
+ variant_type = nm_value_type_get_variant_type (attr_data->value_type);
+ else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_CONFIG)
+ variant_type = G_VARIANT_TYPE_STRING;
+ else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS)
+ variant_type = G_VARIANT_TYPE ("aa{sv}");
+ else if ( !self->d.is_port
+ && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH)
+ variant_type = G_VARIANT_TYPE_STRING_ARRAY;
+ else
+ nm_assert_not_reached ();
+
+ if (!g_variant_is_of_type (v_val, variant_type)) {
+ if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("invalid D-Bus type \"%s\""),
+ g_variant_get_type_string (v_val));
+ _team_setting_prefix_error (self,
+ error,
+ attr_data->dbus_name,
+ attr_data->dbus_name);
+ return FALSE;
+ }
+ continue;
+ }
+
+ /* _nm_setting_new_from_dbus() already checks for duplicate keys. Don't
+ * do that here. */
+ nm_g_variant_unref (variants[attr_data->team_attr]);
+ variants[attr_data->team_attr] = g_steal_pointer (&v_val_free);
+ }
+
+ *out_changed |= nm_team_setting_config_set (self,
+ variants[NM_TEAM_ATTRIBUTE_CONFIG]
+ ? g_variant_get_string (variants[NM_TEAM_ATTRIBUTE_CONFIG], NULL)
+ : NULL);
+
+ if ( variants[NM_TEAM_ATTRIBUTE_CONFIG]
+ && WITH_JSON_VALIDATION) {
+ /* for team settings, the JSON must be able to express all possible options. That means,
+ * if the GVariant contains both the JSON "config" and other options, then the other options
+ * are silently ignored. */
+ } else {
+ guint32 extra_changed = 0u;
+
+ if (variants[NM_TEAM_ATTRIBUTE_LINK_WATCHERS]) {
+ /* FIXME: handle errors for NM_SETTING_PARSE_FLAGS_STRICT.
+ *
+ * But then also move the check before starting to modify the setting so we fail
+ * early. */
+ v_link_watchers = _nm_utils_team_link_watchers_from_variant (variants[NM_TEAM_ATTRIBUTE_LINK_WATCHERS]);
+ }
+
+ for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) {
+ NMValueTypUnion val;
+ guint32 changed = 0u;
+
+ if (!_team_attr_data_is_relevant (attr_data, self->d.is_port))
+ continue;
+ if (!variants[attr_data->team_attr])
+ continue;
+
+ if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) {
+ nm_value_type_get_from_variant (attr_data->value_type, &val, variants[attr_data->team_attr], FALSE);
+ changed = _team_setting_value_set (self,
+ attr_data->team_attr,
+ attr_data->value_type,
+ &val);
+ } else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) {
+ changed = _team_setting_value_link_watchers_set_list (self,
+ v_link_watchers ? (const NMTeamLinkWatcher *const *) v_link_watchers->pdata : NULL,
+ v_link_watchers ? v_link_watchers->len : 0u);
+ } else if ( !self->d.is_port
+ && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) {
+ gs_free const char **strv = NULL;
+ gsize len;
+
+ strv = g_variant_get_strv (variants[attr_data->team_attr], &len);
+ changed = _team_setting_value_master_runner_tx_hash_set_list (self,
+ strv,
+ NM_MIN (len, (gsize) G_MAXUINT));
+ } else
+ nm_assert_not_reached ();
+
+ extra_changed |= changed;
+ }
+
+ if ( !variants[NM_TEAM_ATTRIBUTE_CONFIG]
+ && extra_changed) {
+ /* clear the JSON string so it can be regenerated. But only if we didn't set
+ * it above. */
+ self->_data_priv.strict_validated = TRUE;
+ self->_data_priv._js_str_need_synthetize = TRUE;
+ }
+
+ *out_changed |= extra_changed;
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+gboolean
+nm_team_setting_maybe_changed (NMSetting *source,
+ const GParamSpec *const*obj_properties,
+ guint32 changed_flags)
+{
+ NMTeamAttribute team_attr;
+ int count_flags;
+ guint32 ch;
+
+ if (changed_flags == 0u)
+ return FALSE;
+
+ count_flags = 0;
+ for (ch = changed_flags; ch != 0u; ch >>= 1) {
+ if (NM_FLAGS_HAS (ch, 0x1u))
+ count_flags++;
+ }
+
+ if (count_flags > 1)
+ g_object_freeze_notify (G_OBJECT (source));
+
+ ch = changed_flags;
+ for (team_attr = 0; team_attr < _NM_TEAM_ATTRIBUTE_NUM; team_attr++) {
+ if (!NM_FLAGS_ANY (ch, nm_team_attribute_to_flags (team_attr)))
+ continue;
+ g_object_notify_by_pspec (G_OBJECT (source),
+ (GParamSpec *) obj_properties[team_attr]);
+ ch &= ~nm_team_attribute_to_flags (team_attr);
+ if (ch == 0)
+ break;
+ }
+
+ if (count_flags > 1)
+ g_object_thaw_notify (G_OBJECT (source));
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+NMTeamSetting *
+nm_team_setting_new (gboolean is_port,
+ const char *js_str)
+{
+ NMTeamSetting *self;
+ gsize l;
+
+ G_STATIC_ASSERT_EXPR (sizeof (*self) == sizeof (self->_data_priv));
+ G_STATIC_ASSERT_EXPR (sizeof (*self) == NM_CONST_MAX (nm_offsetofend (NMTeamSetting, d.master), nm_offsetofend (NMTeamSetting, d.port)));
+
+ l = is_port
+ ? nm_offsetofend (NMTeamSetting, d.port)
+ : nm_offsetofend (NMTeamSetting, d.master);
+
+ self = g_malloc0 (l);
+
+ self->_data_priv.is_port = is_port;
+ self->_data_priv.strict_validated = TRUE;
+ self->_data_priv._js_str_need_synthetize = FALSE;
+ self->_data_priv.link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
+
+ _team_setting_ASSERT (self);
+
+ nm_team_setting_config_set (self, js_str);
+
+ _team_setting_ASSERT (self);
+
+ return self;
+}
+
+void
+nm_team_setting_free (NMTeamSetting *self)
+{
+ if (!self)
+ return;
+
+ _team_setting_ASSERT (self);
+
+ if (!self->d.is_port) {
+ nm_clear_pointer (((GPtrArray **) &self->_data_priv.master.runner_tx_hash), g_ptr_array_unref);
+ g_free ((char *) self->_data_priv.master.runner);
+ g_free ((char *) self->_data_priv.master.runner_hwaddr_policy);
+ g_free ((char *) self->_data_priv.master.runner_tx_balancer);
+ g_free ((char *) self->_data_priv.master.runner_agg_select_policy);
+ }
+ g_ptr_array_unref ((GPtrArray *) self->_data_priv.link_watchers);
+ g_free ((char *) self->_data_priv._js_str);
+ g_free (self);
+}
diff --git a/libnm-core/nm-team-utils.h b/libnm-core/nm-team-utils.h
index 6b3550000d..dad74468f1 100644
--- a/libnm-core/nm-team-utils.h
+++ b/libnm-core/nm-team-utils.h
@@ -24,4 +24,250 @@
#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);
+
+/*****************************************************************************/
+
+gboolean nm_team_setting_maybe_changed (struct _NMSetting *source,
+ const GParamSpec *const*obj_properties,
+ guint32 changed);
+
#endif /* __NM_TEAM_UITLS_H__ */
diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h
index 8d953191d3..ee949d8834 100644
--- a/libnm-core/nm-utils-private.h
+++ b/libnm-core/nm-utils-private.h
@@ -131,116 +131,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_ref (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
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 13bf626e9b..aa75ed42be 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -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,36 +5445,8 @@ 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:
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index 20736fb2d8..a8d182c457 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -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,19 +6808,42 @@ _team_config_equal_check (const char *conf1,
gboolean port_config,
gboolean 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);
}
- g_assert_cmpint (_nm_utils_team_config_equal (conf1, conf2, port_config), ==, expected);
+ 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,
@@ -6827,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 ("{ }",
@@ -6837,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,
@@ -6861,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 ("{ }",
@@ -6875,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,
@@ -6888,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
}
/*****************************************************************************/
diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c
index 7844b1aecd..a3be0bc8fa 100644
--- a/libnm-core/tests/test-setting.c
+++ b/libnm-core/tests/test-setting.c
@@ -1378,9 +1378,64 @@ test_team_port_full_config (void)
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
@@ -1393,11 +1448,6 @@ test_team_setting (void)
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);
- if (!WITH_JSON_VALIDATION) {
- g_test_skip ("disabled test without json-validation");
- return;
- }
-
g_assert (watcher1);
g_assert (watcher2);
@@ -1410,7 +1460,6 @@ test_team_setting (void)
_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,
@@ -1420,19 +1469,36 @@ test_team_setting (void)
_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)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}, \"runner\": {\"sys_prio\": 10}}");
+ 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_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}, \"runner\": {\"sys_prio\": 10}}");
+ 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)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}, \"runner\": {\"sys_prio\": 10}}");
+ 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)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}, \"runner\": {\"sys_prio\": 10}}");
+ 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 } }");
}
/*****************************************************************************/