diff options
-rw-r--r-- | clients/common/nm-meta-setting-desc.c | 46 | ||||
-rw-r--r-- | libnm-core/nm-setting-team-port.c | 46 | ||||
-rw-r--r-- | libnm-core/nm-setting-team.c | 65 | ||||
-rw-r--r-- | libnm-core/nm-team-utils.c | 1057 | ||||
-rw-r--r-- | libnm-core/nm-team-utils.h | 28 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 10 | ||||
-rw-r--r-- | 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 @@ -6514,6 +6514,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .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", }, @@ -6525,6 +6529,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .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", }, @@ -6536,6 +6544,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .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", }, @@ -6547,6 +6559,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .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", }, @@ -6598,6 +6614,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .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", }, @@ -6615,6 +6635,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .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", }, @@ -6626,6 +6650,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { .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", }, ), @@ -6688,6 +6720,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = { .value_infos = INT_VALUE_INFOS ( { .value.i64 = 0, + .nick = "unset", + }, + { + .value.i64 = 0, .nick = "default", }, ), @@ -6701,6 +6737,10 @@ 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 = -1, + .nick = "unset", + }, + { .value.i64 = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT, .nick = "default", }, @@ -6712,6 +6752,10 @@ 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 = -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_LINK_WATCHERS, link_watchers, NM_VALUE_TYPE_UNSPEC, NM_SETTING_TEAM_LINK_WATCHERS, _JS_KEYS ("link_watch"), ), - - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT, master.notify_peers_count, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, _JS_KEYS ("notify_peers", "count"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL, master.notify_peers_interval, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, _JS_KEYS ("notify_peers", "interval"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT, master.mcast_rejoin_count, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_MCAST_REJOIN_COUNT, _JS_KEYS ("mcast_rejoin", "count"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL, master.mcast_rejoin_interval, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, _JS_KEYS ("mcast_rejoin", "interval"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER, master.runner, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER, _JS_KEYS ("runner", "name"), .default_val.v_string = NM_SETTING_TEAM_RUNNER_DEFAULT, ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY, master.runner_hwaddr_policy, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, _JS_KEYS ("runner", "hwaddr_policy"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, master.runner_tx_hash, NM_VALUE_TYPE_UNSPEC, NM_SETTING_TEAM_RUNNER_TX_HASH, _JS_KEYS ("runner", "tx_hash"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER, master.runner_tx_balancer, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER_TX_BALANCER, _JS_KEYS ("runner", "tx_balancer", "name"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL, master.runner_tx_balancer_interval, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, _JS_KEYS ("runner", "tx_balancer", "balancing_interval"), .default_val.v_int32 = -1 ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE, master.runner_active, NM_VALUE_TYPE_BOOL, NM_SETTING_TEAM_RUNNER_ACTIVE, _JS_KEYS ("runner", "active"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE, master.runner_fast_rate, NM_VALUE_TYPE_BOOL, NM_SETTING_TEAM_RUNNER_FAST_RATE, _JS_KEYS ("runner", "fast_rate"), ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO, master.runner_sys_prio, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_RUNNER_SYS_PRIO, _JS_KEYS ("runner", "sys_prio"), .default_val.v_int32 = -1, ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS, master.runner_min_ports, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_RUNNER_MIN_PORTS, _JS_KEYS ("runner", "min_ports"), .default_val.v_int32 = -1, ), - _INIT (0, NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY, master.runner_agg_select_policy, NM_VALUE_TYPE_STRING, NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, _JS_KEYS ("runner", "agg_select_policy"), ), - - _INIT (1, NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID, port.queue_id, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_QUEUE_ID, _JS_KEYS ("queue_id"), .default_val.v_int32 = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT, ), - _INIT (1, NM_TEAM_ATTRIBUTE_PORT_PRIO, port.prio, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_PRIO, _JS_KEYS ("prio"), ), - _INIT (1, NM_TEAM_ATTRIBUTE_PORT_STICKY, port.sticky, NM_VALUE_TYPE_BOOL, NM_SETTING_TEAM_PORT_STICKY, _JS_KEYS ("sticky"), ), - _INIT (1, NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO, port.lacp_prio, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_LACP_PRIO, _JS_KEYS ("lacp_prio"), .default_val.v_int32 = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT, ), - _INIT (1, NM_TEAM_ATTRIBUTE_PORT_LACP_KEY, port.lacp_key, NM_VALUE_TYPE_INT32, NM_SETTING_TEAM_PORT_LACP_KEY, _JS_KEYS ("lacp_key"), ), + _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"), _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"), _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"), _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) { - const TeamAttrData *attr_data; gpointer p_field; + gboolean changed; nm_assert (self); - - attr_data = _team_attr_data_get (self->d.is_port, team_attr); - + _team_attr_data_ASSERT (attr_data); 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); + 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; + + nm_assert (self); + + attr_data = _team_attr_data_get (self->d.is_port, 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; @@ -1871,103 +1944,165 @@ 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 (!_team_attr_data_is_relevant (attr_data, self->d.is_port)) + continue; + if (!_team_setting_has_field (self, attr_data)) + continue; + + if (attr_data->has_range) { + gconstpointer p_field; - 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]; + 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 (!val[0]) { + 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 (!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")); + if (!self->d.is_port) { + + 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, + _("%s is only allowed for runner %s"), + attr_data->property_name, + e->valid_runners[0]); } else { + gs_free char *s = NULL; + + s = g_strjoinv (",", (char **) e->valid_runners); g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, - _("unknown link watcher \"%s\""), name); + _("%s is only allowed for runners %s"), + attr_data->property_name, + s); } - _team_setting_prefix_error (self, error, NM_SETTING_TEAM_LINK_WATCHERS, NM_SETTING_TEAM_PORT_LINK_WATCHERS); + _team_setting_prefix_error_plain (self->d.is_port, NM_SETTING_TEAM_RUNNER, error); return FALSE; } - - if ( NM_IN_STRSET (name, - NM_TEAM_LINK_WATCHER_ARP_PING, - NM_TEAM_LINK_WATCHER_NSNA_PING) - && !nm_team_link_watcher_get_target_host (link_watcher)) { - g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING, - _("missing target host")); - _team_setting_prefix_error (self, error, NM_SETTING_TEAM_LINK_WATCHERS, NM_SETTING_TEAM_PORT_LINK_WATCHERS); + } 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; } - 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); + } + + 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] @@ -2273,6 +2419,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 @@ -6863,10 +6863,6 @@ test_nm_utils_team_config_equal (void) /* team config */ _team_config_equal_check ("{ }", - "{ \"runner\" : { \"name\" : \"roundrobin\"} }", - FALSE, - TRUE); - _team_config_equal_check ("{ }", "{ \"runner\" : { \"name\" : \"random\"} }", FALSE, !WITH_JSON_VALIDATION); @@ -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); } /*****************************************************************************/ |