From 56f45d7ba373ee29e51efe24f5a541046358d531 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 29 May 2019 15:48:22 +0200 Subject: [PATCH 1/5] libnm/team: add space in JSON output for link watcher Generate the following: { "runner": { "sys_prio": 10 }, "link_watch": { "name": "ethtool" } } instead of: { "runner": { "sys_prio": 10 }, "link_watch": { "name": "ethtool"} } --- libnm-core/nm-team-utils.c | 2 +- libnm-core/tests/test-setting.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c index 814fd5369a..45738e5d14 100644 --- a/libnm-core/nm-team-utils.c +++ b/libnm-core/nm-team-utils.c @@ -1030,7 +1030,7 @@ _link_watcher_to_json (const NMTeamLinkWatcher *link_watcher, nm_value_type_to_json (attr_data->value_type, gstr, &p_val->val); } - g_string_append (gstr, "}"); + g_string_append (gstr, " }"); } #if WITH_JSON_VALIDATION diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index a3be0bc8fa..1d4b1b1d61 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -1469,7 +1469,7 @@ 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)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"ethtool\"} }"); + 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); @@ -1479,11 +1479,11 @@ test_team_setting (void) nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher1); _check_team_setting (setting); - g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4} }"); + g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4 } }"); nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher2); _check_team_setting (setting); - g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": [ { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4}, { \"name\": \"arp_ping\", \"target_host\": \"ccc\", \"source_host\": \"ddd\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4} ] }"); + 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); From efe602af2a5df9d0cb157be3ef91ae4c9ecc5f44 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 30 May 2019 10:16:07 +0200 Subject: [PATCH 2/5] libnm/team: reorder fields in JSON output for team link watcher The order of the fields in the JSON object does not really matter. Note that with the recent rework the order changed. Before it was arbitrarily, now it still is arbitrary. Reorder again, to follow the same order as `man teamd.conf`. --- libnm-core/nm-team-utils.c | 24 ++++++++++++------------ libnm-core/tests/test-setting.c | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c index 45738e5d14..f30cd108f4 100644 --- a/libnm-core/nm-team-utils.c +++ b/libnm-core/nm-team-utils.c @@ -107,16 +107,16 @@ static const TeamAttrData team_attr_datas[] = { 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_INIT_WAIT, LINK_WATCHER_ATTRIBUTE_MISSED_MAX, - LINK_WATCHER_ATTRIBUTE_VLANID, + LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, + LINK_WATCHER_ATTRIBUTE_TARGET_HOST, LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, + LINK_WATCHER_ATTRIBUTE_VLANID, LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS, } LinkWatcherAttribute; @@ -124,19 +124,19 @@ typedef enum { LINK_WATCHER_ATTRIBUTE_DELAY_UP, \ LINK_WATCHER_ATTRIBUTE_DELAY_DOWN #define _EXPECTED_LINK_WATCHER_ATTRIBUTES_NSNA_PING LINK_WATCHER_ATTRIBUTE_NAME, \ - LINK_WATCHER_ATTRIBUTE_INIT_WAIT, \ LINK_WATCHER_ATTRIBUTE_INTERVAL, \ + LINK_WATCHER_ATTRIBUTE_INIT_WAIT, \ LINK_WATCHER_ATTRIBUTE_MISSED_MAX, \ LINK_WATCHER_ATTRIBUTE_TARGET_HOST #define _EXPECTED_LINK_WATCHER_ATTRIBUTES_ARP_PING LINK_WATCHER_ATTRIBUTE_NAME, \ - LINK_WATCHER_ATTRIBUTE_INIT_WAIT, \ LINK_WATCHER_ATTRIBUTE_INTERVAL, \ + LINK_WATCHER_ATTRIBUTE_INIT_WAIT, \ LINK_WATCHER_ATTRIBUTE_MISSED_MAX, \ - LINK_WATCHER_ATTRIBUTE_VLANID, \ - LINK_WATCHER_ATTRIBUTE_TARGET_HOST, \ LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, \ + LINK_WATCHER_ATTRIBUTE_TARGET_HOST, \ LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, \ LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, \ + LINK_WATCHER_ATTRIBUTE_VLANID, \ LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS typedef struct { @@ -157,16 +157,16 @@ static const LinkWatcherAttrData link_watcher_attr_datas[] = { __VA_ARGS__ \ } _INIT (LINK_WATCHER_ATTRIBUTE_NAME, "name", "name", NM_VALUE_TYPE_STRING, ), - _INIT (LINK_WATCHER_ATTRIBUTE_TARGET_HOST, "target_host", "target-host", NM_VALUE_TYPE_STRING, ), - _INIT (LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, "source_host", "source-host", NM_VALUE_TYPE_STRING, ), _INIT (LINK_WATCHER_ATTRIBUTE_DELAY_UP, "delay_up", "delay-up", NM_VALUE_TYPE_INT, ), _INIT (LINK_WATCHER_ATTRIBUTE_DELAY_DOWN, "delay_down", "delay-down", NM_VALUE_TYPE_INT, ), - _INIT (LINK_WATCHER_ATTRIBUTE_INIT_WAIT, "init_wait", "init-wait", NM_VALUE_TYPE_INT, ), _INIT (LINK_WATCHER_ATTRIBUTE_INTERVAL, "interval", "interval", NM_VALUE_TYPE_INT, ), + _INIT (LINK_WATCHER_ATTRIBUTE_INIT_WAIT, "init_wait", "init-wait", NM_VALUE_TYPE_INT, ), _INIT (LINK_WATCHER_ATTRIBUTE_MISSED_MAX, "missed_max", "missed-max", NM_VALUE_TYPE_INT, .default_val.v_int = 3, ), - _INIT (LINK_WATCHER_ATTRIBUTE_VLANID, "vlanid", "vlanid", NM_VALUE_TYPE_INT, .default_val.v_int = -1, ), + _INIT (LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, "source_host", "source-host", NM_VALUE_TYPE_STRING, ), + _INIT (LINK_WATCHER_ATTRIBUTE_TARGET_HOST, "target_host", "target-host", NM_VALUE_TYPE_STRING, ), _INIT (LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, "validate_active", "validate-active", NM_VALUE_TYPE_BOOL, ), _INIT (LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, "validate_inactive", "validate-inactive", NM_VALUE_TYPE_BOOL, ), + _INIT (LINK_WATCHER_ATTRIBUTE_VLANID, "vlanid", "vlanid", NM_VALUE_TYPE_INT, .default_val.v_int = -1, ), _INIT (LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS, "send_always", "send-always", NM_VALUE_TYPE_BOOL, ), #undef _INIT }; diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 1d4b1b1d61..8741d97737 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -1479,11 +1479,11 @@ test_team_setting (void) nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher1); _check_team_setting (setting); - g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4 } }"); + g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"nsna_ping\", \"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, \"target_host\": \"bbb\" } }"); nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher2); _check_team_setting (setting); - g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": [ { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4 }, { \"name\": \"arp_ping\", \"target_host\": \"ccc\", \"source_host\": \"ddd\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4 } ] }"); + g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": [ { \"name\": \"nsna_ping\", \"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, \"target_host\": \"bbb\" }, { \"name\": \"arp_ping\", \"interval\": 3, \"init_wait\": 1, \"missed_max\": 4, \"source_host\": \"ddd\", \"target_host\": \"ccc\" } ] }"); nm_setting_team_remove_link_watcher (NM_SETTING_TEAM (setting), 0); nm_setting_team_remove_link_watcher (NM_SETTING_TEAM (setting), 0); From 23b1f8234ded35b2debfc16e60f6fbebaf2b61e2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 31 May 2019 10:48:47 +0200 Subject: [PATCH 3/5] libnm/team: fix handling default values and stricter validate team config For each artifical team property we need to track whether it was explicitly set (i.e., present in JSON/GVariant or set by the user via NMSettingTeam/NMSettingTeamPort API). -- As a plus, libnm is now no longer concerned with the underling default values that teamd uses. For example, the effective default value for "notify_peers.count" depends on the selected runner. But libnm does not need to care, it only cares wheher the property is set in JSON or not. This also means that the default (e.g. as interesting to `nmcli -o con show $PROFILE`) is independent from other properties (like the runner). Also change the default value for the GObject properties of NMSettingTeam and NMSettingTeamPort to indicate the "unset" value. For most properties, the default value is a special value that is not a valid configuration itself. For some properties the default value is itself a valid value, namely, "runner.active", "runner.fast_rate", "port.sticky" and "port.prio". As far as NMTeamSetting is concerned, it distinguishes between unset value and set value (including the default value). That means, when it parses a JSON or GVariant, it will remember whether the property was present or not. When using API of NMSettingTeam/NMSettingTeamPort to set a property to the default value, it marks the property as unset. For example, setting NM_SETTING_TEAM_RUNNER_ACTIVE to TRUE (the default), means that the value will not be serialized to JSON/GVariant. For the above 4 properties (where the default value is itself a valid value) this is a limitation of libnm API, as it does not allow to explicitly set '"runner": { "active": true }'. See SET_FIELD_MODE_SET_UNLESS_DEFAULT, Note that changing the default value for properties of NMSetting is problematic, because it changes behavior for how settings are parsed from keyfile/GVariant. For team settings that's not the case, because if a JSON "config" is present, all other properties are ignore. Also, we serialize properties to JSON/GVariant depending on whether it's marked as present, and not whether the value is set to the default (_nm_team_settings_property_to_dbus()). -- While at it, sticter validate the settings. Note that if a setting is initialized from JSON, the strict validation is not not performed. That means, such a setting will always validate, regardless whether the values in JSON are invalid according to libnm. Only when using the extended properties, strict validation is turned on. Note that libnm serializes the properties to GVariant both as JSON "config" and extended properties. Since when parsing a setting from GVariant will prefer the "config" (if present), in most cases also validation is performed. Likewise, settings plugins (keyfile, ifcfg-rh) only persist the JSON config to disk. When loading a setting from file, strict validation is also not performed. The stricter validation only happens if as last operation one of the artificial properties was set, or if the setting was created from a GVariant that has no "config" field. -- This is a (another) change in behavior. --- clients/common/nm-meta-setting-desc.c | 46 +- libnm-core/nm-setting-team-port.c | 46 +- libnm-core/nm-setting-team.c | 65 +- libnm-core/nm-team-utils.c | 1057 +++++++++++++++---------- libnm-core/nm-team-utils.h | 28 +- libnm-core/tests/test-general.c | 10 +- libnm-core/tests/test-setting.c | 116 ++- 7 files changed, 817 insertions(+), 551 deletions(-) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index c252832d35..a99bb014ee 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -6513,6 +6513,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = 0, .nick = "disabled", @@ -6524,6 +6528,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = 0, .nick = "default", @@ -6535,6 +6543,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = 0, .nick = "disabled", @@ -6546,6 +6558,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = 0, .nick = "default", @@ -6597,6 +6613,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, .nick = "default", @@ -6614,6 +6634,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT, .nick = "default", @@ -6625,6 +6649,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = 0, .nick = "default", @@ -6676,7 +6704,11 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = { .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( { - .value.i64 = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT, + .value.i64 = -1, + .nick = "unset", + }, + { + .value.i64 = 0, .nick = "default", }, ), @@ -6686,6 +6718,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = 0, + .nick = "unset", + }, { .value.i64 = 0, .nick = "default", @@ -6700,6 +6736,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT, .nick = "default", @@ -6711,6 +6751,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = { .property_type = &_pt_gobject_int, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "unset", + }, { .value.i64 = 0, .nick = "default", diff --git a/libnm-core/nm-setting-team-port.c b/libnm-core/nm-setting-team-port.c index 22cbdb6703..504798c163 100644 --- a/libnm-core/nm-setting-team-port.c +++ b/libnm-core/nm-setting-team-port.c @@ -54,6 +54,14 @@ 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)) @@ -289,19 +297,6 @@ nm_setting_team_port_clear_link_watchers (NMSettingTeamPort *setting) 0)); } -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, FALSE, NULL)); -} - static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { @@ -556,6 +551,13 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass) 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: * @@ -587,9 +589,10 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass) **/ 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: @@ -603,6 +606,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass) 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: @@ -616,6 +620,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass) FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_PORT_STICKY], "b", FALSE); /** * NMSettingTeamPort:lacp-prio: @@ -626,9 +631,10 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass) **/ 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: @@ -639,9 +645,10 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass) **/ 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)) @@ -662,12 +669,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass) G_TYPE_PTR_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - _properties_override_add_transform (properties_override, - obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS], - G_VARIANT_TYPE ("aa{sv}"), - team_link_watchers_to_dbus, - team_link_watchers_from_dbus); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS], "aa{sv}", TRUE); g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_properties), obj_properties); diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index a478b802b1..a9095836d3 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -734,6 +734,14 @@ G_DEFINE_TYPE (NMSettingTeam, nm_setting_team, NM_TYPE_SETTING) /*****************************************************************************/ +NMTeamSetting * +_nm_setting_team_get_team_setting (NMSettingTeam *setting) +{ + return NM_SETTING_TEAM_GET_PRIVATE (setting)->team_setting; +} + +/*****************************************************************************/ + #define _maybe_changed(self, changed) \ nm_team_setting_maybe_changed (NM_SETTING (_NM_ENSURE_TYPE (NMSettingTeam *, self)), (const GParamSpec *const*) obj_properties, (changed)) @@ -1223,19 +1231,6 @@ nm_setting_team_clear_link_watchers (NMSettingTeam *setting) 0)); } -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, FALSE, NULL)); -} - static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { @@ -1503,6 +1498,13 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) 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)) + /** * NMSettingTeam:config: * @@ -1533,9 +1535,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) **/ 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_MININT32, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT], "i", FALSE); /** * NMSettingTeam:notify-peers-interval: @@ -1546,9 +1549,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) **/ 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_MININT32, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL], "i", FALSE); /** * NMSettingTeam:mcast-rejoin-count: @@ -1559,9 +1563,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) **/ 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_MININT32, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT], "i", FALSE); /** * NMSettingTeam:mcast-rejoin-interval: @@ -1572,9 +1577,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) **/ 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_MININT32, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL], "i", FALSE); /** * NMSettingTeam:runner: @@ -1590,6 +1596,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER], "s", FALSE); /** * NMSettingTeam:runner-hwaddr-policy: @@ -1603,6 +1610,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY], "s", FALSE); /** * NMSettingTeam:runner-tx-hash: @@ -1617,6 +1625,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH], "as", FALSE); /** * NMSettingTeam:runner-tx-balancer: @@ -1630,6 +1639,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER], "s", FALSE); /** * NMSettingTeam:runner-tx-balancer-interval: @@ -1640,9 +1650,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) **/ 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_MININT32, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL], "i", FALSE); /** * NMSettingTeam:runner-active: @@ -1653,9 +1664,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) **/ obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE] = g_param_spec_boolean (NM_SETTING_TEAM_RUNNER_ACTIVE, "", "", - FALSE, + TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE], "b", FALSE); /** * NMSettingTeam:runner-fast-rate: @@ -1669,6 +1681,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE], "b", FALSE); /** * NMSettingTeam:runner-sys-prio: @@ -1679,9 +1692,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) **/ 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_MININT32, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO], "i", FALSE); /** * NMSettingTeam:runner-min-ports: @@ -1692,9 +1706,10 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) **/ 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_MININT32, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS], "i", FALSE); /** * NMSettingTeam:runner-agg-select-policy: @@ -1708,6 +1723,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY], "s", FALSE); /** * NMSettingTeam:link-watchers: (type GPtrArray(NMTeamLinkWatcher)) @@ -1728,12 +1744,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) G_TYPE_PTR_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - _properties_override_add_transform (properties_override, - obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS], - G_VARIANT_TYPE ("aa{sv}"), - team_link_watchers_to_dbus, - team_link_watchers_from_dbus); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS], "aa{sv}", TRUE); /* ---dbus--- * property: interface-name diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c index f30cd108f4..701424a725 100644 --- a/libnm-core/nm-team-utils.c +++ b/libnm-core/nm-team-utils.c @@ -33,21 +33,115 @@ /*****************************************************************************/ +typedef enum { + SET_FIELD_MODE_UNSET = 0, + SET_FIELD_MODE_SET = 1, + + /* Sets the field as set, unless the field is at the default. + * This is the case for API that is called from NMSettingTeam/NMSettingTeamPort. + * This means, using libnm API to reset the value of a NMSetting to the default, + * will mark the field as unset. + * This is different from initializing the field when parsing JSON/GVariant. In + * that case an explicitly set field (even set to the default value) will be remembered + * to be set. */ + SET_FIELD_MODE_SET_UNLESS_DEFAULT = 2, +} SetFieldModeEnum; + +typedef enum { + RESET_JSON_NO = FALSE, + RESET_JSON_YES = TRUE, +} ResetJsonEnum; + /* 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); +static const char *const _valid_names_runner[] = { + NM_SETTING_TEAM_RUNNER_BROADCAST, + NM_SETTING_TEAM_RUNNER_ROUNDROBIN, + NM_SETTING_TEAM_RUNNER_RANDOM, + NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP, + NM_SETTING_TEAM_RUNNER_LOADBALANCE, + NM_SETTING_TEAM_RUNNER_LACP, + NULL, +}; + +static const char *const _valid_names_runner_hwaddr_policy[] = { + NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_SAME_ALL, + NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_BY_ACTIVE, + NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_ONLY_ACTIVE, + NULL, +}; + +static const char *const _valid_names_runner_tx_balancer[] = { + "basic", + NULL, +}; + +static const char *const _valid_names_runner_tx_hash[] = { + "eth", + "vlan", + "ipv4", + "ipv6", + "ip", + "l3", + "l4", + "tcp", + "udp", + "sctp", + NULL, +}; + +static const char *const _valid_names_runner_agg_select_policy[] = { + "lacp_prio", + "lacp_prio_stable", + "bandwidth", + "count", + "port_config", + NULL, +}; + +typedef struct { + NMTeamAttribute team_attr; + const char *const*valid_runners; +} RunnerCompatElem; + +static const RunnerCompatElem _runner_compat_lst[] = { + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP), }, + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_LOADBALANCE, + NM_SETTING_TEAM_RUNNER_LACP), }, + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_LOADBALANCE, + NM_SETTING_TEAM_RUNNER_LACP), }, + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_LOADBALANCE, + NM_SETTING_TEAM_RUNNER_LACP), }, + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_LACP), }, + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_LACP), }, + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_LACP), }, + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_LACP), }, + { NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY, NM_MAKE_STRV (NM_SETTING_TEAM_RUNNER_LACP), }, +}; + typedef struct { const char *const*js_keys; - const char *dbus_name; + const char *property_name; NMValueTypUnion default_val; + union { + struct { + gint32 min; + gint32 max; + } r_int32; + struct { + const char *const*valid_names; + } r_string; + } range; NMTeamAttribute team_attr; NMValueType value_type; guint8 field_offset; guint8 js_keys_len; bool for_master:1; bool for_port:1; + bool has_range:1; } TeamAttrData; #define TEAM_ATTR_IDX(_is_port, _team_attr) \ @@ -63,44 +157,65 @@ static const TeamAttrData team_attr_datas[] = { .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, ...) \ +#define _VAL_BOOL(_default) \ + .default_val.v_bool = (_default) + +#define _VAL_INT32(_default) \ + .default_val.v_int32 = (_default) + +#define _VAL_INT32_RANGE(_default, _min,_max) \ + _VAL_INT32 (_default), \ + .has_range = TRUE, \ + .range.r_int32 = { .min = _min, .max = _max, } + +#define _VAL_STRING() \ + .default_val.v_string = NULL + +#define _VAL_STRING_RANGE(_valid_names) \ + _VAL_STRING (), \ + .has_range = TRUE, \ + .range.r_string = { .valid_names = (_valid_names), } + +#define _VAL_UNSPEC() \ + .default_val.v_string = (NULL) + +#define _INIT(_is_port, _team_attr, field, _value_type, _property_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"", \ + .property_name = ""_property_name"", \ __VA_ARGS__ \ } - _INIT (0, NM_TEAM_ATTRIBUTE_CONFIG, _js_str, NM_VALUE_TYPE_UNSPEC, NM_SETTING_TEAM_CONFIG, ), + _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_LINK_WATCHERS, link_watchers, NM_VALUE_TYPE_UNSPEC, NM_SETTING_TEAM_LINK_WATCHERS, _JS_KEYS ("link_watch"), _VAL_UNSPEC (), ), - _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 (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"), _VAL_INT32_RANGE (-1, 0, G_MAXINT32), ), + _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"), _VAL_INT32_RANGE (-1, 0, G_MAXINT32), ), + _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"), _VAL_INT32_RANGE (-1, 0, G_MAXINT32), ), + _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"), _VAL_INT32_RANGE (-1, 0, G_MAXINT32), ), + _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER, master.runner, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER, _JS_KEYS ("runner", "name"), _VAL_STRING_RANGE (_valid_names_runner), ), + _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"), _VAL_STRING_RANGE (_valid_names_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"), _VAL_UNSPEC (), ), + _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"), _VAL_STRING_RANGE (_valid_names_runner_tx_balancer), ), + _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"), _VAL_INT32_RANGE (-1, 0, G_MAXINT32), ), + _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE, master.runner_active, NM_VALUE_TYPE_BOOL, NM_SETTING_TEAM_RUNNER_ACTIVE, _JS_KEYS ("runner", "active"), _VAL_BOOL (TRUE), ), + _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"), _VAL_BOOL (FALSE), ), + _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"), _VAL_INT32_RANGE (-1, 0, USHRT_MAX + 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"), _VAL_INT32_RANGE (-1, 1, UCHAR_MAX + 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"), _VAL_STRING_RANGE (_valid_names_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"), ), + _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"), _VAL_INT32_RANGE (-1, 0, G_MAXINT32), ), + _INIT (1, NM_TEAM_ATTRIBUTE_PORT_PRIO, port.prio, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_PRIO, _JS_KEYS ("prio"), _VAL_INT32 (0), ), + _INIT (1, NM_TEAM_ATTRIBUTE_PORT_STICKY, port.sticky, NM_VALUE_TYPE_BOOL, NM_SETTING_TEAM_PORT_STICKY, _JS_KEYS ("sticky"), _VAL_BOOL (FALSE), ), + _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"), _VAL_INT32_RANGE (-1, 0, USHRT_MAX + 1), ), + _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"), _VAL_INT32_RANGE (-1, 0, USHRT_MAX + 1), ), #undef _INIT - }; /*****************************************************************************/ @@ -177,8 +292,8 @@ 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 gboolean _team_setting_verify_properties (const NMTeamSetting *self, + GError **error); static void _link_watcher_to_json (const NMTeamLinkWatcher *link_watcher, GString *gstr); @@ -197,7 +312,7 @@ _team_attr_data_ASSERT (const TeamAttrData *attr_data) 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); + nm_assert (attr_data->property_name); { static int checked = 0; @@ -235,124 +350,19 @@ _team_attr_data_get (gboolean is_port, } static const TeamAttrData * -_team_attr_data_find_for_dbus_name (gboolean is_port, - const char *dbus_name) +_team_attr_data_find_for_property_name (gboolean is_port, + const char *property_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)) + && nm_streq (property_name, attr_data->property_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, @@ -455,44 +465,6 @@ _team_attr_data_copy (const TeamAttrData *attr_data, 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, @@ -574,6 +546,64 @@ _team_setting_ASSERT (const NMTeamSetting *self) #endif } +static gboolean +_team_setting_has_field (const NMTeamSetting *self, + const TeamAttrData *attr_data) +{ + _team_setting_ASSERT (self); + return NM_FLAGS_ALL (self->d.has_fields_mask, nm_team_attribute_to_flags (attr_data->team_attr)); +} + +static gboolean +_team_setting_has_fields_any_v (const NMTeamSetting *self, + const NMTeamAttribute *team_attrs, + gsize n_team_attrs) +{ + gsize i; + + for (i = 0; i < n_team_attrs; i++) { + const TeamAttrData *attr_data = _team_attr_data_get (self->d.is_port, team_attrs[i]); + + if (_team_setting_has_field (self, attr_data)) + return TRUE; + } + return FALSE; +} + +#define _team_setting_has_fields_any(self, ...) \ + _team_setting_has_fields_any_v ((self), ((const NMTeamAttribute []) { __VA_ARGS__ }), NM_NARG (__VA_ARGS__)) + +static void +_team_setting_has_field_set (NMTeamSetting *self, + const TeamAttrData *attr_data, + SetFieldModeEnum set_field_mode) +{ + guint32 mask = nm_team_attribute_to_flags (attr_data->team_attr); + + _team_setting_ASSERT (self); + + switch (set_field_mode) { + case SET_FIELD_MODE_UNSET: + goto do_unset; + case SET_FIELD_MODE_SET: + goto do_set; + case SET_FIELD_MODE_SET_UNLESS_DEFAULT: + if (_team_attr_data_equal (attr_data, + self->d.is_port, + _team_setting_get_field (self, attr_data), + &attr_data->default_val)) + goto do_unset; + goto do_set; + } + nm_assert_not_reached (); + +do_unset: + self->_data_priv.has_fields_mask &= ~mask; + return; +do_set: + self->_data_priv.has_fields_mask |= mask; +} + static gpointer _team_setting_get_field (const NMTeamSetting *self, const TeamAttrData *attr_data) @@ -593,12 +623,20 @@ _team_setting_get_field (const NMTeamSetting *self, static guint32 _team_setting_attribute_changed (NMTeamSetting *self, - NMTeamAttribute team_attr, - gboolean changed) + const TeamAttrData *attr_data, + gboolean changed, + SetFieldModeEnum set_field_mode, + ResetJsonEnum reset_json) { guint32 changed_flags; - nm_assert (_team_attr_data_get (self->d.is_port, team_attr)); + _team_setting_has_field_set (self, attr_data, set_field_mode); + + if (!reset_json) { + return changed + ? nm_team_attribute_to_flags (attr_data->team_attr) + : 0u; + } if (!changed) { /* a regular attribute was set, but the value did not change. @@ -614,7 +652,7 @@ _team_setting_attribute_changed (NMTeamSetting *self, return 0; changed_flags = nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG); } else { - changed_flags = nm_team_attribute_to_flags (team_attr) + changed_flags = nm_team_attribute_to_flags (attr_data->team_attr) | nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG); } @@ -625,13 +663,28 @@ _team_setting_attribute_changed (NMTeamSetting *self, return changed_flags; } -static void +static guint32 +_team_setting_attribute_changed_attr (NMTeamSetting *self, + NMTeamAttribute team_attr, + gboolean changed, + SetFieldModeEnum set_field_mode, + ResetJsonEnum reset_json) +{ + return _team_setting_attribute_changed (self, + _team_attr_data_get (self->d.is_port, team_attr), + changed, + set_field_mode, + reset_json); +} + +static gboolean _team_setting_field_to_json (const NMTeamSetting *self, GString *gstr, gboolean prepend_delimiter, - NMTeamAttribute team_attr) + const TeamAttrData *attr_data) { - const TeamAttrData *attr_data = _team_attr_data_get (self->d.is_port, team_attr); + if (!_team_setting_has_field (self, attr_data)) + return FALSE; if (prepend_delimiter) nm_json_aux_gstr_append_delimiter (gstr); @@ -639,13 +692,13 @@ _team_setting_field_to_json (const NMTeamSetting *self, self->d.is_port, gstr, _team_setting_get_field (self, attr_data)); + return TRUE; } 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) { @@ -653,14 +706,13 @@ _team_setting_fields_to_json_maybe (const NMTeamSetting *self, 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; + if (_team_setting_field_to_json (self, + gstr, + prepend_delimiter, + _team_attr_data_get (self->d.is_port, team_attrs_lst[i]))) { + any_added = TRUE; + prepend_delimiter = TRUE; + } } return any_added; } @@ -673,39 +725,22 @@ _team_setting_set (NMTeamSetting *self, { 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; + gboolean has_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); - } + has_field = (has_lst && has_lst[attr_data->team_attr]); + + p_val = has_field + ? &val_lst[attr_data->team_attr] + : &attr_data->default_val; p_field = _team_setting_get_field (self, attr_data); @@ -721,6 +756,14 @@ _team_setting_set (NMTeamSetting *self, } changed_flags |= nm_team_attribute_to_flags (attr_data->team_attr); } + + if (modify) { + _team_setting_has_field_set (self, + attr_data, + has_field + ? SET_FIELD_MODE_SET + : SET_FIELD_MODE_UNSET); + } } return changed_flags; @@ -749,31 +792,54 @@ _nm_team_setting_value_get (const NMTeamSetting *self, nm_assert (value_type == attr_data->value_type); + nm_assert ( _team_setting_has_field (self, attr_data) + || _team_attr_data_equal (attr_data, + self->d.is_port, + _team_setting_get_field (self, attr_data), + &attr_data->default_val)); 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, + gconstpointer val, + SetFieldModeEnum set_field_mode, + ResetJsonEnum reset_json) +{ + gpointer p_field; + gboolean changed; + + nm_assert (self); + _team_attr_data_ASSERT (attr_data); + nm_assert (val); + + p_field = _team_setting_get_field (self, attr_data); + + changed = !_team_attr_data_equal (attr_data, self->d.is_port, p_field, val); + if (changed) + nm_value_type_copy (attr_data->value_type, p_field, val); + return _team_setting_attribute_changed (self, attr_data, changed, set_field_mode, reset_json); +} + +guint32 +nm_team_setting_value_reset (NMTeamSetting *self, + NMTeamAttribute team_attr, + gboolean to_default /* or else unset */) { 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); + return _team_setting_value_set (self, + attr_data, + &attr_data->default_val, + to_default + ? SET_FIELD_MODE_SET + : SET_FIELD_MODE_UNSET, + RESET_JSON_YES); } guint32 @@ -782,12 +848,19 @@ _nm_team_setting_value_set (NMTeamSetting *self, NMValueType value_type, gconstpointer val) { - return _team_setting_attribute_changed (self, - team_attr, - (_team_setting_value_set (self, - team_attr, - value_type, - val) != 0u)); + const TeamAttrData *attr_data; + + nm_assert (self); + + attr_data = _team_attr_data_get (self->d.is_port, team_attr); + + nm_assert (value_type == attr_data->value_type); + + return _team_setting_value_set (self, + attr_data, + val, + SET_FIELD_MODE_SET_UNLESS_DEFAULT, + RESET_JSON_YES); } guint32 @@ -795,14 +868,19 @@ nm_team_setting_value_link_watchers_add (NMTeamSetting *self, const NMTeamLinkWatcher *link_watcher) { guint i; + gboolean changed; 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); + if (nm_team_link_watcher_equal (self->d.link_watchers->pdata[i], link_watcher)) { + changed = FALSE; + goto out; + } } + changed = TRUE; 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); +out: + return _team_setting_attribute_changed_attr (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, changed, SET_FIELD_MODE_SET_UNLESS_DEFAULT, RESET_JSON_YES); } guint32 @@ -816,7 +894,7 @@ nm_team_setting_value_link_watchers_remove_by_value (NMTeamSetting *self, link_watcher)) return nm_team_setting_value_link_watchers_remove (self, i); } - return _team_setting_attribute_changed (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, FALSE); + return _team_setting_attribute_changed_attr (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, FALSE, SET_FIELD_MODE_SET_UNLESS_DEFAULT, RESET_JSON_YES); } guint32 @@ -824,21 +902,28 @@ 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); + return _team_setting_attribute_changed_attr (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, TRUE, SET_FIELD_MODE_SET_UNLESS_DEFAULT, RESET_JSON_YES); } static guint32 _team_setting_value_link_watchers_set_list (NMTeamSetting *self, const NMTeamLinkWatcher *const*arr, - guint len) + guint len, + SetFieldModeEnum set_field_mode, + ResetJsonEnum reset_json) { + gboolean changed; + 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; + FALSE) == 0) { + changed = FALSE; + goto out; + } + changed = TRUE; if (len == 0) g_ptr_array_set_size ((GPtrArray *) self->d.link_watchers, 0); else { @@ -857,7 +942,8 @@ _team_setting_value_link_watchers_set_list (NMTeamSetting *self, } } - return nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_LINK_WATCHERS); +out: + return _team_setting_attribute_changed_attr (self, NM_TEAM_ATTRIBUTE_LINK_WATCHERS, changed, set_field_mode, reset_json); } guint32 @@ -865,11 +951,11 @@ 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)); + return _team_setting_value_link_watchers_set_list (self, + arr, + len, + SET_FIELD_MODE_SET_UNLESS_DEFAULT, + RESET_JSON_YES); } /*****************************************************************************/ @@ -878,18 +964,23 @@ guint32 nm_team_setting_value_master_runner_tx_hash_add (NMTeamSetting *self, const char *txhash) { + gboolean changed; 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); + if (nm_streq (txhash, self->d.master.runner_tx_hash->pdata[i])) { + changed = FALSE; + goto out; + } } } + changed = TRUE; 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); +out: + return _team_setting_attribute_changed_attr (self, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, changed, SET_FIELD_MODE_SET_UNLESS_DEFAULT, RESET_JSON_YES); } guint32 @@ -897,22 +988,29 @@ 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); + return _team_setting_attribute_changed_attr (self, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, TRUE, SET_FIELD_MODE_SET_UNLESS_DEFAULT, RESET_JSON_YES); } static guint32 _team_setting_value_master_runner_tx_hash_set_list (NMTeamSetting *self, const char *const*arr, - guint len) + guint len, + SetFieldModeEnum set_field_mode, + ResetJsonEnum reset_json) { _nm_unused gs_unref_ptrarray GPtrArray *old_val_destroy = NULL; + gboolean changed; 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; + len) == 0) { + changed = FALSE; + goto out; + } + + changed = TRUE; old_val_destroy = (GPtrArray *) g_steal_pointer (&self->_data_priv.master.runner_tx_hash); @@ -924,7 +1022,8 @@ _team_setting_value_master_runner_tx_hash_set_list (NMTeamSetting *self, 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); +out: + return _team_setting_attribute_changed_attr (self, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, changed, set_field_mode, reset_json); } guint32 @@ -932,11 +1031,11 @@ 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)); + return _team_setting_value_master_runner_tx_hash_set_list (self, + arr, + len, + SET_FIELD_MODE_SET_UNLESS_DEFAULT, + RESET_JSON_YES); } /*****************************************************************************/ @@ -1361,7 +1460,7 @@ _link_watcher_from_variant (GVariant *watcher_var, * Returns: (transfer full): a new floating #GVariant representing link watchers. **/ GVariant * -_nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers) +_nm_utils_team_link_watchers_to_variant (const GPtrArray *link_watchers) { GVariantBuilder builder; guint i; @@ -1441,29 +1540,13 @@ nm_team_setting_config_get (const NMTeamSetting *self) * 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; + GString *gstr; 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, @@ -1473,57 +1556,57 @@ nm_team_setting_config_get (const NMTeamSetting *self) 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))) + if (_team_setting_fields_to_json_maybe (self, gstr, !list_is_empty, attr_lst_port, G_N_ELEMENTS (attr_lst_port))) list_is_empty = FALSE; } else { + 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, + }; + static const NMTeamAttribute attr_lst_notify_peers[] = { + NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT, + NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL, + }; + static const NMTeamAttribute attr_lst_mcast_rejoin[] = { + NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT, + NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL, + }; - 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, - }; + if ( _team_setting_has_fields_any_v (self, attr_lst_runner_pt1, G_N_ELEMENTS (attr_lst_runner_pt1)) + || _team_setting_has_fields_any_v (self, attr_lst_runner_pt2, G_N_ELEMENTS (attr_lst_runner_pt2)) + || _team_setting_has_fields_any_v (self, attr_lst_runner_pt3, G_N_ELEMENTS (attr_lst_runner_pt3))) { 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))) + if (_team_setting_fields_to_json_maybe (self, gstr, !list_is_empty2, 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 (_team_setting_has_fields_any_v (self, attr_lst_runner_pt2, G_N_ELEMENTS (attr_lst_runner_pt2))) { 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))) + if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, 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))) + if (_team_setting_fields_to_json_maybe (self, gstr, !list_is_empty2, attr_lst_runner_pt3, G_N_ELEMENTS (attr_lst_runner_pt3))) list_is_empty2 = FALSE; nm_assert (!list_is_empty2); @@ -1531,43 +1614,33 @@ nm_team_setting_config_get (const NMTeamSetting *self) 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 (_team_setting_has_fields_any_v (self, attr_lst_notify_peers, G_N_ELEMENTS (attr_lst_notify_peers))) { 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))) + if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, 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 (_team_setting_has_fields_any_v (self, attr_lst_mcast_rejoin, G_N_ELEMENTS (attr_lst_mcast_rejoin))) { 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))) + if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, attr_lst_mcast_rejoin, G_N_ELEMENTS (attr_lst_mcast_rejoin))) 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); + if (_team_setting_field_to_json (self, + gstr, + !list_is_empty, + _team_attr_data_get (self->d.is_port, NM_TEAM_ATTRIBUTE_LINK_WATCHERS))) list_is_empty = FALSE; - } + if (!list_is_empty) g_string_append (gstr, " }"); @@ -1846,7 +1919,7 @@ nm_team_setting_config_set (NMTeamSetting *self, const char *js_str) val_lst); if ( !unrecognized_content - && _team_setting_verify (self, NULL)) { + && _team_setting_verify_properties (self, NULL)) { /* if we could parse everything without unexpected/unknown data, * we switch into strictly validating mode. */ new_strict_validated = TRUE; @@ -1870,104 +1943,166 @@ nm_team_setting_config_set (NMTeamSetting *self, const char *js_str) /*****************************************************************************/ +static void +_team_setting_prefix_error_plain (gboolean is_port, + const char *property_name, + GError **error) +{ + g_prefix_error (error, + "%s.%s: ", + is_port + ? NM_SETTING_TEAM_PORT_SETTING_NAME + : NM_SETTING_TEAM_SETTING_NAME, + property_name); +} + static void _team_setting_prefix_error (const NMTeamSetting *self, - GError **error, const char *prop_name_master, - const char *prop_name_port) + const char *prop_name_port, + GError **error) { _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); + _team_setting_prefix_error_plain (self->d.is_port, + self->d.is_port + ? prop_name_port + : prop_name_master, + error); } static gboolean -_team_setting_verify (const NMTeamSetting *self, - GError **error) +_team_setting_verify_properties (const NMTeamSetting *self, + GError **error) { + const TeamAttrData *attr_data; 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; - } + 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 (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 (!_team_attr_data_is_relevant (attr_data, self->d.is_port)) + continue; + if (!_team_setting_has_field (self, attr_data)) + continue; - if (!val[0]) { + if (attr_data->has_range) { + gconstpointer p_field; + + p_field = _team_setting_get_field (self, attr_data); + if (attr_data->value_type == NM_VALUE_TYPE_INT32) { + gint32 v = *((const gint32 *) p_field); + + if ( v < attr_data->range.r_int32.min + || v > attr_data->range.r_int32.max) { 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); + _("value out or range")); + _team_setting_prefix_error_plain (self->d.is_port, attr_data->property_name, error); return FALSE; } + } else if (attr_data->value_type == NM_VALUE_TYPE_STRING) { + const char *v = *((const char *const*) p_field); + + if (nm_utils_strv_find_first ((char **) attr_data->range.r_string.valid_names, + -1, + v) < 0) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, + _("invalid value")); + _team_setting_prefix_error_plain (self->d.is_port, attr_data->property_name, error); + return FALSE; + } + } else + nm_assert_not_reached (); + } + + if ( !self->d.is_port + && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { + 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 + || (nm_utils_strv_find_first ((char **) _valid_names_runner_tx_hash, + -1, + val) < 0)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, + _("invalid runner-tx-hash")); + _team_setting_prefix_error_plain (self->d.is_port, NM_SETTING_TEAM_RUNNER_TX_HASH, error); + 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 (!self->d.is_port) { - 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 { + for (i = 0; i < G_N_ELEMENTS (_runner_compat_lst); i++) { + const RunnerCompatElem *e = &_runner_compat_lst[i]; + + nm_assert (NM_PTRARRAY_LEN (e->valid_runners) > 0); + + attr_data = _team_attr_data_get (FALSE, e->team_attr); + + if (!_team_setting_has_field (self, attr_data)) + continue; + if ( self->d.master.runner + && (nm_utils_strv_find_first ((char **) e->valid_runners, + -1, + self->d.master.runner) >= 0)) + continue; + if (e->valid_runners[1] == NULL) { 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; - } + _("%s is only allowed for runner %s"), + attr_data->property_name, + e->valid_runners[0]); + } else { + gs_free char *s = NULL; - 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); + s = g_strjoinv (",", (char **) e->valid_runners); + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, + _("%s is only allowed for runners %s"), + attr_data->property_name, + s); + } + _team_setting_prefix_error_plain (self->d.is_port, NM_SETTING_TEAM_RUNNER, error); 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); + } else { + gboolean has_lacp_attrs; + gboolean has_activebackup_attrs; + + has_lacp_attrs = _team_setting_has_fields_any (self, NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO, + NM_TEAM_ATTRIBUTE_PORT_LACP_KEY); + has_activebackup_attrs = _team_setting_has_fields_any (self, NM_TEAM_ATTRIBUTE_PORT_PRIO, + NM_TEAM_ATTRIBUTE_PORT_STICKY); + if (has_lacp_attrs && has_activebackup_attrs) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, + _("cannot set parameters for lacp and activebackup runners together")); + _team_setting_prefix_error (self, NM_SETTING_TEAM_LINK_WATCHERS, NM_SETTING_TEAM_PORT_LINK_WATCHERS, error); return FALSE; } } + for (i = 0; i < self->d.link_watchers->len; i++) { + if (!self->d.link_watchers->pdata[i]) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, + _("missing link watcher")); + _team_setting_prefix_error (self, NM_SETTING_TEAM_LINK_WATCHERS, NM_SETTING_TEAM_PORT_LINK_WATCHERS, error); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +_team_setting_verify_config (const NMTeamSetting *self, + GError **error) +{ + const char *js_str; + /* 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); @@ -1976,19 +2111,19 @@ _team_setting_verify (const NMTeamSetting *self, 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); + _team_setting_prefix_error (self, NM_SETTING_TEAM_CONFIG, NM_SETTING_TEAM_PORT_CONFIG, error); 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); + _team_setting_prefix_error (self, NM_SETTING_TEAM_CONFIG, NM_SETTING_TEAM_PORT_CONFIG, error); 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); + _team_setting_prefix_error (self, NM_SETTING_TEAM_CONFIG, NM_SETTING_TEAM_PORT_CONFIG, error); return FALSE; } } @@ -2000,7 +2135,11 @@ gboolean nm_team_setting_verify (const NMTeamSetting *self, GError **error) { - return _team_setting_verify (self, error); + if (self->d.strict_validated) { + if (!_team_setting_verify_properties (self, error)) + return FALSE; + } + return _team_setting_verify_config (self, error); } /*****************************************************************************/ @@ -2017,12 +2156,13 @@ nm_team_setting_cmp (const NMTeamSetting *self_a, 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 (!_team_attr_data_is_relevant (attr_data, self_a->d.is_port)) + continue; + + 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) { @@ -2038,7 +2178,7 @@ nm_team_setting_reset (NMTeamSetting *self, const NMTeamSetting *src) { const TeamAttrData *attr_data; - guint32 changed; + guint32 changed_flags; _team_setting_ASSERT (self); _team_setting_ASSERT (src); @@ -2047,7 +2187,7 @@ nm_team_setting_reset (NMTeamSetting *self, if (self == src) return 0; - changed = 0; + changed_flags = 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)) @@ -2061,21 +2201,23 @@ nm_team_setting_reset (NMTeamSetting *self, 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); + changed_flags |= nm_team_attribute_to_flags (attr_data->team_attr); } + self->_data_priv.has_fields_mask = src->d.has_fields_mask; + 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); + changed_flags |= nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG); + } else if (changed_flags != 0) + changed_flags |= 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; + return changed_flags; } static void @@ -2109,7 +2251,7 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, _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); + attr_data = _team_attr_data_find_for_property_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. */ @@ -2136,10 +2278,9 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, 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); + _team_setting_prefix_error_plain (self->d.is_port, + attr_data->property_name, + error); return FALSE; } continue; @@ -2162,9 +2303,9 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, _("invalid link-watchers: %s"), local->message); _team_setting_prefix_error (self, - error, NM_SETTING_TEAM_LINK_WATCHERS, - NM_SETTING_TEAM_PORT_LINK_WATCHERS); + NM_SETTING_TEAM_PORT_LINK_WATCHERS, + error); return FALSE; } } @@ -2184,7 +2325,7 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, 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; + guint32 changed_flags = 0u; if (!_team_attr_data_is_relevant (attr_data, self->d.is_port)) continue; @@ -2193,27 +2334,32 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, 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); + changed_flags = _team_setting_value_set (self, + attr_data, + &val, + SET_FIELD_MODE_SET, + RESET_JSON_NO); } 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); + changed_flags = _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, + SET_FIELD_MODE_SET, + RESET_JSON_NO); } 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)); + changed_flags = _team_setting_value_master_runner_tx_hash_set_list (self, + strv, + NM_MIN (len, (gsize) G_MAXUINT), + SET_FIELD_MODE_SET, + RESET_JSON_NO); } else nm_assert_not_reached (); - extra_changed |= changed; + extra_changed |= changed_flags; } if ( !variants[NM_TEAM_ATTRIBUTE_CONFIG] @@ -2272,6 +2418,55 @@ nm_team_setting_maybe_changed (NMSetting *source, /*****************************************************************************/ +NMTeamSetting * +_nm_setting_get_team_setting (struct _NMSetting *setting) +{ + if (NM_IS_SETTING_TEAM (setting)) + return _nm_setting_team_get_team_setting (NM_SETTING_TEAM (setting)); + return _nm_setting_team_port_get_team_setting (NM_SETTING_TEAM_PORT (setting)); +} + +GVariant * +_nm_team_settings_property_to_dbus (const NMSettInfoSetting *sett_info, + guint property_idx, + NMConnection *connection, + NMSetting *setting, + NMConnectionSerializationFlags flags) +{ + NMTeamSetting *self = _nm_setting_get_team_setting (setting); + const NMSettInfoProperty *property = &sett_info->property_infos[property_idx]; + NMTeamAttribute team_attr = property->param_spec->param_id; + const TeamAttrData *attr_data = _team_attr_data_get (self->d.is_port, team_attr); + + if (!_team_setting_has_field (self, attr_data)) + return NULL; + + if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) { + return nm_value_type_to_variant (attr_data->value_type, + _team_setting_get_field (self, attr_data)); + } + if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) + return _nm_utils_team_link_watchers_to_variant (self->d.link_watchers); + if ( !self->d.is_port + && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { + return g_variant_new_strv (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); + } + + nm_assert_not_reached (); + return NULL; +} + +void +_nm_team_settings_property_from_dbus_link_watchers (GVariant *dbus_value, + GValue *prop_value) +{ + g_value_take_boxed (prop_value, + _nm_utils_team_link_watchers_from_variant (dbus_value, FALSE, NULL)); +} + +/*****************************************************************************/ + NMTeamSetting * nm_team_setting_new (gboolean is_port, const char *js_str) diff --git a/libnm-core/nm-team-utils.h b/libnm-core/nm-team-utils.h index e443b27dd3..0e897da96a 100644 --- a/libnm-core/nm-team-utils.h +++ b/libnm-core/nm-team-utils.h @@ -96,6 +96,8 @@ struct _NMTeamSettingData { bool is_port:1; + guint32 has_fields_mask; + union { struct { const GPtrArray *runner_tx_hash; @@ -185,6 +187,10 @@ nm_team_setting_value_get_string (const NMTeamSetting *self, /*****************************************************************************/ +guint32 nm_team_setting_value_reset (NMTeamSetting *self, + NMTeamAttribute team_attr, + gboolean to_default /* or else unset */); + guint32 _nm_team_setting_value_set (NMTeamSetting *self, NMTeamAttribute team_attr, NMValueType value_type, @@ -269,7 +275,7 @@ gboolean nm_team_setting_reset_from_dbus (NMTeamSetting *self, GPtrArray *_nm_utils_team_link_watchers_from_variant (GVariant *value, gboolean strict_parsing, GError **error); -GVariant *_nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers); +GVariant *_nm_utils_team_link_watchers_to_variant (const GPtrArray *link_watchers); /*****************************************************************************/ @@ -277,4 +283,24 @@ gboolean nm_team_setting_maybe_changed (struct _NMSetting *source, const GParamSpec *const*obj_properties, guint32 changed); +struct _NMSettingTeam; +struct _NMSettingTeamPort; +NMTeamSetting *_nm_setting_team_get_team_setting (struct _NMSettingTeam *setting); +NMTeamSetting *_nm_setting_team_port_get_team_setting (struct _NMSettingTeamPort *setting); +NMTeamSetting *_nm_setting_get_team_setting (struct _NMSetting *setting); + +/*****************************************************************************/ + +#include "nm-connection.h" +#include "nm-core-internal.h" + +GVariant *_nm_team_settings_property_to_dbus (const NMSettInfoSetting *sett_info, + guint property_idx, + NMConnection *connection, + NMSetting *setting, + NMConnectionSerializationFlags flags); + +void _nm_team_settings_property_from_dbus_link_watchers (GVariant *dbus_value, + GValue *prop_value); + #endif /* __NM_TEAM_UITLS_H__ */ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index a8d182c457..1c023b65bd 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -6862,10 +6862,6 @@ test_nm_utils_team_config_equal (void) TRUE); /* team config */ - _team_config_equal_check ("{ }", - "{ \"runner\" : { \"name\" : \"roundrobin\"} }", - FALSE, - TRUE); _team_config_equal_check ("{ }", "{ \"runner\" : { \"name\" : \"random\"} }", FALSE, @@ -6889,7 +6885,7 @@ test_nm_utils_team_config_equal (void) _team_config_equal_check ("{ \"runner\" : { \"name\" : \"lacp\"} }", "{ \"runner\" : { \"name\" : \"lacp\", \"tx_hash\" : [ \"eth\", \"ipv4\", \"ipv6\" ] } }", FALSE, - TRUE); + !WITH_JSON_VALIDATION); _team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }", "{ \"runner\" : { \"name\" : \"roundrobin\", \"tx_hash\" : [ \"eth\", \"ipv4\", \"ipv6\" ] } }", FALSE, @@ -6903,7 +6899,7 @@ test_nm_utils_team_config_equal (void) _team_config_equal_check ("{ }", "{ \"link_watch\" : { \"name\" : \"ethtool\"} }", TRUE, - TRUE); + !WITH_JSON_VALIDATION); _team_config_equal_check ("{ }", "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", TRUE, @@ -6911,7 +6907,7 @@ test_nm_utils_team_config_equal (void) _team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"ethtool\"} }", "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", TRUE, - TRUE); + !WITH_JSON_VALIDATION); _team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", TRUE, diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 8741d97737..5c0b731137 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -1057,11 +1057,11 @@ static void test_runner_roundrobin_sync_from_config (void) { _test_team_config_sync ("", - 0, 0, 0, 0, - NM_SETTING_TEAM_RUNNER_ROUNDROBIN, + -1, -1, -1, -1, + NULL, NULL, NULL, NULL, -1, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, NULL); } @@ -1069,11 +1069,11 @@ static void test_runner_broadcast_sync_from_config (void) { _test_team_config_sync ("{\"runner\": {\"name\": \"broadcast\"}}", - 0, 0, 0, 0, + -1, -1, -1, -1, NM_SETTING_TEAM_RUNNER_BROADCAST, NULL, NULL, NULL, -1, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, NULL); } @@ -1081,11 +1081,11 @@ static void test_runner_random_sync_from_config (void) { _test_team_config_sync ("{\"runner\": {\"name\": \"random\"}}", - 0, 0, 0, 0, + -1, -1, -1, -1, NM_SETTING_TEAM_RUNNER_RANDOM, NULL, NULL, NULL, -1, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, NULL); } @@ -1093,12 +1093,11 @@ static void test_runner_activebackup_sync_from_config (void) { _test_team_config_sync ("{\"runner\": {\"name\": \"activebackup\"}}", - NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT, 0, - NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT, 0, + -1, -1, -1, -1, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP, - NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_DEFAULT, + NULL, NULL, NULL, -1, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, NULL); } @@ -1113,29 +1112,29 @@ test_runner_loadbalance_sync_from_config (void) g_ptr_array_add (tx_hash, g_strdup ("ipv6")); _test_team_config_sync ("{\"runner\": {\"name\": \"loadbalance\"}}", - 0, 0, 0, 0, + -1, -1, -1, -1, NM_SETTING_TEAM_RUNNER_LOADBALANCE, NULL, - tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, - FALSE, FALSE, -1, -1, NULL, + NULL, NULL, -1, + TRUE, FALSE, -1, -1, NULL, NULL); _test_team_config_sync ("{\"runner\": {\"name\": \"loadbalance\", " "\"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}", - 0, 0, 0, 0, + -1, -1, -1, -1, NM_SETTING_TEAM_RUNNER_LOADBALANCE, NULL, - tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, - FALSE, FALSE, -1, -1, NULL, + tx_hash, NULL, -1, + TRUE, FALSE, -1, -1, NULL, NULL); _test_team_config_sync ("{\"runner\": {\"name\": \"loadbalance\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"], " "\"tx_balancer\": {\"name\": \"basic\", \"balancing_interval\": 30}}}", - 0, 0, 0, 0, + -1, -1, -1, -1, NM_SETTING_TEAM_RUNNER_LOADBALANCE, NULL, tx_hash, "basic", 30, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, NULL); } @@ -1150,21 +1149,21 @@ test_runner_lacp_sync_from_config (void) g_ptr_array_add (tx_hash, g_strdup ("ipv6")); _test_team_config_sync ("{\"runner\": {\"name\": \"lacp\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}", - 0, 0, 0, 0, + -1, -1, -1, -1, NM_SETTING_TEAM_RUNNER_LACP, NULL, - tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, - TRUE, FALSE, NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT, 0, - NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT, + tx_hash, NULL, -1, + TRUE, FALSE, -1, -1, + NULL, NULL); _test_team_config_sync ("{\"runner\": {\"name\": \"lacp\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"], " "\"active\": false, \"fast_rate\": true, \"sys_prio\": 10, \"min_ports\": 5, " "\"agg_select_policy\": \"port_config\"}}", - 0, 0, 0, 0, + -1, -1, -1, -1, NM_SETTING_TEAM_RUNNER_LACP, NULL, - tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, + tx_hash, NULL, -1, FALSE, TRUE, 10, 5, "port_config", NULL); } @@ -1177,11 +1176,11 @@ test_watcher_ethtool_sync_from_config (void) link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); g_ptr_array_add (link_watchers, nm_team_link_watcher_new_ethtool (0, 0, NULL)); _test_team_config_sync ("{\"link_watch\": {\"name\": \"ethtool\"}}", - 0, 0, 0, 0, - "roundrobin", + -1, -1, -1, -1, + NULL, NULL, NULL, NULL, -1, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, link_watchers); } @@ -1193,11 +1192,11 @@ test_watcher_nsna_ping_sync_from_config (void) link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); g_ptr_array_add (link_watchers, nm_team_link_watcher_new_nsna_ping (0, 0, 3, "target.host", NULL)); _test_team_config_sync ("{\"link_watch\": {\"name\": \"nsna_ping\", \"target_host\": \"target.host\"}}", - 0, 0, 0, 0, - "roundrobin", + -1, -1, -1, -1, + NULL, NULL, NULL, NULL, -1, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, link_watchers); } @@ -1211,11 +1210,11 @@ test_watcher_arp_ping_sync_from_config (void) nm_team_link_watcher_new_arp_ping (0, 0, 3, "target.host", "source.host", 0, NULL)); _test_team_config_sync ("{\"link_watch\": {\"name\": \"arp_ping\", \"target_host\": \"target.host\", " "\"source_host\": \"source.host\"}}", - 0, 0, 0, 0, - "roundrobin", + -1, -1, -1, -1, + NULL, NULL, NULL, NULL, -1, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, link_watchers); } @@ -1240,11 +1239,11 @@ test_multiple_watchers_sync_from_config (void) "\"validate_active\": true, \"validate_inactive\": true, \"send_always\": true}, " "{\"name\": \"nsna_ping\", \"init_wait\": 3, \"interval\": 6, \"missed_max\": 9, " "\"target_host\": \"target.host\"}]}", - 0, 0, 0, 0, - "roundrobin", + -1, -1, -1, -1, + NULL, NULL, NULL, NULL, -1, - FALSE, FALSE, -1, -1, NULL, + TRUE, FALSE, -1, -1, NULL, link_watchers); } @@ -1300,52 +1299,52 @@ _test_team_port_config_sync (const char *team_port_config, static void test_team_port_default (void) { - _test_team_port_config_sync ("", -1, 0, FALSE, 255, 0, NULL); + _test_team_port_config_sync ("", -1, 0, FALSE, -1, -1, NULL); } static void test_team_port_queue_id (void) { _test_team_port_config_sync ("{\"queue_id\": 3}", - 3, 0, FALSE, 255, 0, NULL); + 3, 0, FALSE, -1, -1, NULL); _test_team_port_config_sync ("{\"queue_id\": 0}", - 0, 0, FALSE, 255, 0, NULL); + 0, 0, FALSE, -1, -1, NULL); } static void test_team_port_prio (void) { _test_team_port_config_sync ("{\"prio\": 6}", - -1, 6, FALSE, 255, 0, NULL); + -1, 6, FALSE, -1, -1, NULL); _test_team_port_config_sync ("{\"prio\": 0}", - -1, 0, FALSE, 255, 0, NULL); + -1, 0, FALSE, -1, -1, NULL); } static void test_team_port_sticky (void) { _test_team_port_config_sync ("{\"sticky\": true}", - -1, 0, TRUE, 255, 0, NULL); + -1, 0, TRUE, -1, -1, NULL); _test_team_port_config_sync ("{\"sticky\": false}", - -1, 0, FALSE, 255, 0, NULL); + -1, 0, FALSE, -1, -1, NULL); } static void test_team_port_lacp_prio (void) { _test_team_port_config_sync ("{\"lacp_prio\": 9}", - -1, 0, FALSE, 9, 0, NULL); + -1, 0, FALSE, 9, -1, NULL); _test_team_port_config_sync ("{\"lacp_prio\": 0}", - -1, 0, FALSE, 0, 0, NULL); + -1, 0, FALSE, 0, -1, NULL); } static void test_team_port_lacp_key (void) { _test_team_port_config_sync ("{\"lacp_key\": 12}", - -1, 0, FALSE, 255, 12, NULL); + -1, 0, FALSE, -1, 12, NULL); _test_team_port_config_sync ("{\"lacp_key\": 0}", - -1, 0, FALSE, 255, 0, NULL); + -1, 0, FALSE, -1, 0, NULL); } static void @@ -1386,20 +1385,6 @@ _check_team_setting (NMSetting *setting) 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 @@ -1420,6 +1405,7 @@ _check_team_setting (NMSetting *setting) * 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_clone = nm_setting_duplicate (setting); setting = setting_clone; if (is_port) { g_object_set (setting, @@ -1499,6 +1485,12 @@ test_team_setting (void) 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 } }"); + + g_object_set (setting, + NM_SETTING_TEAM_CONFIG, + "{ \"runner\": { \"tx_hash\": [ \"eth\", \"l3\" ] } }", + NULL); + _check_team_setting (setting); } /*****************************************************************************/ From dfa8ecdab82807fef0fc648ff3c52d74ff91a14e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 31 May 2019 18:27:45 +0200 Subject: [PATCH 4/5] cli: remove unnecessary workaround for clearing team link watchers and runner-tx-hash This is fixed in libnm. Resetting the GObject property clears the list of watchers and tx-hashes. Since nmcli requires a libnm version >= itself, this workaround is no longer necessary. --- clients/common/nm-meta-setting-desc.c | 82 --------------------------- 1 file changed, 82 deletions(-) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index a99bb014ee..25969cd1f1 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -3672,85 +3672,6 @@ _validate_fcn_team_config (const char *value, char **out_to_free, GError **error RETURN_STR_TO_FREE (json); } -static void -_multilist_clear_all_fcn_team_runner_tx_hash (NMSetting *setting) -{ - /* Workaround libnm bug (confirmed against version 1.16.0). - * We need to both clear the GObject property and call the libnm API. - * - * This workaround was added in nmcli as [1]. This needs fixing in libnm. - * - * Without this, CI test "team_abs_set_runner_tx_hash" fails. - * Try (without the following workaround): */ -#if 0 - $ (nmcli connection delete team0 ; :); \ - nmcli connection add type team con-name team0 ifname team0 autoconnect no \ - team.runner lacp && \ - echo ">>> FIRST:" && \ - PAGER= nmcli -o connection show team0 && \ - nmcli connection modify team0 team.runner-tx-hash l3 && \ - echo ">>> AFTER:" && \ - PAGER= nmcli -o connection show team0 -#endif - /* See also: - * - * - https://github.com/NetworkManager/NetworkManager/pull/318 - * - https://bugzilla.redhat.com/show_bug.cgi?id=1691619 - * - * [1] https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=350dbb55abf3a80267c398e6f64c2cee4645475a - */ - - /* it appears, we don't really need _gobject_property_reset(). Just to be sure - * also call it. */ - _gobject_property_reset (setting, NM_SETTING_TEAM_RUNNER_TX_HASH, FALSE); - while (nm_setting_team_get_num_runner_tx_hash (NM_SETTING_TEAM (setting))) - nm_setting_team_remove_runner_tx_hash (NM_SETTING_TEAM (setting), 0); -} - -static void -_objlist_clear_all_fcn_team_link_watchers (NMSetting *setting) -{ - /* the same workaround as _multilist_clear_all_fcn_team_runner_tx_hash() above. - * - * Reproduce with: */ -#if 0 - $ (nmcli connection delete team0 ; :); \ - nmcli connection add type team con-name team0 ifname team0 autoconnect no \ - team.link-watchers 'name=arp_ping source-host=172.16.1.1 target-host=172.16.1.254, name=ethtool delay-up=3' && \ - echo ">>> FIRST:" && \ - PAGER= nmcli -o connection show team0 && \ - nmcli connection modify team0 team.link-watchers 'name=ethtool delay-up=4' && \ - echo ">>> AFTER:" && \ - PAGER= nmcli -o connection show team0 - - (nmcli connection delete team0-slave ; :); \ - nmcli connection add type ethernet con-name team0-slave master team0 slave-type team ifname eth0 autoconnect no \ - team-port.link-watchers 'name=arp_ping source-host=172.16.1.1 target-host=172.16.1.254, name=ethtool delay-up=3' && \ - echo ">>> FIRST:" && \ - PAGER= nmcli -o connection show team0-slave && \ - nmcli connection modify team0-slave team.link-watchers 'name=ethtool delay-up=4' && \ - echo ">>> AFTER:" && \ - PAGER= nmcli -o connection show team0-slave -#endif - /* See also: - * - * - https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=72bf38cad6ca6033d0117bf67b0e726001922d8f - * - https://github.com/NetworkManager/NetworkManager/pull/318 - * - https://bugzilla.redhat.com/show_bug.cgi?id=1691619 - */ - - /* In this case, it appears both GObject reset and nm_setting_team*_clear_link_watchers() - * work (on their own). So, we might not need the workaround. - * Just to be sure, as something is not right with libnm here. */ - if (NM_IS_SETTING_TEAM (setting)) { - _gobject_property_reset (setting, NM_SETTING_TEAM_LINK_WATCHERS, FALSE); - nm_setting_team_clear_link_watchers (NM_SETTING_TEAM (setting)); - } else { - _gobject_property_reset (setting, NM_SETTING_TEAM_PORT_LINK_WATCHERS, FALSE); - nm_setting_team_port_clear_link_watchers (NM_SETTING_TEAM_PORT (setting)); - } -} - static void _objlist_obj_to_str_fcn_team_link_watchers (NMMetaAccessorGetType get_type, NMSetting *setting, @@ -6593,7 +6514,6 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( PROPERTY_TYP_DATA_SUBTYPE (multilist, .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingTeam, nm_setting_team_get_num_runner_tx_hash), - .clear_all_fcn = _multilist_clear_all_fcn_team_runner_tx_hash, .add_fcn = MULTILIST_ADD_FCN (NMSettingTeam, nm_setting_team_add_runner_tx_hash), .remove_by_idx_fcn_u = MULTILIST_REMOVE_BY_IDX_FCN_U (NMSettingTeam, nm_setting_team_remove_runner_tx_hash), .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingTeam, nm_setting_team_remove_runner_tx_hash_by_value), @@ -6676,7 +6596,6 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( PROPERTY_TYP_DATA_SUBTYPE (objlist, .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingTeam, nm_setting_team_get_num_link_watchers), - .clear_all_fcn = _objlist_clear_all_fcn_team_link_watchers, .obj_to_str_fcn = _objlist_obj_to_str_fcn_team_link_watchers, .set_fcn = _objlist_set_fcn_team_link_watchers, .remove_by_idx_fcn_u = OBJLIST_REMOVE_BY_IDX_FCN_U (NMSettingTeam, nm_setting_team_remove_link_watcher), @@ -6768,7 +6687,6 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = { .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( PROPERTY_TYP_DATA_SUBTYPE (objlist, .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingTeamPort, nm_setting_team_port_get_num_link_watchers), - .clear_all_fcn = _objlist_clear_all_fcn_team_link_watchers, .obj_to_str_fcn = _objlist_obj_to_str_fcn_team_link_watchers, .set_fcn = _objlist_set_fcn_team_link_watchers, .remove_by_idx_fcn_u = OBJLIST_REMOVE_BY_IDX_FCN_U (NMSettingTeamPort, nm_setting_team_port_remove_link_watcher), From cd74fc28b5ed5846112e34aa255b1c62319d367f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 1 Jun 2019 10:28:42 +0200 Subject: [PATCH 5/5] libnm/team: strict validate team settings by libnm clients not sending the JSON When parsing a NMSettingTeam/NMSettingTeamPort from GVariant, the JSON "config" is always preferred. If that field is present, all other attributes are ignored (aside from validating that the individual fields are as expected). The idea is that the JSON config anyway must contain everything that artificial properties could. In this mode, also no validation is performed and the setting is always accepted (regardless whether libnm thinks the setting verifies). When a libnm client created the setting via the artificial properties, only send them via D-Bus and exclude the JSON config. This turns on strict validation server side. Now we actually get validation of the settings: $ nmcli connection add type team team.runner-tx-hash l3 Error: Failed to add 'team' connection: team.runner: runner-tx-hash is only allowed for runners loadbalance,lacp this is obviously a change in behavior as previously all settings would have been accepted, regardless whether they made sense. --- libnm-core/nm-setting-team-port.c | 1 + libnm-core/nm-setting-team.c | 1 + libnm-core/nm-team-utils.c | 82 +++++++++++++++++++------------ 3 files changed, 53 insertions(+), 31 deletions(-) diff --git a/libnm-core/nm-setting-team-port.c b/libnm-core/nm-setting-team-port.c index 504798c163..c0d78a7044 100644 --- a/libnm-core/nm-setting-team-port.c +++ b/libnm-core/nm-setting-team-port.c @@ -578,6 +578,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass) 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: diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index a9095836d3..3e057c5451 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -1525,6 +1525,7 @@ nm_setting_team_class_init (NMSettingTeamClass *klass) G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + _property_override (properties_override, obj_properties[NM_TEAM_ATTRIBUTE_CONFIG], "s", FALSE); /** * NMSettingTeam:notify-peers-count: diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c index 701424a725..7346c1d03e 100644 --- a/libnm-core/nm-team-utils.c +++ b/libnm-core/nm-team-utils.c @@ -292,8 +292,6 @@ 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_properties (const NMTeamSetting *self, - GError **error); static void _link_watcher_to_json (const NMTeamLinkWatcher *link_watcher, GString *gstr); @@ -1855,7 +1853,6 @@ 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); @@ -1917,13 +1914,6 @@ nm_team_setting_config_set (NMTeamSetting *self, const char *js_str) TRUE, has_lst, val_lst); - - if ( !unrecognized_content - && _team_setting_verify_properties (self, NULL)) { - /* if we could parse everything without unexpected/unknown data, - * we switch into strictly validating mode. */ - new_strict_validated = TRUE; - } } } @@ -1932,7 +1922,7 @@ nm_team_setting_config_set (NMTeamSetting *self, const char *js_str) if (do_set_default) changed_flags |= _team_setting_set_default (self); - self->_data_priv.strict_validated = new_strict_validated; + self->_data_priv.strict_validated = FALSE; 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); @@ -2293,20 +2283,36 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, } if (variants[NM_TEAM_ATTRIBUTE_LINK_WATCHERS]) { - gs_free_error GError *local = NULL; - v_link_watchers = _nm_utils_team_link_watchers_from_variant (variants[NM_TEAM_ATTRIBUTE_LINK_WATCHERS], - NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT), - &local); - if (local) { - g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("invalid link-watchers: %s"), - local->message); - _team_setting_prefix_error (self, - NM_SETTING_TEAM_LINK_WATCHERS, - NM_SETTING_TEAM_PORT_LINK_WATCHERS, - error); - return FALSE; + if ( variants[NM_TEAM_ATTRIBUTE_CONFIG] + && WITH_JSON_VALIDATION + && !NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) { + /* we don't require the content of the "link-watchers" and we also + * don't perform strict validation. No need to parse it. */ + } else { + gs_free_error GError *local = NULL; + + /* We might need the parsed v_link_watchers array below (because there is no JSON + * "config" present or because we don't build WITH_JSON_VALIDATION). + * + * Or we might run with NM_SETTING_PARSE_FLAGS_STRICT. In that mode, we may not necessarily + * require that the entire setting as a whole validates (if a JSON config is present and + * we are not "strict_validated") , but we require that we can at least parse the link watchers + * on their own. */ + v_link_watchers = _nm_utils_team_link_watchers_from_variant (variants[NM_TEAM_ATTRIBUTE_LINK_WATCHERS], + NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT), + &local); + if ( local + && NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("invalid link-watchers: %s"), + local->message); + _team_setting_prefix_error (self, + NM_SETTING_TEAM_LINK_WATCHERS, + NM_SETTING_TEAM_PORT_LINK_WATCHERS, + error); + return FALSE; + } } } @@ -2315,8 +2321,8 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, ? g_variant_get_string (variants[NM_TEAM_ATTRIBUTE_CONFIG], NULL) : NULL); - if ( variants[NM_TEAM_ATTRIBUTE_CONFIG] - && WITH_JSON_VALIDATION) { + if ( WITH_JSON_VALIDATION + && variants[NM_TEAM_ATTRIBUTE_CONFIG]) { /* 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. */ @@ -2362,8 +2368,7 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, extra_changed |= changed_flags; } - if ( !variants[NM_TEAM_ATTRIBUTE_CONFIG] - && extra_changed) { + if (!variants[NM_TEAM_ATTRIBUTE_CONFIG]) { /* clear the JSON string so it can be regenerated. But only if we didn't set * it above. */ self->_data_priv.strict_validated = TRUE; @@ -2434,9 +2439,24 @@ _nm_team_settings_property_to_dbus (const NMSettInfoSetting *sett_info, NMConnectionSerializationFlags flags) { NMTeamSetting *self = _nm_setting_get_team_setting (setting); - const NMSettInfoProperty *property = &sett_info->property_infos[property_idx]; - NMTeamAttribute team_attr = property->param_spec->param_id; - const TeamAttrData *attr_data = _team_attr_data_get (self->d.is_port, team_attr); + const TeamAttrData *attr_data = _team_attr_data_get (self->d.is_port, sett_info->property_infos[property_idx].param_spec->param_id); + + if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_CONFIG) { + const char *config; + + if ( self->d.strict_validated + && !_nm_utils_is_manager_process) { + /* if we are in strict validating mode on the client side, the JSON is generated + * artificially. In this case, don't send the config via D-Bus to the server. + * + * This also will cause NetworkManager to strictly validate the settings. + * If a JSON "config" is present, strict validation won't be performed. */ + return NULL; + } + + config = nm_team_setting_config_get (self); + return config ? g_variant_new_string (config) : NULL; + } if (!_team_setting_has_field (self, attr_data)) return NULL;