NetworkManager/libnm-core/nm-setting-team-port.c

686 lines
23 KiB
C
Raw Normal View History

// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright (C) 2017 Red Hat, Inc.
* Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us>
*/
#include "nm-default.h"
#include "nm-setting-team-port.h"
#include <ctype.h>
#include <stdlib.h>
#include "nm-utils.h"
#include "nm-utils-private.h"
#include "nm-connection-private.h"
#include "nm-setting-connection.h"
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
#include "nm-team-utils.h"
/**
* SECTION:nm-setting-team-port
* @short_description: Describes connection properties for team ports
*
* The #NMSettingTeamPort object is a #NMSetting subclass that describes
* optional properties that apply to team ports.
**/
/*****************************************************************************/
static GParamSpec *obj_properties[_NM_TEAM_ATTRIBUTE_PORT_NUM] = {
NULL,
};
typedef struct {
NMTeamSetting *team_setting;
} NMSettingTeamPortPrivate;
G_DEFINE_TYPE(NMSettingTeamPort, nm_setting_team_port, NM_TYPE_SETTING)
#define NM_SETTING_TEAM_PORT_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE((o), NM_TYPE_SETTING_TEAM_PORT, NMSettingTeamPortPrivate))
/*****************************************************************************/
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.
2019-05-31 10:48:47 +02:00
NMTeamSetting *
_nm_setting_team_port_get_team_setting(NMSettingTeamPort *setting)
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.
2019-05-31 10:48:47 +02:00
{
return NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting;
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.
2019-05-31 10:48:47 +02:00
}
/*****************************************************************************/
#define _maybe_changed(self, changed) \
nm_team_setting_maybe_changed(NM_SETTING(_NM_ENSURE_TYPE(NMSettingTeamPort *, self)), \
(const GParamSpec *const *) obj_properties, \
(changed))
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
#define _maybe_changed_with_assert(self, changed) \
G_STMT_START \
{ \
if (!_maybe_changed((self), (changed))) \
nm_assert_not_reached(); \
} \
G_STMT_END
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
/*****************************************************************************/
/**
* nm_setting_team_port_get_config:
* @setting: the #NMSettingTeamPort
*
* Returns: the #NMSettingTeamPort:config property of the setting
**/
const char *
nm_setting_team_port_get_config(NMSettingTeamPort *setting)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), NULL);
return nm_team_setting_config_get(NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting);
}
/**
* nm_setting_team_port_get_queue_id:
* @setting: the #NMSettingTeamPort
*
* Returns: the #NMSettingTeamPort:queue_id property of the setting
*
* Since: 1.12
**/
int
nm_setting_team_port_get_queue_id(NMSettingTeamPort *setting)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), -1);
return NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting->d.port.queue_id;
}
/**
* nm_setting_team_port_get_prio:
* @setting: the #NMSettingTeamPort
*
* Returns: the #NMSettingTeamPort:prio property of the setting
*
* Since: 1.12
**/
int
nm_setting_team_port_get_prio(NMSettingTeamPort *setting)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting->d.port.prio;
}
/**
* nm_setting_team_port_get_sticky:
* @setting: the #NMSettingTeamPort
*
* Returns: the #NMSettingTeamPort:sticky property of the setting
*
* Since: 1.12
**/
gboolean
nm_setting_team_port_get_sticky(NMSettingTeamPort *setting)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), FALSE);
return NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting->d.port.sticky;
}
/**
* nm_setting_team_port_get_lacp_prio:
* @setting: the #NMSettingTeamPort
*
* Returns: the #NMSettingTeamPort:lacp-prio property of the setting
*
* Since: 1.12
**/
int
nm_setting_team_port_get_lacp_prio(NMSettingTeamPort *setting)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting->d.port.lacp_prio;
}
/**
* nm_setting_team_port_get_lacp_key:
* @setting: the #NMSettingTeamPort
*
* Returns: the #NMSettingTeamPort:lacp-key property of the setting
*
* Since: 1.12
**/
int
nm_setting_team_port_get_lacp_key(NMSettingTeamPort *setting)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting->d.port.lacp_key;
}
/**
* nm_setting_team_port_get_num_link_watchers:
* @setting: the #NMSettingTeamPort
*
* Returns: the number of configured link watchers
*
* Since: 1.12
**/
guint
nm_setting_team_port_get_num_link_watchers(NMSettingTeamPort *setting)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting->d.link_watchers->len;
}
/**
* nm_setting_team_port_get_link_watcher:
* @setting: the #NMSettingTeamPort
* @idx: index number of the link watcher to return
*
* Returns: (transfer none): the link watcher at index @idx.
*
* Since: 1.12
**/
NMTeamLinkWatcher *
nm_setting_team_port_get_link_watcher(NMSettingTeamPort *setting, guint idx)
{
NMSettingTeamPortPrivate *priv;
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), NULL);
priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(setting);
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
g_return_val_if_fail(idx < priv->team_setting->d.link_watchers->len, NULL);
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
return priv->team_setting->d.link_watchers->pdata[idx];
}
/**
* nm_setting_team_port_add_link_watcher:
* @setting: the #NMSettingTeamPort
* @link_watcher: the link watcher to add
*
* Appends a new link watcher to the setting.
*
* Returns: %TRUE if the link watcher is added; %FALSE if an identical link
* watcher was already there.
*
* Since: 1.12
**/
gboolean
nm_setting_team_port_add_link_watcher(NMSettingTeamPort *setting, NMTeamLinkWatcher *link_watcher)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), FALSE);
g_return_val_if_fail(link_watcher != NULL, FALSE);
return _maybe_changed(setting,
nm_team_setting_value_link_watchers_add(
NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting,
link_watcher));
}
/**
* nm_setting_team_port_remove_link_watcher:
* @setting: the #NMSettingTeamPort
* @idx: index number of the link watcher to remove
*
* Removes the link watcher at index #idx.
*
* Since: 1.12
**/
void
nm_setting_team_port_remove_link_watcher(NMSettingTeamPort *setting, guint idx)
{
NMSettingTeamPortPrivate *priv;
g_return_if_fail(NM_IS_SETTING_TEAM_PORT(setting));
priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(setting);
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
g_return_if_fail(idx < priv->team_setting->d.link_watchers->len);
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
_maybe_changed_with_assert(setting,
nm_team_setting_value_link_watchers_remove(priv->team_setting, idx));
}
/**
* nm_setting_team_port_remove_link_watcher_by_value:
* @setting: the #NMSettingTeamPort
* @link_watcher: the link watcher to remove
*
* Removes the link watcher entry matching link_watcher.
*
* Returns: %TRUE if the link watcher was found and removed, %FALSE otherwise.
*
* Since: 1.12
**/
gboolean
nm_setting_team_port_remove_link_watcher_by_value(NMSettingTeamPort *setting,
NMTeamLinkWatcher *link_watcher)
{
g_return_val_if_fail(NM_IS_SETTING_TEAM_PORT(setting), FALSE);
g_return_val_if_fail(link_watcher, FALSE);
return _maybe_changed(setting,
nm_team_setting_value_link_watchers_remove_by_value(
NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting,
link_watcher));
}
/**
* nm_setting_team_port_clear_link_watchers:
* @setting: the #NMSettingTeamPort
*
* Removes all configured link watchers.
*
* Since: 1.12
**/
void
nm_setting_team_port_clear_link_watchers(NMSettingTeamPort *setting)
{
g_return_if_fail(NM_IS_SETTING_TEAM_PORT(setting));
_maybe_changed(setting,
nm_team_setting_value_link_watchers_set_list(
NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting,
NULL,
0));
}
static gboolean
verify(NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(setting);
if (connection) {
NMSettingConnection *s_con;
const char * slave_type;
s_con = nm_connection_get_setting_connection(connection);
if (!s_con) {
g_set_error(error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_MISSING_SETTING,
_("missing setting"));
g_prefix_error(error, "%s: ", NM_SETTING_CONNECTION_SETTING_NAME);
return FALSE;
}
slave_type = nm_setting_connection_get_slave_type(s_con);
if (slave_type && strcmp(slave_type, NM_SETTING_TEAM_SETTING_NAME)) {
g_set_error(error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("A connection with a '%s' setting must have the slave-type set to '%s'. "
"Instead it is '%s'"),
NM_SETTING_TEAM_PORT_SETTING_NAME,
NM_SETTING_TEAM_SETTING_NAME,
slave_type);
g_prefix_error(error,
"%s.%s: ",
NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_SLAVE_TYPE);
return FALSE;
}
}
if (!nm_team_setting_verify(priv->team_setting, error))
return FALSE;
return TRUE;
}
static NMTernary
compare_property(const NMSettInfoSetting *sett_info,
guint property_idx,
NMConnection * con_a,
NMSetting * set_a,
NMConnection * con_b,
NMSetting * set_b,
NMSettingCompareFlags flags)
{
NMSettingTeamPortPrivate *a_priv;
NMSettingTeamPortPrivate *b_priv;
if (nm_streq(sett_info->property_infos[property_idx].name,
NM_SETTING_TEAM_PORT_LINK_WATCHERS)) {
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
return NM_TERNARY_DEFAULT;
if (!set_b)
return TRUE;
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(set_a);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(set_b);
return nm_team_link_watchers_equal(a_priv->team_setting->d.link_watchers,
b_priv->team_setting->d.link_watchers,
TRUE);
}
if (nm_streq(sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_PORT_CONFIG)) {
if (set_b) {
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
/* If we are trying to match a connection in order to assume it (and thus
* @flags contains INFERRABLE), use the "relaxed" matching for team
* configuration. Otherwise, for all other purposes (including connection
* comparison before an update), resort to the default string comparison. */
return TRUE;
}
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(set_a);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(set_b);
return nm_streq0(nm_team_setting_config_get(a_priv->team_setting),
nm_team_setting_config_get(b_priv->team_setting));
}
return TRUE;
}
return NM_SETTING_CLASS(nm_setting_team_port_parent_class)
->compare_property(sett_info, property_idx, con_a, set_a, con_b, set_b, flags);
}
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
static void
duplicate_copy_properties(const NMSettInfoSetting *sett_info, NMSetting *src, NMSetting *dst)
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
{
_maybe_changed(NM_SETTING_TEAM_PORT(dst),
nm_team_setting_reset(NM_SETTING_TEAM_PORT_GET_PRIVATE(dst)->team_setting,
NM_SETTING_TEAM_PORT_GET_PRIVATE(src)->team_setting));
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
}
static gboolean
init_from_dbus(NMSetting * setting,
GHashTable * keys,
GVariant * setting_dict,
GVariant * connection_dict,
guint /* NMSettingParseFlags */ parse_flags,
GError ** error)
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
{
guint32 changed = 0;
gboolean success;
success =
nm_team_setting_reset_from_dbus(NM_SETTING_TEAM_PORT_GET_PRIVATE(setting)->team_setting,
setting_dict,
keys,
&changed,
parse_flags,
error);
_maybe_changed(NM_SETTING_TEAM_PORT(setting), changed);
return success;
libnm: rework team handling of JSON config Completely refactor the team/JSON handling in libnm's NMSettingTeam and NMSettingTeamPort. - team handling was added as rh#1398925. The goal is to have a more convenient way to set properties than constructing JSON. This requires libnm to implement the hard task of parsing JSON (and exposing well-understood properties) and generating JSON (based on these "artificial" properties). But not only libnm. In particular nmcli and the D-Bus API must make this "simpler" API accessible. - since NMSettingTeam and NMSettingTeamPort are conceptually the same, add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to handle the similar code side-by-sdie. The setting classes now just delegate for everything to NMTeamSetting. - Previously, there was a very fuzzy understanding of the provided JSON config. Tighten that up, when setting a JSON config it regenerates/parses all other properties and tries to make the best of it. When modifying any abstraction property, the entire JSON config gets regenerated. In particular, don't try to merge existing JSON config with the new fields. If the user uses the abstraction API, then the entire JSON gets replaced. For example note that nm_setting_team_add_link_watcher() would not be reflected in the JSON config (a bug). That only accidentally worked because client would serializing the changed link watcher to GVariant/D-Bus, then NetworkManager would set it via g_object_set(), which would renerate the JSON, and finally persist it to disk. But as far as libnm is concerned, nm_setting_team_add_link_watcher() would bring the settings instance in an inconsistent state where JSON and the link watcher property disagree. Setting any property must immediately update both the JSON and the abstraction API. - when constucting a team setting from D-Bus, we would previously parse both "config" and abstraction properties. That is wrong. Since our settings plugins only support JSON, all information must be present in the JSON config anyway. So, when "config" is present, only the JSON must be parsed. In the best case, the other information is redudant and contributes nothing. In the worse case, they information differs (which might happen if the client version differs from the server version). As the settings plugin only supports JSON, it's wrong to consider redundant, differing information from D-Bus. - we now only convert string to JSON or back when needed. Previously, setting a property resulted in parsing several JSON multiple times (per property). All operations should now scale well and be reasonably efficient. - also the property-changed signals are now handled correctly. Since NMTeamSetting knows the current state of all attributes, it can emit the exact property changed signals for what changed. - we no longer use libjansson to generate the JSON. JSON is supposed to be a machine readable exchange format, hence a major goal is to be easily handled by applications. While parsing JSON is not so trivial, writing a well-known set of values to JSON is. The advantage is that when you build libnm without libjansson support, then we still can convert the artificial properties to JSON. - Requiring libjansson in libnm is a burden, because most of the time it is not needed (as most users don't create team configurations). With this change we only require it to parse the team settings (no longer to write them). It should be reasonably simple to use a more minimalistic JSON parser that is sufficient for us, so that we can get rid of the libjansson dependency (for libnm). This also avoids the pain that we have due to the symbol collision of libjansson and libjson-glib. https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
}
/*****************************************************************************/
static void
get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
NMSettingTeamPort * setting = NM_SETTING_TEAM_PORT(object);
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(setting);
switch (prop_id) {
case NM_TEAM_ATTRIBUTE_CONFIG:
g_value_set_string(value, nm_team_setting_config_get(priv->team_setting));
break;
case NM_TEAM_ATTRIBUTE_PORT_STICKY:
g_value_set_boolean(value, nm_team_setting_value_get_bool(priv->team_setting, prop_id));
break;
case NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID:
case NM_TEAM_ATTRIBUTE_PORT_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_KEY:
g_value_set_int(value, nm_team_setting_value_get_int32(priv->team_setting, prop_id));
break;
case NM_TEAM_ATTRIBUTE_LINK_WATCHERS:
g_value_take_boxed(value,
_nm_utils_copy_array(priv->team_setting->d.link_watchers,
(NMUtilsCopyFunc) _nm_team_link_watcher_ref,
(GDestroyNotify) nm_team_link_watcher_unref));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
NMSettingTeamPort * setting = NM_SETTING_TEAM_PORT(object);
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(setting);
guint32 changed;
const GPtrArray * v_ptrarr;
switch (prop_id) {
case NM_TEAM_ATTRIBUTE_CONFIG:
changed = nm_team_setting_config_set(priv->team_setting, g_value_get_string(value));
break;
case NM_TEAM_ATTRIBUTE_PORT_STICKY:
changed =
nm_team_setting_value_set_bool(priv->team_setting, prop_id, g_value_get_boolean(value));
break;
case NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID:
case NM_TEAM_ATTRIBUTE_PORT_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_KEY:
changed =
nm_team_setting_value_set_int32(priv->team_setting, prop_id, g_value_get_int(value));
break;
case NM_TEAM_ATTRIBUTE_LINK_WATCHERS:
v_ptrarr = g_value_get_boxed(value);
changed = nm_team_setting_value_link_watchers_set_list(
priv->team_setting,
v_ptrarr ? (const NMTeamLinkWatcher *const *) v_ptrarr->pdata : NULL,
v_ptrarr ? v_ptrarr->len : 0u);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
return;
}
_maybe_changed(setting, changed & ~(((guint32) 1) << prop_id));
}
/*****************************************************************************/
static void
nm_setting_team_port_init(NMSettingTeamPort *setting)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(setting);
priv->team_setting = nm_team_setting_new(TRUE, NULL);
}
/**
* nm_setting_team_port_new:
*
* Creates a new #NMSettingTeamPort object with default values.
*
* Returns: (transfer full): the new empty #NMSettingTeamPort object
**/
NMSetting *
nm_setting_team_port_new(void)
{
return (NMSetting *) g_object_new(NM_TYPE_SETTING_TEAM_PORT, NULL);
}
static void
finalize(GObject *object)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE(object);
nm_team_setting_free(priv->team_setting);
G_OBJECT_CLASS(nm_setting_team_port_parent_class)->finalize(object);
}
static void
nm_setting_team_port_class_init(NMSettingTeamPortClass *klass)
{
GObjectClass * object_class = G_OBJECT_CLASS(klass);
NMSettingClass *setting_class = NM_SETTING_CLASS(klass);
GArray * properties_override = _nm_sett_info_property_override_create_array();
g_type_class_add_private(klass, sizeof(NMSettingTeamPortPrivate));
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->finalize = finalize;
setting_class->compare_property = compare_property;
setting_class->verify = verify;
setting_class->duplicate_copy_properties = duplicate_copy_properties;
setting_class->init_from_dbus = init_from_dbus;
/**
* NMSettingTeamPort:config:
*
* The JSON configuration for the team port. The property should contain raw
* JSON configuration data suitable for teamd, because the value is passed
* directly to teamd. If not specified, the default configuration is
* used. See man teamd.conf for the format details.
**/
/* ---ifcfg-rh---
* property: config
* variable: TEAM_PORT_CONFIG
* description: Team port configuration in JSON. See man teamd.conf for details.
* ---end---
*/
obj_properties[NM_TEAM_ATTRIBUTE_CONFIG] = g_param_spec_string(
NM_SETTING_TEAM_PORT_CONFIG,
"",
"",
NULL,
G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS);
_nm_properties_override_gobj(properties_override,
obj_properties[NM_TEAM_ATTRIBUTE_CONFIG],
&nm_sett_info_propert_type_team_s);
/**
* NMSettingTeamPort:queue-id:
*
* Corresponds to the teamd ports.PORTIFNAME.queue_id.
* When set to -1 means the parameter is skipped from the json config.
*
* Since: 1.12
**/
obj_properties[NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID] =
g_param_spec_int(NM_SETTING_TEAM_PORT_QUEUE_ID,
"",
"",
G_MININT32,
G_MAXINT32,
-1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
_nm_properties_override_gobj(properties_override,
obj_properties[NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID],
&nm_sett_info_propert_type_team_i);
/**
* NMSettingTeamPort:prio:
*
* Corresponds to the teamd ports.PORTIFNAME.prio.
*
* Since: 1.12
**/
obj_properties[NM_TEAM_ATTRIBUTE_PORT_PRIO] =
g_param_spec_int(NM_SETTING_TEAM_PORT_PRIO,
"",
"",
G_MININT32,
G_MAXINT32,
0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
_nm_properties_override_gobj(properties_override,
obj_properties[NM_TEAM_ATTRIBUTE_PORT_PRIO],
&nm_sett_info_propert_type_team_i);
/**
* NMSettingTeamPort:sticky:
*
* Corresponds to the teamd ports.PORTIFNAME.sticky.
*
* Since: 1.12
**/
obj_properties[NM_TEAM_ATTRIBUTE_PORT_STICKY] =
g_param_spec_boolean(NM_SETTING_TEAM_PORT_STICKY,
"",
"",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
_nm_properties_override_gobj(properties_override,
obj_properties[NM_TEAM_ATTRIBUTE_PORT_STICKY],
&nm_sett_info_propert_type_team_b);
/**
* NMSettingTeamPort:lacp-prio:
*
* Corresponds to the teamd ports.PORTIFNAME.lacp_prio.
*
* Since: 1.12
**/
obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO] =
g_param_spec_int(NM_SETTING_TEAM_PORT_LACP_PRIO,
"",
"",
G_MININT32,
G_MAXINT32,
-1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
_nm_properties_override_gobj(properties_override,
obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO],
&nm_sett_info_propert_type_team_i);
/**
* NMSettingTeamPort:lacp-key:
*
* Corresponds to the teamd ports.PORTIFNAME.lacp_key.
*
* Since: 1.12
**/
obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_KEY] =
g_param_spec_int(NM_SETTING_TEAM_PORT_LACP_KEY,
"",
"",
G_MININT32,
G_MAXINT32,
-1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
_nm_properties_override_gobj(properties_override,
obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_KEY],
&nm_sett_info_propert_type_team_i);
/**
* NMSettingTeamPort:link-watchers: (type GPtrArray(NMTeamLinkWatcher))
*
* Link watchers configuration for the connection: each link watcher is
* defined by a dictionary, whose keys depend upon the selected link
* watcher. Available link watchers are 'ethtool', 'nsna_ping' and
* 'arp_ping' and it is specified in the dictionary with the key 'name'.
* Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait';
* nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host';
* arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active',
* 'validate-inactive', 'send-always'. See teamd.conf man for more details.
*
* Since: 1.12
**/
obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS] =
g_param_spec_boxed(NM_SETTING_TEAM_PORT_LINK_WATCHERS,
"",
"",
G_TYPE_PTR_ARRAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
_nm_properties_override_gobj(properties_override,
obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS],
&nm_sett_info_propert_type_team_link_watchers);
g_object_class_install_properties(object_class, G_N_ELEMENTS(obj_properties), obj_properties);
_nm_setting_class_commit_full(setting_class,
NM_META_SETTING_TYPE_TEAM_PORT,
NULL,
properties_override);
}