summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-05-06 12:36:41 +0200
committerThomas Haller <thaller@redhat.com>2019-05-23 18:09:49 +0200
commit13f6f3a410b8f55b0e9eda9d5072cced380c2e95 (patch)
treef9caa1d3bc6f734a11662b9dee1223d3480737ad
parent539dfbcc42228185f4f2d490040e1761808f7d01 (diff)
libnm: rework team handling of JSON config
Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
-rw-r--r--clients/common/settings-docs.h.in2
-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
-rwxr-xr-xlibnm/generate-setting-docs.py2
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c10
13 files changed, 2728 insertions, 1583 deletions
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 8e6ca9db29..aa7d44d514 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -310,7 +310,7 @@
#define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL N_("Corresponds to the teamd mcast_rejoin.interval.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_COUNT N_("Corresponds to the teamd notify_peers.count.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL N_("Corresponds to the teamd notify_peers.interval.")
-#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\". When setting the runner, all the properties specific to the runner will be reset to the default value; all the properties specific to other runners will be set to an empty value (or if not possible to a default value).")
+#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\".")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_ACTIVE N_("Corresponds to the teamd runner.active.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY N_("Corresponds to the teamd runner.agg_select_policy.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_FAST_RATE N_("Corresponds to the teamd runner.fast_rate.")
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 } }");
}
/*****************************************************************************/
diff --git a/libnm/generate-setting-docs.py b/libnm/generate-setting-docs.py
index bf069cbd58..7e890074af 100755
--- a/libnm/generate-setting-docs.py
+++ b/libnm/generate-setting-docs.py
@@ -165,6 +165,8 @@ def get_default_value(setting, pspec, propxml):
default_value = '[]'
elif str(default_value).startswith('<'):
default_value = None
+ elif str(default_value).startswith('['):
+ default_value = None
return default_value
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8543e6f6f0..0da49c6d4e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -102,6 +102,7 @@ libnm-core/nm-setting-wireless-security.c
libnm-core/nm-setting-wireless.c
libnm-core/nm-setting-wpan.c
libnm-core/nm-setting.c
+libnm-core/nm-team-utils.c
libnm-core/nm-utils.c
libnm-core/nm-vpn-editor-plugin.c
libnm-core/nm-vpn-plugin-info.c
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 41397bde17..35340e8812 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -8939,11 +8939,15 @@ test_read_team_master_invalid (gconstpointer user_data)
{
const char *const PATH_NAME = user_data;
gs_free_error GError *error = NULL;
+ gs_unref_object NMConnection *connection = NULL;
- _connection_from_file_fail (PATH_NAME, NULL, TYPE_ETHERNET, &error);
+ if (WITH_JSON_VALIDATION) {
+ _connection_from_file_fail (PATH_NAME, NULL, TYPE_ETHERNET, &error);
- g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
- g_assert (strstr (error->message, "JSON"));
+ g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
+ g_assert (strstr (error->message, _("invalid json")));
+ } else
+ connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
}
static void