about summary refs log tree commit diff
path: root/libnm-core/nm-setting-team-port.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-core/nm-setting-team-port.c')
-rw-r--r--libnm-core/nm-setting-team-port.c414
1 files changed, 181 insertions, 233 deletions
diff --git a/libnm-core/nm-setting-team-port.c b/libnm-core/nm-setting-team-port.c
index b2c57ffa..6c087aa9 100644
--- a/libnm-core/nm-setting-team-port.c
+++ b/libnm-core/nm-setting-team-port.c
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,6 +29,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 +41,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 +53,25 @@ G_DEFINE_TYPE (NMSettingTeamPort, nm_setting_team_port, NM_TYPE_SETTING)
 
 /*****************************************************************************/
 
+NMTeamSetting *
+_nm_setting_team_port_get_team_setting (NMSettingTeamPort *setting)
+{
+	return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_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 +83,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 +99,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 +115,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 +131,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 +147,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 +163,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 +177,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 +194,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 +221,12 @@ gboolean
 nm_setting_team_port_add_link_watcher (NMSettingTeamPort *setting,
                                        NMTeamLinkWatcher *link_watcher)
 {
-	NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
-	guint i;
-
 	g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE);
 	g_return_val_if_fail (link_watcher != NULL, FALSE);
 
-	for (i = 0; i < priv->link_watchers->len; i++) {
-		if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher))
-			return FALSE;
-	}
-
-	g_ptr_array_add (priv->link_watchers, nm_team_link_watcher_dup (link_watcher));
-	_notify (setting, PROP_LINK_WATCHERS);
-	return TRUE;
+	return _maybe_changed (setting,
+	                       nm_team_setting_value_link_watchers_add (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
+	                                                                link_watcher));
 }
 
 /**
@@ -253,13 +241,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 +269,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,27 +288,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);
-	}
-}
-
-static GVariant *
-team_link_watchers_to_dbus (const GValue *prop_value)
-{
-	return _nm_utils_team_link_watchers_to_variant (g_value_get_boxed (prop_value));
-}
-
-static void
-team_link_watchers_from_dbus (GVariant   *dbus_value,
-                              GValue     *prop_value)
-{
-	g_value_take_boxed (prop_value, _nm_utils_team_link_watchers_from_variant (dbus_value));
+	_maybe_changed (setting,
+	                nm_team_setting_value_link_watchers_set_list (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
+	                                                              NULL,
+	                                                              0));
 }
 
 static gboolean
@@ -360,29 +330,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;
 }
@@ -390,8 +339,10 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 static NMTernary
 compare_property (const NMSettInfoSetting *sett_info,
                   guint property_idx,
-                  NMSetting *setting,
-                  NMSetting *other,
+                  NMConnection *con_a,
+                  NMSetting *set_a,
+                  NMConnection *con_b,
+                  NMSetting *set_b,
                   NMSettingCompareFlags flags)
 {
 	NMSettingTeamPortPrivate *a_priv;
@@ -401,31 +352,30 @@ compare_property (const NMSettInfoSetting *sett_info,
 
 		if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
 			return NM_TERNARY_DEFAULT;
-		if (!other)
+		if (!set_b)
 			return TRUE;
-		a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
-		b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
-		return _nm_team_link_watchers_equal (a_priv->link_watchers,
-		                                     b_priv->link_watchers,
-		                                     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->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 (other) {
-			a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
-			b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
-
+		if (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;
@@ -433,11 +383,44 @@ compare_property (const NMSettInfoSetting *sett_info,
 
 	return NM_SETTING_CLASS (nm_setting_team_port_parent_class)->compare_property (sett_info,
 	                                                                               property_idx,
-	                                                                               setting,
-	                                                                               other,
+	                                                                               con_a,
+	                                                                               set_a,
+	                                                                               con_b,
+	                                                                               set_b,
 	                                                                               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
@@ -448,27 +431,26 @@ get_property (GObject *object, guint prop_id,
 	NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
 
 	switch (prop_id) {
-	case PROP_CONFIG:
-		g_value_set_string (value, nm_setting_team_port_get_config (setting));
+	case NM_TEAM_ATTRIBUTE_CONFIG:
+		g_value_set_string (value,
+		                    nm_team_setting_config_get (priv->team_setting));
 		break;
-	case PROP_QUEUE_ID:
-		g_value_set_int (value, priv->queue_id);
+	case NM_TEAM_ATTRIBUTE_PORT_STICKY:
+		g_value_set_boolean (value,
+		                     nm_team_setting_value_get_bool (priv->team_setting,
+		                                                     prop_id));
 		break;
-	case PROP_PRIO:
-		g_value_set_int (value, priv->prio);
+	case NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID:
+	case NM_TEAM_ATTRIBUTE_PORT_PRIO:
+	case NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO:
+	case NM_TEAM_ATTRIBUTE_PORT_LACP_KEY:
+		g_value_set_int (value,
+		                 nm_team_setting_value_get_int32 (priv->team_setting,
+		                                                  prop_id));
 		break;
-	case PROP_STICKY:
-		g_value_set_boolean (value, priv->sticky);
-		break;
-	case PROP_LACP_PRIO:
-		g_value_set_int (value, priv->lacp_prio);
-		break;
-	case PROP_LACP_KEY:
-		g_value_set_int (value, priv->lacp_key);
-		break;
-	case PROP_LINK_WATCHERS:
-		g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers,
-		                                                 (NMUtilsCopyFunc) nm_team_link_watcher_dup,
+	case NM_TEAM_ATTRIBUTE_LINK_WATCHERS:
+		g_value_take_boxed (value, _nm_utils_copy_array (priv->team_setting->d.link_watchers,
+		                                                 (NMUtilsCopyFunc) _nm_team_link_watcher_ref,
 		                                                 (GDestroyNotify) nm_team_link_watcher_unref));
 		break;
 	default:
@@ -481,81 +463,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_dup,
-		                                            (GDestroyNotify) nm_team_link_watcher_unref);
-		if (priv->link_watchers->len)
-			align_value = value;
-		align_config = TRUE;
+	case NM_TEAM_ATTRIBUTE_LINK_WATCHERS:
+		v_ptrarr = g_value_get_boxed (value);
+		changed = nm_team_setting_value_link_watchers_set_list (priv->team_setting,
+		                                                        v_ptrarr ? (const NMTeamLinkWatcher *const*) v_ptrarr->pdata : NULL,
+		                                                        v_ptrarr ? v_ptrarr->len                                     : 0u);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
+		return;
 	}
-	if (align_config)
-		_nm_utils_json_append_gvalue (&priv->config, _prop_to_keys[prop_id], align_value);
+
+	_maybe_changed (setting, changed & ~(((guint32) 1) << prop_id));
 }
 
 /*****************************************************************************/
@@ -565,9 +506,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);
 }
 
 /**
@@ -588,8 +527,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);
 }
@@ -607,8 +545,17 @@ 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;
+
+#define _property_override(_properties_override, _param_spec, _variant_type, _is_link_watcher) \
+	_properties_override_add ((_properties_override), \
+	                          .param_spec          = (_param_spec), \
+	                          .dbus_type           = G_VARIANT_TYPE (""_variant_type""), \
+	                          .to_dbus_fcn         = _nm_team_settings_property_to_dbus, \
+	                          .gprop_from_dbus_fcn = ((_is_link_watcher) ? _nm_team_settings_property_from_dbus_link_watchers : NULL))
 
 	/**
 	 * NMSettingTeamPort:config:
@@ -624,12 +571,13 @@ 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 |
 	                         NM_SETTING_PARAM_INFERRABLE |
 	                         G_PARAM_STATIC_STRINGS);
+	_property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_CONFIG], "s", FALSE);
 
 	/**
 	 * NMSettingTeamPort:queue-id:
@@ -639,11 +587,12 @@ 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_MININT32, G_MAXINT32, -1,
 	                      G_PARAM_READWRITE |
 	                      G_PARAM_STATIC_STRINGS);
+	_property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID], "i", FALSE);
 
 	/**
 	 * NMSettingTeamPort:prio:
@@ -652,11 +601,12 @@ 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 |
 	                      G_PARAM_STATIC_STRINGS);
+	_property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_PORT_PRIO], "i", FALSE);
 
 	/**
 	 * NMSettingTeamPort:sticky:
@@ -665,11 +615,12 @@ 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 |
 	                          G_PARAM_STATIC_STRINGS);
+	_property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_PORT_STICKY], "b", FALSE);
 
 	/**
 	 * NMSettingTeamPort:lacp-prio:
@@ -678,11 +629,12 @@ 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_MININT32, G_MAXINT32, -1,
 	                      G_PARAM_READWRITE |
 	                      G_PARAM_STATIC_STRINGS);
+	_property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO], "i", FALSE);
 
 	/**
 	 * NMSettingTeamPort:lacp-key:
@@ -691,11 +643,12 @@ 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_MININT32, G_MAXINT32, -1,
 	                      G_PARAM_READWRITE |
 	                      G_PARAM_STATIC_STRINGS);
+	_property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_KEY], "i", FALSE);
 
 	/**
 	 * NMSettingTeamPort:link-watchers: (type GPtrArray(NMTeamLinkWatcher))
@@ -711,19 +664,14 @@ 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);
+	_property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS], "aa{sv}", TRUE);
 
-	_properties_override_add_transform (properties_override,
-	                                    obj_properties[PROP_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);