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
This commit is contained in:
Thomas Haller 2019-05-06 12:36:41 +02:00
parent 539dfbcc42
commit 13f6f3a410
13 changed files with 2726 additions and 1581 deletions

View file

@ -310,7 +310,7 @@
#define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL N_("Corresponds to the teamd mcast_rejoin.interval.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_COUNT N_("Corresponds to the teamd notify_peers.count.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL N_("Corresponds to the teamd notify_peers.interval.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\". When setting the runner, all the properties specific to the runner will be reset to the default value; all the properties specific to other runners will be set to an empty value (or if not possible to a default value).")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\".")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_ACTIVE N_("Corresponds to the teamd runner.active.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY N_("Corresponds to the teamd runner.agg_select_policy.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_FAST_RATE N_("Corresponds to the teamd runner.fast_rate.")

View file

@ -547,19 +547,6 @@ gboolean nm_team_link_watchers_equal (const GPtrArray *a,
const GPtrArray *b,
gboolean ignore_order);
gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, gboolean port);
GValue *_nm_utils_team_config_get (const char *conf,
const char *key,
const char *key2,
const char *key3,
gboolean port_config);
gboolean _nm_utils_team_config_set (char **conf,
const char *key,
const char *key2,
const char *key3,
const GValue *value);
/*****************************************************************************/
guint32 _nm_utils_parse_tc_handle (const char *str,

View file

@ -30,6 +30,7 @@
#include "nm-utils-private.h"
#include "nm-connection-private.h"
#include "nm-setting-connection.h"
#include "nm-team-utils.h"
/**
* SECTION:nm-setting-team-port
@ -41,34 +42,10 @@
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE (NMSettingTeamPort,
PROP_CONFIG,
PROP_QUEUE_ID,
PROP_PRIO,
PROP_STICKY,
PROP_LACP_PRIO,
PROP_LACP_KEY,
PROP_LINK_WATCHERS,
);
static const _NMUtilsTeamPropertyKeys _prop_to_keys[_PROPERTY_ENUMS_LAST] = {
[PROP_CONFIG] = { },
[PROP_QUEUE_ID] = { .key1 = "queue_id", .default_int = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT, },
[PROP_PRIO] = { .key1 = "prio", },
[PROP_STICKY] = { .key1 = "sticky", },
[PROP_LACP_PRIO] = { .key1 = "lacp_prio", .default_int = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT, },
[PROP_LACP_KEY] = { .key1 = "lacp_key", },
[PROP_LINK_WATCHERS] = { .key1 = "link_watch", },
};
static GParamSpec *obj_properties[_NM_TEAM_ATTRIBUTE_PORT_NUM] = { NULL, };
typedef struct {
char *config;
int queue_id;
int prio;
gboolean sticky;
int lacp_prio;
int lacp_key;
GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */
NMTeamSetting *team_setting;
} NMSettingTeamPortPrivate;
G_DEFINE_TYPE (NMSettingTeamPort, nm_setting_team_port, NM_TYPE_SETTING)
@ -77,6 +54,17 @@ G_DEFINE_TYPE (NMSettingTeamPort, nm_setting_team_port, NM_TYPE_SETTING)
/*****************************************************************************/
#define _maybe_changed(self, changed) \
nm_team_setting_maybe_changed (NM_SETTING (_NM_ENSURE_TYPE (NMSettingTeamPort *, self)), (const GParamSpec *const*) obj_properties, (changed))
#define _maybe_changed_with_assert(self, changed) \
G_STMT_START { \
if (!_maybe_changed ((self), (changed))) \
nm_assert_not_reached (); \
} G_STMT_END
/*****************************************************************************/
/**
* nm_setting_team_port_get_config:
* @setting: the #NMSettingTeamPort
@ -88,7 +76,7 @@ nm_setting_team_port_get_config (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), NULL);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->config;
return nm_team_setting_config_get (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting);
}
/**
@ -104,7 +92,7 @@ nm_setting_team_port_get_queue_id (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), -1);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->queue_id;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.queue_id;
}
/**
@ -120,7 +108,7 @@ nm_setting_team_port_get_prio (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->prio;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.prio;
}
/**
@ -136,7 +124,7 @@ nm_setting_team_port_get_sticky (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->sticky;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.sticky;
}
/**
@ -152,7 +140,7 @@ nm_setting_team_port_get_lacp_prio (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->lacp_prio;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.lacp_prio;
}
/**
@ -168,7 +156,7 @@ nm_setting_team_port_get_lacp_key (NMSettingTeamPort *setting)
{
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0);
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->lacp_key;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.port.lacp_key;
}
/**
@ -182,11 +170,9 @@ nm_setting_team_port_get_lacp_key (NMSettingTeamPort *setting)
guint
nm_setting_team_port_get_num_link_watchers (NMSettingTeamPort *setting)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0);
return priv->link_watchers->len;
return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting->d.link_watchers->len;
}
/**
@ -201,12 +187,15 @@ nm_setting_team_port_get_num_link_watchers (NMSettingTeamPort *setting)
NMTeamLinkWatcher *
nm_setting_team_port_get_link_watcher (NMSettingTeamPort *setting, guint idx)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
NMSettingTeamPortPrivate *priv;
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), NULL);
g_return_val_if_fail (idx < priv->link_watchers->len, NULL);
return priv->link_watchers->pdata[idx];
priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
g_return_val_if_fail (idx < priv->team_setting->d.link_watchers->len, NULL);
return priv->team_setting->d.link_watchers->pdata[idx];
}
/**
@ -225,20 +214,12 @@ gboolean
nm_setting_team_port_add_link_watcher (NMSettingTeamPort *setting,
NMTeamLinkWatcher *link_watcher)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
guint i;
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE);
g_return_val_if_fail (link_watcher != NULL, FALSE);
for (i = 0; i < priv->link_watchers->len; i++) {
if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher))
return FALSE;
}
g_ptr_array_add (priv->link_watchers, _nm_team_link_watcher_ref (link_watcher));
_notify (setting, PROP_LINK_WATCHERS);
return TRUE;
return _maybe_changed (setting,
nm_team_setting_value_link_watchers_add (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
link_watcher));
}
/**
@ -253,13 +234,17 @@ nm_setting_team_port_add_link_watcher (NMSettingTeamPort *setting,
void
nm_setting_team_port_remove_link_watcher (NMSettingTeamPort *setting, guint idx)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
NMSettingTeamPortPrivate *priv;
g_return_if_fail (NM_IS_SETTING_TEAM_PORT (setting));
g_return_if_fail (idx < priv->link_watchers->len);
g_ptr_array_remove_index (priv->link_watchers, idx);
_notify (setting, PROP_LINK_WATCHERS);
priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
g_return_if_fail (idx < priv->team_setting->d.link_watchers->len);
_maybe_changed_with_assert (setting,
nm_team_setting_value_link_watchers_remove (priv->team_setting,
idx));
}
/**
@ -277,19 +262,12 @@ gboolean
nm_setting_team_port_remove_link_watcher_by_value (NMSettingTeamPort *setting,
NMTeamLinkWatcher *link_watcher)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
guint i;
g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE);
g_return_val_if_fail (link_watcher, FALSE);
for (i = 0; i < priv->link_watchers->len; i++) {
if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher)) {
g_ptr_array_remove_index (priv->link_watchers, i);
_notify (setting, PROP_LINK_WATCHERS);
return TRUE;
}
}
return FALSE;
return _maybe_changed (setting,
nm_team_setting_value_link_watchers_remove_by_value (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
link_watcher));
}
/**
@ -303,14 +281,12 @@ nm_setting_team_port_remove_link_watcher_by_value (NMSettingTeamPort *setting,
void
nm_setting_team_port_clear_link_watchers (NMSettingTeamPort *setting)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
g_return_if_fail (NM_IS_SETTING_TEAM_PORT (setting));
if (priv->link_watchers->len != 0) {
g_ptr_array_set_size (priv->link_watchers, 0);
_notify (setting, PROP_LINK_WATCHERS);
}
_maybe_changed (setting,
nm_team_setting_value_link_watchers_set_list (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
NULL,
0));
}
static GVariant *
@ -360,29 +336,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
if (priv->config) {
if (strlen (priv->config) > 1*1024*1024) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("team config exceeds size limit"));
g_prefix_error (error,
"%s.%s: ",
NM_SETTING_TEAM_PORT_SETTING_NAME,
NM_SETTING_TEAM_PORT_CONFIG);
return FALSE;
}
if (!nm_utils_is_json_object (priv->config, error)) {
g_prefix_error (error,
"%s.%s: ",
NM_SETTING_TEAM_PORT_SETTING_NAME,
NM_SETTING_TEAM_PORT_CONFIG);
/* We treat an empty string as no config for compatibility. */
return *priv->config ? FALSE : NM_SETTING_VERIFY_NORMALIZABLE;
}
}
/* NOTE: normalizable/normalizable-errors must appear at the end with decreasing severity.
* Take care to properly order statements with priv->config above. */
if (!nm_team_setting_verify (priv->team_setting, error))
return FALSE;
return TRUE;
}
@ -407,27 +362,26 @@ compare_property (const NMSettInfoSetting *sett_info,
return TRUE;
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_a);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_b);
return nm_team_link_watchers_equal (a_priv->link_watchers,
b_priv->link_watchers,
return nm_team_link_watchers_equal (a_priv->team_setting->d.link_watchers,
b_priv->team_setting->d.link_watchers,
TRUE);
}
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_PORT_CONFIG)) {
if (set_b) {
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_a);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_b);
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
/* If we are trying to match a connection in order to assume it (and thus
* @flags contains INFERRABLE), use the "relaxed" matching for team
* configuration. Otherwise, for all other purposes (including connection
* comparison before an update), resort to the default string comparison. */
return _nm_utils_team_config_equal (a_priv->config,
b_priv->config,
TRUE);
return TRUE;
}
return nm_streq0 (a_priv->config, b_priv->config);
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_a);
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (set_b);
return nm_streq0 (nm_team_setting_config_get (a_priv->team_setting),
nm_team_setting_config_get (b_priv->team_setting));
}
return TRUE;
@ -442,6 +396,37 @@ compare_property (const NMSettInfoSetting *sett_info,
flags);
}
static void
duplicate_copy_properties (const NMSettInfoSetting *sett_info,
NMSetting *src,
NMSetting *dst)
{
_maybe_changed (NM_SETTING_TEAM_PORT (dst),
nm_team_setting_reset (NM_SETTING_TEAM_PORT_GET_PRIVATE (dst)->team_setting,
NM_SETTING_TEAM_PORT_GET_PRIVATE (src)->team_setting));
}
static gboolean
init_from_dbus (NMSetting *setting,
GHashTable *keys,
GVariant *setting_dict,
GVariant *connection_dict,
guint /* NMSettingParseFlags */ parse_flags,
GError **error)
{
guint32 changed = 0;
gboolean success;
success = nm_team_setting_reset_from_dbus (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->team_setting,
setting_dict,
keys,
&changed,
parse_flags,
error);
_maybe_changed (NM_SETTING_TEAM_PORT (setting), changed);
return success;
}
/*****************************************************************************/
static void
@ -452,26 +437,25 @@ get_property (GObject *object, guint prop_id,
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
switch (prop_id) {
case PROP_CONFIG:
g_value_set_string (value, nm_setting_team_port_get_config (setting));
case NM_TEAM_ATTRIBUTE_CONFIG:
g_value_set_string (value,
nm_team_setting_config_get (priv->team_setting));
break;
case PROP_QUEUE_ID:
g_value_set_int (value, priv->queue_id);
case NM_TEAM_ATTRIBUTE_PORT_STICKY:
g_value_set_boolean (value,
nm_team_setting_value_get_bool (priv->team_setting,
prop_id));
break;
case PROP_PRIO:
g_value_set_int (value, priv->prio);
case NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID:
case NM_TEAM_ATTRIBUTE_PORT_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_KEY:
g_value_set_int (value,
nm_team_setting_value_get_int32 (priv->team_setting,
prop_id));
break;
case PROP_STICKY:
g_value_set_boolean (value, priv->sticky);
break;
case PROP_LACP_PRIO:
g_value_set_int (value, priv->lacp_prio);
break;
case PROP_LACP_KEY:
g_value_set_int (value, priv->lacp_key);
break;
case PROP_LINK_WATCHERS:
g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers,
case NM_TEAM_ATTRIBUTE_LINK_WATCHERS:
g_value_take_boxed (value, _nm_utils_copy_array (priv->team_setting->d.link_watchers,
(NMUtilsCopyFunc) _nm_team_link_watcher_ref,
(GDestroyNotify) nm_team_link_watcher_unref));
break;
@ -485,81 +469,40 @@ static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (object);
const GValue *align_value = NULL;
gboolean align_config = FALSE;
#define JSON_TO_VAL(typ, id) _nm_utils_json_extract_##typ (priv->config, _prop_to_keys[id], TRUE)
NMSettingTeamPort *setting = NM_SETTING_TEAM_PORT (object);
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
guint32 changed;
const GPtrArray *v_ptrarr;
switch (prop_id) {
case PROP_CONFIG:
g_free (priv->config);
priv->config = g_value_dup_string (value);
priv->queue_id = JSON_TO_VAL (int, PROP_QUEUE_ID);
priv->prio = JSON_TO_VAL (int, PROP_PRIO);
priv->sticky = JSON_TO_VAL (boolean, PROP_STICKY);
priv->lacp_prio = JSON_TO_VAL (int, PROP_LACP_PRIO);
priv->lacp_key = JSON_TO_VAL (int, PROP_LACP_KEY);
g_ptr_array_unref (priv->link_watchers);
priv->link_watchers = JSON_TO_VAL (ptr_array, PROP_LINK_WATCHERS);
case NM_TEAM_ATTRIBUTE_CONFIG:
changed = nm_team_setting_config_set (priv->team_setting, g_value_get_string (value));
break;
case PROP_QUEUE_ID:
if (priv->queue_id == g_value_get_int (value))
break;
priv->queue_id = g_value_get_int (value);
if (priv->queue_id != NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT)
align_value = value;
align_config = TRUE;
case NM_TEAM_ATTRIBUTE_PORT_STICKY:
changed = nm_team_setting_value_set_bool (priv->team_setting,
prop_id,
g_value_get_boolean (value));
break;
case PROP_PRIO:
if (priv->prio == g_value_get_int (value))
break;
priv->prio = g_value_get_int (value);
if (priv->prio)
align_value = value;
align_config = TRUE;
case NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID:
case NM_TEAM_ATTRIBUTE_PORT_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO:
case NM_TEAM_ATTRIBUTE_PORT_LACP_KEY:
changed = nm_team_setting_value_set_int32 (priv->team_setting,
prop_id,
g_value_get_int (value));
break;
case PROP_STICKY:
if (priv->sticky == g_value_get_boolean (value))
break;
priv->sticky = g_value_get_boolean (value);
if (priv->sticky)
align_value = value;
align_config = TRUE;
break;
case PROP_LACP_PRIO:
if (priv->lacp_prio == g_value_get_int (value))
break;
priv->lacp_prio = g_value_get_int (value);
/* from libteam sources: lacp_prio default value is 0xff */
if (priv->lacp_prio != NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT)
align_value = value;
align_config = TRUE;
break;
case PROP_LACP_KEY:
if (priv->lacp_key == g_value_get_int (value))
break;
priv->lacp_key = g_value_get_int (value);
if (priv->lacp_key)
align_value = value;
align_config = TRUE;
break;
case PROP_LINK_WATCHERS:
g_ptr_array_unref (priv->link_watchers);
priv->link_watchers = _nm_utils_copy_array (g_value_get_boxed (value),
(NMUtilsCopyFunc) _nm_team_link_watcher_ref,
(GDestroyNotify) nm_team_link_watcher_unref);
if (priv->link_watchers->len)
align_value = value;
align_config = TRUE;
case NM_TEAM_ATTRIBUTE_LINK_WATCHERS:
v_ptrarr = g_value_get_boxed (value);
changed = nm_team_setting_value_link_watchers_set_list (priv->team_setting,
v_ptrarr ? (const NMTeamLinkWatcher *const*) v_ptrarr->pdata : NULL,
v_ptrarr ? v_ptrarr->len : 0u);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
return;
}
if (align_config)
_nm_utils_json_append_gvalue (&priv->config, _prop_to_keys[prop_id], align_value);
_maybe_changed (setting, changed & ~(((guint32) 1) << prop_id));
}
/*****************************************************************************/
@ -569,9 +512,7 @@ nm_setting_team_port_init (NMSettingTeamPort *setting)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
priv->queue_id = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT;
priv->lacp_prio = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT;
priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
priv->team_setting = nm_team_setting_new (TRUE, NULL);
}
/**
@ -592,8 +533,7 @@ finalize (GObject *object)
{
NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (object);
g_free (priv->config);
g_ptr_array_unref (priv->link_watchers);
nm_team_setting_free (priv->team_setting);
G_OBJECT_CLASS (nm_setting_team_port_parent_class)->finalize (object);
}
@ -611,8 +551,10 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
object_class->set_property = set_property;
object_class->finalize = finalize;
setting_class->compare_property = compare_property;
setting_class->verify = verify;
setting_class->compare_property = compare_property;
setting_class->verify = verify;
setting_class->duplicate_copy_properties = duplicate_copy_properties;
setting_class->init_from_dbus = init_from_dbus;
/**
* NMSettingTeamPort:config:
@ -628,7 +570,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
* description: Team port configuration in JSON. See man teamd.conf for details.
* ---end---
*/
obj_properties[PROP_CONFIG] =
obj_properties[NM_TEAM_ATTRIBUTE_CONFIG] =
g_param_spec_string (NM_SETTING_TEAM_PORT_CONFIG, "", "",
NULL,
G_PARAM_READWRITE |
@ -643,7 +585,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_QUEUE_ID] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID] =
g_param_spec_int (NM_SETTING_TEAM_PORT_QUEUE_ID, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@ -656,7 +598,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_PRIO] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_PRIO] =
g_param_spec_int (NM_SETTING_TEAM_PORT_PRIO, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@ -669,7 +611,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_STICKY] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_STICKY] =
g_param_spec_boolean (NM_SETTING_TEAM_PORT_STICKY, "", "",
FALSE,
G_PARAM_READWRITE |
@ -682,7 +624,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_LACP_PRIO] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO] =
g_param_spec_int (NM_SETTING_TEAM_PORT_LACP_PRIO, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@ -695,7 +637,7 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_LACP_KEY] =
obj_properties[NM_TEAM_ATTRIBUTE_PORT_LACP_KEY] =
g_param_spec_int (NM_SETTING_TEAM_PORT_LACP_KEY, "", "",
G_MININT32, G_MAXINT32, 0,
G_PARAM_READWRITE |
@ -715,19 +657,19 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
*
* Since: 1.12
**/
obj_properties[PROP_LINK_WATCHERS] =
obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS] =
g_param_spec_boxed (NM_SETTING_TEAM_PORT_LINK_WATCHERS, "", "",
G_TYPE_PTR_ARRAY,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
_properties_override_add_transform (properties_override,
obj_properties[PROP_LINK_WATCHERS],
obj_properties[NM_TEAM_ATTRIBUTE_LINK_WATCHERS],
G_VARIANT_TYPE ("aa{sv}"),
team_link_watchers_to_dbus,
team_link_watchers_from_dbus);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_properties), obj_properties);
_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_TEAM_PORT,
NULL, properties_override);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -24,4 +24,250 @@
#error Cannot use this header.
#endif
#include "nm-glib-aux/nm-value-type.h"
struct _NMSetting;
struct NMTeamLinkWatcher;
typedef enum {
_NM_TEAM_ATTRIBUTE_0 = 0,
NM_TEAM_ATTRIBUTE_CONFIG = 1,
NM_TEAM_ATTRIBUTE_LINK_WATCHERS = 2,
_NM_TEAM_ATTRIBUTE_START = 3,
NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT = _NM_TEAM_ATTRIBUTE_START,
NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL,
NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT,
NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS,
NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY,
_NM_TEAM_ATTRIBUTE_MASTER_NUM,
NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID = _NM_TEAM_ATTRIBUTE_START,
NM_TEAM_ATTRIBUTE_PORT_PRIO,
NM_TEAM_ATTRIBUTE_PORT_STICKY,
NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO,
NM_TEAM_ATTRIBUTE_PORT_LACP_KEY,
_NM_TEAM_ATTRIBUTE_PORT_NUM,
_NM_TEAM_ATTRIBUTE_NUM = NM_CONST_MAX (_NM_TEAM_ATTRIBUTE_MASTER_NUM, _NM_TEAM_ATTRIBUTE_PORT_NUM),
} NMTeamAttribute;
static inline guint32
nm_team_attribute_to_flags (NMTeamAttribute team_attr)
{
nm_assert (_NM_INT_NOT_NEGATIVE (team_attr));
nm_assert (team_attr < _NM_TEAM_ATTRIBUTE_NUM);
G_STATIC_ASSERT_EXPR (_NM_TEAM_ATTRIBUTE_NUM < 32);
return ((guint32) 1) << team_attr;
}
struct _NMTeamSettingData {
const char *_js_str;
const GPtrArray *link_watchers;
/* this means that @_js_str is unset and needs to be created by
* converting the properties to JSON. This flag indicates that
* we need to re-generate the JSON string on-demand (lazily). */
bool _js_str_need_synthetize;
bool strict_validated:1;
/* indicates tha the JSON is invalid. Usually, we do a very relaxed validation of
* the JSON config, in case !@strict_validated and accept all unknown fields. This
* flag indicates that the JSON value is not even parsable as JSON. nm_connection_verify()
* would reject such a setting. */
bool js_str_invalid:1;
bool is_port:1;
union {
struct {
const GPtrArray *runner_tx_hash;
const char *runner;
const char *runner_hwaddr_policy;
const char *runner_tx_balancer;
const char *runner_agg_select_policy;
gint32 notify_peers_count;
gint32 notify_peers_interval;
gint32 mcast_rejoin_count;
gint32 mcast_rejoin_interval;
gint32 runner_sys_prio;
gint32 runner_min_ports;
gint32 runner_tx_balancer_interval;
bool runner_active;
bool runner_fast_rate;
} master;
struct {
gint32 queue_id;
gint32 prio;
gint32 lacp_prio;
gint32 lacp_key;
bool sticky;
} port;
};
};
/*****************************************************************************/
typedef struct {
union {
const struct _NMTeamSettingData d;
struct _NMTeamSettingData _data_priv;
};
} NMTeamSetting;
NMTeamSetting *nm_team_setting_new (gboolean is_port,
const char *js_str);
void nm_team_setting_free (NMTeamSetting *self);
NM_AUTO_DEFINE_FCN0 (NMTeamSetting *, _nm_auto_free_team_setting, nm_team_setting_free)
#define nm_auto_free_team_setting nm_auto (_nm_auto_free_team_setting)
/*****************************************************************************/
const char *nm_team_setting_config_get (const NMTeamSetting *self);
guint32 nm_team_setting_config_set (NMTeamSetting *self, const char *js_str);
/*****************************************************************************/
gconstpointer _nm_team_setting_value_get (const NMTeamSetting *self,
NMTeamAttribute team_attr,
NMValueType value_type);
static inline gboolean
nm_team_setting_value_get_bool (const NMTeamSetting *self,
NMTeamAttribute team_attr)
{
const bool *p;
p = _nm_team_setting_value_get (self, team_attr, NM_VALUE_TYPE_BOOL);
return p ? *p : 0;
}
static inline gint32
nm_team_setting_value_get_int32 (const NMTeamSetting *self,
NMTeamAttribute team_attr)
{
const gint32 *p;
p = _nm_team_setting_value_get (self, team_attr, NM_VALUE_TYPE_INT32);
return p ? *p : 0;
}
static inline const char *
nm_team_setting_value_get_string (const NMTeamSetting *self,
NMTeamAttribute team_attr)
{
const char *const*p;
p = _nm_team_setting_value_get (self, team_attr, NM_VALUE_TYPE_STRING);
return p ? *p : NULL;
}
/*****************************************************************************/
guint32 _nm_team_setting_value_set (NMTeamSetting *self,
NMTeamAttribute team_attr,
NMValueType value_type,
gconstpointer val);
static inline guint32
nm_team_setting_value_set_bool (NMTeamSetting *self,
NMTeamAttribute team_attr,
gboolean val)
{
const bool bool_val = val;
return _nm_team_setting_value_set (self, team_attr, NM_VALUE_TYPE_BOOL, &bool_val);
}
static inline guint32
nm_team_setting_value_set_int32 (NMTeamSetting *self,
NMTeamAttribute team_attr,
gint32 val)
{
return _nm_team_setting_value_set (self, team_attr, NM_VALUE_TYPE_INT32, &val);
}
static inline guint32
nm_team_setting_value_set_string (NMTeamSetting *self,
NMTeamAttribute team_attr,
const char *arg)
{
return _nm_team_setting_value_set (self, team_attr, NM_VALUE_TYPE_STRING, &arg);
}
/*****************************************************************************/
guint32 nm_team_setting_value_link_watchers_add (NMTeamSetting *self,
const struct NMTeamLinkWatcher *link_watcher);
guint32 nm_team_setting_value_link_watchers_remove (NMTeamSetting *self,
guint idx);
guint32 nm_team_setting_value_link_watchers_remove_by_value (NMTeamSetting *self,
const struct NMTeamLinkWatcher *link_watcher);
guint32 nm_team_setting_value_link_watchers_set_list (NMTeamSetting *self,
const struct NMTeamLinkWatcher *const*arr,
guint len);
/*****************************************************************************/
guint32 nm_team_setting_value_master_runner_tx_hash_add (NMTeamSetting *self,
const char *txhash);
guint32 nm_team_setting_value_master_runner_tx_hash_remove (NMTeamSetting *self,
guint idx);
guint32 nm_team_setting_value_master_runner_tx_hash_set_list (NMTeamSetting *self,
const char *const*arr,
guint len);
/*****************************************************************************/
gboolean nm_team_setting_verify (const NMTeamSetting *self,
GError **error);
/*****************************************************************************/
int nm_team_setting_cmp (const NMTeamSetting *self_a,
const NMTeamSetting *self_b,
gboolean ignore_js_str);
guint32 nm_team_setting_reset (NMTeamSetting *self,
const NMTeamSetting *src);
gboolean nm_team_setting_reset_from_dbus (NMTeamSetting *self,
GVariant *setting_dict,
GHashTable *keys,
guint32 *out_changed,
guint /* NMSettingParseFlags */ parse_flags,
GError **error);
/*****************************************************************************/
gboolean nm_team_setting_maybe_changed (struct _NMSetting *source,
const GParamSpec *const*obj_properties,
guint32 changed);
#endif /* __NM_TEAM_UITLS_H__ */

View file

@ -131,116 +131,4 @@ gboolean _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
const char *setting,
const char *property);
/* JSON to GValue conversion macros */
static inline void
_nm_auto_unset_and_free_gvalue (GValue **ptr)
{
if (*ptr) {
g_value_unset (*ptr);
g_free (*ptr);
}
}
#define nm_auto_unset_and_free_gvalue nm_auto(_nm_auto_unset_and_free_gvalue)
typedef struct {
const char *key1;
const char *key2;
const char *key3;
union {
int default_int;
gboolean default_bool;
const char *default_str;
};
} _NMUtilsTeamPropertyKeys;
static inline int
_nm_utils_json_extract_int (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_VALUE_HOLDS_INT (t_value))
return key.default_int;
return g_value_get_int (t_value);
}
static inline gboolean
_nm_utils_json_extract_boolean (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_VALUE_HOLDS_BOOLEAN (t_value))
return key.default_bool;
return g_value_get_boolean (t_value);
}
static inline char *
_nm_utils_json_extract_string (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_VALUE_HOLDS_STRING (t_value))
return g_strdup (key.default_str);
return g_value_dup_string (t_value);
}
static inline char **
_nm_utils_json_extract_strv (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_TYPE_CHECK_VALUE_TYPE (t_value, G_TYPE_STRV))
return NULL;
return g_strdupv (g_value_get_boxed (t_value))
?: g_new0 (char *, 1);
}
static inline GPtrArray *
_nm_utils_json_extract_ptr_array (char *conf,
_NMUtilsTeamPropertyKeys key,
gboolean is_port)
{
nm_auto_unset_and_free_gvalue GValue *t_value = NULL;
GPtrArray *data, *ret;
guint i;
ret = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port);
if ( !t_value
|| !G_TYPE_CHECK_VALUE_TYPE (t_value, G_TYPE_PTR_ARRAY))
return ret;
data = g_value_get_boxed (t_value);
if (!data)
return ret;
for (i = 0; i < data->len; i++)
g_ptr_array_add (ret, _nm_team_link_watcher_ref (data->pdata[i]));
return ret;
}
static inline void
_nm_utils_json_append_gvalue (char **conf,
_NMUtilsTeamPropertyKeys key,
const GValue *val)
{
_nm_utils_team_config_set (conf, key.key1, key.key2, key.key3, val);
}
#endif

View file

@ -5378,429 +5378,6 @@ _nm_utils_is_json_object_no_validation (const char *str, GError **error)
return FALSE;
}
#if WITH_JSON_VALIDATION
static void
_json_add_object (json_t *json,
const char *key1,
const char *key2,
const char *key3,
json_t *value)
{
json_t *json_element, *json_link;
json_element = json_object_get (json, key1);
if (!json_element) {
json_element = value;
if (key2) {
if (key3) {
json_element = json_object ();
json_object_set_new (json_element, key3, value);
}
json_link = json_object ();
json_object_set_new (json_link, key2, json_element);
json_element = json_link;
}
json_object_set_new (json, key1, json_element);
return;
}
if (!key2)
goto key_already_there;
json_link = json_element;
json_element = json_object_get (json_element, key2);
if (!json_element) {
json_element = value;
if (key3) {
json_element = json_object ();
json_object_set_new (json_element, key3, value);
}
json_object_set_new (json_link, key2, json_element);
return;
}
if (!key3)
goto key_already_there;
json_link = json_element;
json_element = json_object_get (json_element, key3);
if (!json_element) {
json_object_set_new (json_link, key3, value);
return;
}
key_already_there:
json_decref (value);
}
/*
* Removes the specified key1[.key2.key3] from json.
* Returns TRUE if json has been modified, FALSE otherwise. */
static gboolean
_json_del_object (json_t *json,
const char *key1,
const char *key2,
const char *key3)
{
json_t *json_element = json;
json_t *json_link = NULL;
const char *iter_key = key1;
if (key2) {
json_link = json;
json_element = json_object_get (json, key1);
if (!json_element)
return FALSE;
iter_key = key2;
}
if (key3) {
json_link = json_element;
json_element = json_object_get (json_element, key2);
if (!json_element)
return FALSE;
iter_key = key3;
}
if (json_object_del (json_element, iter_key) != 0)
return FALSE;
/* 1st level key only */
if (!json_link)
return TRUE;
if (json_object_size (json_element) == 0)
json_object_del (json_link, (key3 ? key2 : key1));
if (key3 && json_object_size (json_link) == 0)
json_object_del (json, key1);
return TRUE;
}
/* Adds in place to json the defaults for missing properties;
* the "add_implicit" allows to add to the json also the default
* values used but not shown with teamdctl */
static void
_json_team_add_defaults (json_t *json,
gboolean port_config,
gboolean add_implicit)
{
json_t *json_element;
const char *runner = NULL;
if (port_config) {
_json_add_object (json, "link_watch", "name", NULL,
json_string (NM_TEAM_LINK_WATCHER_ETHTOOL));
return;
}
/* Retrieve runner or add default one */
json_element = json_object_get (json, "runner");
if (json_element) {
runner = json_string_value (json_object_get (json_element, "name"));
} else {
json_element = json_object ();
json_object_set_new (json, "runner", json_element);
}
if (!runner) {
runner = NM_SETTING_TEAM_RUNNER_DEFAULT;
json_object_set_new (json_element, "name", json_string (runner));
}
if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) {
_json_add_object (json, "notify_peers", "count", NULL,
json_integer (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT));
_json_add_object (json, "mcast_rejoin", "count", NULL,
json_integer (NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT));
} else if ( nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE)
|| nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) {
json_element = json_array ();
json_array_append_new (json_element, json_string ("eth"));
json_array_append_new (json_element, json_string ("ipv4"));
json_array_append_new (json_element, json_string ("ipv6"));
_json_add_object (json, "runner", "tx_hash", NULL, json_element);
}
if (!add_implicit)
return;
if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP))
_json_add_object (json, "runner", "hwaddr_policy", NULL, json_string ("same_all"));
else if (NM_IN_STRSET (runner,
NM_SETTING_TEAM_RUNNER_LOADBALANCE,
NM_SETTING_TEAM_RUNNER_LACP)) {
_json_add_object (json, "runner", "tx_balancer", "balancing_interval",
json_integer (NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT));
if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) {
_json_add_object (json, "runner", "active", NULL, json_boolean (TRUE));
_json_add_object (json, "runner", "sys_prio", NULL,
json_integer (NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT));
_json_add_object (json, "runner", "min_ports", NULL, json_integer (0));
_json_add_object (json, "runner", "agg_select_policy", NULL,
json_string (NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT));
}
}
}
static json_t *
_json_find_object (json_t *json,
const char *key1,
const char *key2,
const char *key3)
{
json_t *json_element;
if (!key1)
return NULL;
json_element = json_object_get (json, key1);
if (!key2 || !json_element)
return json_element;
json_element = json_object_get (json_element, key2);
if (!key3 || !json_element)
return json_element;
json_element = json_object_get (json_element, key3);
return json_element;
}
static void
_json_delete_object_on_int_match (json_t *json,
const char *key1,
const char *key2,
const char *key3,
int val)
{
json_t *json_element;
json_element = _json_find_object (json, key1, key2, key3);
if (!json_element || !json_is_integer (json_element))
return;
if (json_integer_value (json_element) == val)
_json_del_object (json, key1, key2, key3);
}
static void
_json_delete_object_on_bool_match (json_t *json,
const char *key1,
const char *key2,
const char *key3,
gboolean val)
{
json_t *json_element;
json_element = _json_find_object (json, key1, key2, key3);
if (!json_element || !json_is_boolean (json_element))
return;
if (json_boolean_value (json_element) == val)
_json_del_object (json, key1, key2, key3);
}
static void
_json_delete_object_on_string_match (json_t *json,
const char *key1,
const char *key2,
const char *key3,
const char *val)
{
json_t *json_element;
json_element = _json_find_object (json, key1, key2, key3);
if (!json_element || !json_is_string (json_element))
return;
if (nm_streq0 (json_string_value (json_element), val))
_json_del_object (json, key1, key2, key3);
}
static void
_json_team_normalize_defaults (json_t *json, gboolean reset)
{
json_t *json_element;
const char *runner = NM_SETTING_TEAM_RUNNER_DEFAULT;
gs_free char *runner_free = NULL;
int notify_peers_count = 0, notify_peers_interval = 0;
int mcast_rejoin_count = 0, mcast_rejoin_interval = 0;
int runner_tx_balancer_interval = -1;
gboolean runner_active = FALSE, runner_fast_rate = FALSE;
int runner_sys_prio = -1, runner_min_ports = -1;
json_element = _json_find_object (json, "runner", "name", NULL);
if (json_element) {
runner_free = g_strdup (json_string_value (json_element));
runner = runner_free;
_json_delete_object_on_string_match (json, "runner", "name", NULL,
NM_SETTING_TEAM_RUNNER_DEFAULT);
}
/* the runner changed: clear all the properties. Then team.config will be saved
* and reloaded triggering the reset of the values through _nm_utils_team_config_get
*/
if (reset) {
_json_del_object (json, "notify_peers", "count", NULL);
_json_del_object (json, "notify_peers", "interval", NULL);
_json_del_object (json, "mcast_rejoin", "count", NULL);
_json_del_object (json, "mcast_rejoin", "interval", NULL);
_json_del_object (json, "runner", "hwaddr_policy", NULL);
_json_del_object (json, "runner", "tx_hash", NULL);
_json_del_object (json, "runner", "tx_balancer", "name");
_json_del_object (json, "runner", "tx_balancer", "balancing_interval");
_json_del_object (json, "runner", "active", NULL);
_json_del_object (json, "runner", "fast_rate", NULL);
_json_del_object (json, "runner", "sys_prio", NULL);
_json_del_object (json, "runner", "min_ports", NULL);
_json_del_object (json, "runner", "agg_select_policy", NULL);
return;
}
if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) {
notify_peers_count = 1;
mcast_rejoin_count = 1;
_json_delete_object_on_string_match (json, "runner", "hwaddr_policy", NULL,
NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_DEFAULT);
} else if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) {
runner_tx_balancer_interval = NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT;
runner_active = TRUE;
runner_sys_prio = NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT;
runner_min_ports = 0;
_json_delete_object_on_string_match (json, "runner", "agg_select_policy", NULL,
NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT);
} else if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE))
runner_tx_balancer_interval = 50;
_json_delete_object_on_int_match (json, "notify_peers", "count", NULL, notify_peers_count);
_json_delete_object_on_int_match (json, "notify_peers", "interval", NULL, notify_peers_interval);
_json_delete_object_on_int_match (json, "mcast_rejoin", "count", NULL, mcast_rejoin_count);
_json_delete_object_on_int_match (json, "macst_rejoin", "interval", NULL, mcast_rejoin_interval);
_json_delete_object_on_int_match (json, "runner", "tx_balancer", "balancing_interval",
runner_tx_balancer_interval);
_json_delete_object_on_int_match (json, "runner", "sys_prio", NULL, runner_sys_prio);
_json_delete_object_on_int_match (json, "runner", "min_ports", NULL, runner_min_ports);
_json_delete_object_on_bool_match (json, "runner", "active", NULL, runner_active);
_json_delete_object_on_bool_match (json, "runner", "active", NULL, runner_active);
_json_delete_object_on_bool_match (json, "runner", "fast_rate", NULL, runner_fast_rate);
}
static NMTeamLinkWatcher *
_nm_utils_team_link_watcher_from_json (json_t *json_element)
{
const char *j_key;
json_t *j_val;
gs_free char *name = NULL, *target_host = NULL, *source_host = NULL;
int val1 = 0, val2 = 0, val3 = 3, val4 = -1;
NMTeamLinkWatcherArpPingFlags flags = 0;
g_return_val_if_fail (json_element, NULL);
json_object_foreach (json_element, j_key, j_val) {
if (nm_streq (j_key, "name")) {
g_free (name);
name = strdup (json_string_value (j_val));
} else if (nm_streq (j_key, "target_host")) {
g_free (target_host);
target_host = strdup (json_string_value (j_val));
} else if (nm_streq (j_key, "source_host")) {
g_free (source_host);
source_host = strdup (json_string_value (j_val));
} else if (NM_IN_STRSET (j_key, "delay_up", "init_wait"))
val1 = json_integer_value (j_val);
else if (NM_IN_STRSET (j_key, "delay_down", "interval"))
val2 = json_integer_value (j_val);
else if (nm_streq (j_key, "missed_max"))
val3 = json_integer_value (j_val);
else if (nm_streq (j_key, "vlanid"))
val4 = json_integer_value (j_val);
else if (nm_streq (j_key, "validate_active")) {
if (json_is_true (j_val))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
} else if (nm_streq (j_key, "validate_inactive")) {
if (json_is_true (j_val))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE;
} else if (nm_streq (j_key, "send_always")) {
if (json_is_true (j_val))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
}
}
if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ETHTOOL))
return nm_team_link_watcher_new_ethtool (val1, val2, NULL);
else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, NULL);
else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
return nm_team_link_watcher_new_arp_ping2 (val1, val2, val3, val4, target_host,
source_host, flags, NULL);
} else
return NULL;
}
static json_t *
_nm_utils_team_link_watcher_to_json (NMTeamLinkWatcher *watcher)
{
const char *name;
int int_val;
const char *str_val;
NMTeamLinkWatcherArpPingFlags flags = 0;
json_t *json_element;
g_return_val_if_fail (watcher, NULL);
json_element = json_object ();
name = nm_team_link_watcher_get_name (watcher);
if (!name)
goto fail;
json_object_set_new (json_element, "name", json_string (name));
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
int_val = nm_team_link_watcher_get_delay_up (watcher);
if (int_val)
json_object_set_new (json_element, "delay_up", json_integer (int_val));
int_val = nm_team_link_watcher_get_delay_down (watcher);
if (int_val)
json_object_set_new (json_element, "delay_down", json_integer (int_val));
return json_element;
}
int_val = nm_team_link_watcher_get_init_wait (watcher);
if (int_val)
json_object_set_new (json_element, "init_wait", json_integer (int_val));
int_val = nm_team_link_watcher_get_interval (watcher);
if (int_val)
json_object_set_new (json_element, "interval", json_integer (int_val));
int_val = nm_team_link_watcher_get_missed_max (watcher);
if (int_val != 3)
json_object_set_new (json_element, "missed_max", json_integer (int_val));
str_val = nm_team_link_watcher_get_target_host (watcher);
if (!str_val)
goto fail;
json_object_set_new (json_element, "target_host", json_string (str_val));
if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
return json_element;
int_val = nm_team_link_watcher_get_vlanid (watcher);
if (int_val != -1)
json_object_set_new (json_element, "vlanid", json_integer (int_val));
str_val = nm_team_link_watcher_get_source_host (watcher);
if (!str_val)
goto fail;
json_object_set_new (json_element, "source_host", json_string (str_val));
flags = nm_team_link_watcher_get_flags (watcher);
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE)
json_object_set_new (json_element, "validate_active", json_string ("true"));
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE)
json_object_set_new (json_element, "validate_inactive", json_string ("true"));
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS)
json_object_set_new (json_element, "send_always", json_string ("true"));
return json_element;
fail:
json_decref (json_element);
return NULL;
}
/**
* nm_utils_is_json_object:
* @str: the JSON string to test
@ -5816,6 +5393,7 @@ fail:
gboolean
nm_utils_is_json_object (const char *str, GError **error)
{
#if WITH_JSON_VALIDATION
json_t *json;
json_error_t jerror;
@ -5855,305 +5433,7 @@ nm_utils_is_json_object (const char *str, GError **error)
json_decref (json);
return TRUE;
}
gboolean
_nm_utils_team_config_equal (const char *conf1,
const char *conf2,
gboolean port_config)
{
json_t *json1 = NULL, *json2 = NULL, *json;
gs_free char *dump1 = NULL, *dump2 = NULL;
json_t *value;
json_error_t jerror;
const char *key;
gboolean ret;
void *tmp;
int i;
if (nm_streq0 (conf1, conf2))
return TRUE;
else if (!nm_jansson_load ())
return FALSE;
/* A NULL configuration is equivalent to default value '{}' */
json1 = json_loads (conf1 ?: "{}", JSON_REJECT_DUPLICATES, &jerror);
if (json1)
json2 = json_loads (conf2 ?: "{}", JSON_REJECT_DUPLICATES, &jerror);
if (!json1 || !json2) {
ret = FALSE;
goto out;
}
/* Some properties are added by teamd when missing from the initial
* configuration. Add them with the default value if necessary, depending
* on the configuration type.
*/
for (i = 0, json = json1; i < 2; i++, json = json2)
_json_team_add_defaults (json, port_config, FALSE);
/* Only consider a given subset of nodes, others can change depending on
* current state */
for (i = 0, json = json1; i < 2; i++, json = json2) {
json_object_foreach_safe (json, tmp, key, value) {
if (!NM_IN_STRSET (key, "runner", "link_watch"))
json_object_del (json, key);
}
}
dump1 = json_dumps (json1, JSON_INDENT(0) | JSON_ENSURE_ASCII | JSON_SORT_KEYS);
dump2 = json_dumps (json2, JSON_INDENT(0) | JSON_ENSURE_ASCII | JSON_SORT_KEYS);
ret = nm_streq0 (dump1, dump2);
out:
if (json1)
json_decref (json1);
if (json2)
json_decref (json2);
return ret;
}
GValue *
_nm_utils_team_config_get (const char *conf,
const char *key,
const char *key2,
const char *key3,
gboolean port_config)
{
json_t *json;
json_t *json_element;
GValue *value = NULL;
json_error_t jerror;
if (!key)
return NULL;
if (!nm_jansson_load ())
return NULL;
json = json_loads (conf ?: "{}", JSON_REJECT_DUPLICATES, &jerror);
/* Invalid json in conf */
if (!json)
return NULL;
/* Some properties are added by teamd when missing from the initial
* configuration. Add them with the default value if necessary, depending
* on the configuration type.
* Skip this for port config, as some properties change on the basis of the
* runner specified in the master connection... but we don't want to check
* against properties in another connection. Moreover, for team-port we have
* the link-watchers property only here: and for this compound property it is
* fine to show the default value only if explicitly set.
*/
if (!port_config)
_json_team_add_defaults (json, port_config, TRUE);
/* Now search the property to retrieve */
json_element = json_object_get (json, key);
if (json_element && key2)
json_element = json_object_get (json_element, key2);
if (json_element && key3)
json_element = json_object_get (json_element, key3);
if (json_element) {
value = g_new0 (GValue, 1);
if (json_is_string (json_element)) {
g_value_init (value, G_TYPE_STRING);
g_value_set_string (value, json_string_value (json_element));
} else if (json_is_integer (json_element)) {
g_value_init (value, G_TYPE_INT);
g_value_set_int (value, json_integer_value (json_element));
} else if (json_is_boolean (json_element)) {
g_value_init (value, G_TYPE_BOOLEAN);
g_value_set_boolean (value, json_boolean_value (json_element));
} else if (nm_streq (key, "link_watch")) {
NMTeamLinkWatcher *watcher;
GPtrArray *data = g_ptr_array_new_with_free_func
((GDestroyNotify) nm_team_link_watcher_unref);
if (json_is_array (json_element)) {
json_t *j_watcher;
int index;
json_array_foreach (json_element, index, j_watcher) {
watcher = _nm_utils_team_link_watcher_from_json (j_watcher);
if (watcher)
g_ptr_array_add (data, watcher);
}
} else {
watcher = _nm_utils_team_link_watcher_from_json (json_element);
if (watcher)
g_ptr_array_add (data, watcher);
}
if (data->len) {
g_value_init (value, G_TYPE_PTR_ARRAY);
g_value_take_boxed (value, data);
} else
g_ptr_array_free (data, TRUE);
} else if (json_is_array (json_element)) {
GPtrArray *data = g_ptr_array_new_with_free_func (g_free);
json_t *str_element;
int index;
json_array_foreach (json_element, index, str_element) {
if (json_is_string (str_element))
g_ptr_array_add (data, g_strdup (json_string_value (str_element)));
}
g_ptr_array_add (data, NULL);
g_value_init (value, G_TYPE_STRV);
g_value_take_boxed (value, g_ptr_array_free (data, FALSE));
} else {
g_assert_not_reached ();
g_free (value);
value = NULL;
}
}
if (json)
json_decref (json);
return value;
}
/* if conf is updated in place returns TRUE */
gboolean
_nm_utils_team_config_set (char **conf,
const char *key,
const char *key2,
const char *key3,
const GValue *value)
{
nm_auto_decref_json json_t *json = NULL;
nm_auto_decref_json json_t *json_value = NULL;
json_t *json_element;
json_t *json_link;
json_error_t jerror;
const char *iter_key = key;
gs_free char *conf_new = NULL;
g_return_val_if_fail (key, FALSE);
if (!nm_jansson_load ())
return FALSE;
json = json_loads (*conf?: "{}", JSON_REJECT_DUPLICATES, &jerror);
if (!json)
return FALSE;
if (!value) {
if (!_json_del_object (json, key, key2, key3))
return FALSE;
goto done;
}
if (G_VALUE_HOLDS_STRING (value))
json_value = json_string (g_value_get_string (value));
else if (G_VALUE_HOLDS_INT (value))
json_value = json_integer (g_value_get_int (value));
else if (G_VALUE_HOLDS_BOOLEAN (value))
json_value = json_boolean (g_value_get_boolean (value));
else if (G_VALUE_HOLDS_BOXED (value)) {
if (nm_streq (key, "link_watch")) {
gboolean has_array = FALSE;
GPtrArray *array;
guint i;
array = g_value_get_boxed (value);
if (!array || !array->len)
return FALSE;
for (i = 0; i < array->len; i++) {
json_t *el;
el = _nm_utils_team_link_watcher_to_json (array->pdata[i]);
if (!el)
continue;
/* if there is only one watcher, it is added as-is. If there
* are multiple watchers, they are added in an array. */
if (!json_value) {
json_value = el;
continue;
}
if (!has_array) {
json_t *el_arr;
has_array = TRUE;
el_arr = json_array();
json_array_append_new (el_arr, json_value);
json_value = el_arr;
}
json_array_append_new (json_value, el);
}
} else if ( nm_streq (key, "runner")
&& nm_streq0 (key2, "tx_hash")) {
const char *const*strv;
gsize i;
strv = g_value_get_boxed (value);
if (!strv)
return FALSE;
json_value = json_array ();
for (i = 0; strv[i]; i++)
json_array_append_new (json_value, json_string (strv[i]));
} else {
nm_assert_not_reached ();
return FALSE;
}
} else { /* G_VALUE_HOLDS_? */
nm_assert_not_reached ();
return FALSE;
}
/* Simplest case: first level key only */
json_element = json;
json_link = NULL;
if (key2) {
json_link = json;
json_element = json_object_get (json, iter_key);
if (!json_element) {
json_element = json_object ();
json_object_set_new (json_link, iter_key, json_element);
}
iter_key = key2;
}
if (key3) {
json_link = json_element;
json_element = json_object_get (json_link, iter_key);
if (!json_element) {
json_element = json_object ();
json_object_set_new (json_link, iter_key, json_element);
}
iter_key = key3;
}
json_object_set_new (json_element, iter_key, g_steal_pointer (&json_value));
done:
_json_team_normalize_defaults (json, ( nm_streq0 (key, "runner")
&& nm_streq0 (key2, "name")));
conf_new = json_dumps (json, JSON_PRESERVE_ORDER);
if (nm_streq0 (conf_new, "{}"))
nm_clear_g_free (&conf_new);
if (nm_streq0 (conf_new, *conf))
return FALSE;
g_free (*conf);
*conf = g_steal_pointer (&conf_new);
return TRUE;
}
#else /* !WITH_JSON_VALIDATION */
gboolean
nm_utils_is_json_object (const char *str, GError **error)
{
g_return_val_if_fail (!error || !*error, FALSE);
if (!str || !str[0]) {
@ -6165,36 +5445,8 @@ nm_utils_is_json_object (const char *str, GError **error)
}
return _nm_utils_is_json_object_no_validation (str, error);
}
gboolean
_nm_utils_team_config_equal (const char *conf1,
const char *conf2,
gboolean port_config)
{
return nm_streq0 (conf1, conf2);
}
GValue *
_nm_utils_team_config_get (const char *conf,
const char *key,
const char *key2,
const char *key3,
gboolean port_config)
{
return NULL;
}
gboolean
_nm_utils_team_config_set (char **conf,
const char *key,
const char *key2,
const char *key3,
const GValue *value)
{
return FALSE;
}
#endif
}
/**
* _nm_utils_team_link_watchers_to_variant:

View file

@ -32,6 +32,7 @@
#include "nm-utils-private.h"
#include "nm-core-internal.h"
#include "nm-core-tests-enum-types.h"
#include "nm-team-utils.h"
#include "nm-setting-8021x.h"
#include "nm-setting-adsl.h"
@ -6807,19 +6808,42 @@ _team_config_equal_check (const char *conf1,
gboolean port_config,
gboolean expected)
{
nm_auto_free_team_setting NMTeamSetting *team_a = NULL;
nm_auto_free_team_setting NMTeamSetting *team_b = NULL;
gboolean is_same;
if (nmtst_get_rand_bool ())
NMTST_SWAP (conf1, conf2);
if (!nm_streq0 (conf1, conf2)) {
_team_config_equal_check (conf1, conf1, port_config, TRUE);
_team_config_equal_check (conf2, conf2, port_config, TRUE);
}
g_assert_cmpint (_nm_utils_team_config_equal (conf1, conf2, port_config), ==, expected);
team_a = nm_team_setting_new (port_config, conf1);
team_b = nm_team_setting_new (port_config, conf2);
is_same = (nm_team_setting_cmp (team_a, team_b, TRUE) == 0);
g_assert_cmpint (is_same, ==, expected);
if (nm_streq0 (conf1, conf2)) {
g_assert_cmpint (nm_team_setting_cmp (team_a, team_b, FALSE), ==, 0);
g_assert (expected);
} else
g_assert_cmpint (nm_team_setting_cmp (team_a, team_b, FALSE), !=, 0);
}
static void
test_nm_utils_team_config_equal (void)
{
#if WITH_JSON_VALIDATION
_team_config_equal_check ("", "", TRUE, TRUE);
_team_config_equal_check ("",
"",
TRUE,
TRUE);
_team_config_equal_check ("",
" ",
TRUE,
TRUE);
_team_config_equal_check ("{}",
"{ }",
TRUE,
@ -6827,7 +6851,15 @@ test_nm_utils_team_config_equal (void)
_team_config_equal_check ("{}",
"{",
TRUE,
FALSE);
TRUE);
_team_config_equal_check ("{ \"a\": 1 }",
"{ \"a\": 1 }",
TRUE,
TRUE);
_team_config_equal_check ("{ \"a\": 1 }",
"{ \"a\": 1 }",
TRUE,
TRUE);
/* team config */
_team_config_equal_check ("{ }",
@ -6837,11 +6869,11 @@ test_nm_utils_team_config_equal (void)
_team_config_equal_check ("{ }",
"{ \"runner\" : { \"name\" : \"random\"} }",
FALSE,
FALSE);
!WITH_JSON_VALIDATION);
_team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }",
"{ \"runner\" : { \"name\" : \"random\"} }",
FALSE,
FALSE);
!WITH_JSON_VALIDATION);
_team_config_equal_check ("{ \"runner\" : { \"name\" : \"random\"} }",
"{ \"runner\" : { \"name\" : \"random\"} }",
FALSE,
@ -6861,11 +6893,11 @@ test_nm_utils_team_config_equal (void)
_team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }",
"{ \"runner\" : { \"name\" : \"roundrobin\", \"tx_hash\" : [ \"eth\", \"ipv4\", \"ipv6\" ] } }",
FALSE,
FALSE);
!WITH_JSON_VALIDATION);
_team_config_equal_check ("{ \"runner\" : { \"name\" : \"lacp\"} }",
"{ \"runner\" : { \"name\" : \"lacp\", \"tx_hash\" : [ \"eth\" ] } }",
FALSE,
FALSE);
!WITH_JSON_VALIDATION);
/* team port config */
_team_config_equal_check ("{ }",
@ -6875,11 +6907,11 @@ test_nm_utils_team_config_equal (void)
_team_config_equal_check ("{ }",
"{ \"link_watch\" : { \"name\" : \"arp_ping\"} }",
TRUE,
FALSE);
TRUE);
_team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"ethtool\"} }",
"{ \"link_watch\" : { \"name\" : \"arp_ping\"} }",
TRUE,
FALSE);
TRUE);
_team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"arp_ping\"} }",
"{ \"link_watch\" : { \"name\" : \"arp_ping\"} }",
TRUE,
@ -6888,13 +6920,6 @@ test_nm_utils_team_config_equal (void)
"{ \"link_watch\" : { \"name\" : \"arp_ping\"}, \"ports\" : { \"eth1\" : {} } }",
TRUE,
TRUE);
#else
/* Without JSON library, strings are compared for equality */
_team_config_equal_check ("", "", TRUE, TRUE);
_team_config_equal_check ("", " ", TRUE, FALSE);
_team_config_equal_check ("{ \"a\": 1 }", "{ \"a\": 1 }", TRUE, TRUE);
_team_config_equal_check ("{ \"a\": 1 }", "{ \"a\": 1 }", TRUE, FALSE);
#endif
}
/*****************************************************************************/

View file

@ -1378,9 +1378,64 @@ test_team_port_full_config (void)
static void
_check_team_setting (NMSetting *setting)
{
gs_unref_object NMSetting *setting2 = NULL;
gs_unref_object NMSetting *setting_clone = NULL;
gboolean is_port = NM_IS_SETTING_TEAM_PORT (setting);
gs_unref_variant GVariant *variant2 = NULL;
gs_unref_variant GVariant *variant3 = NULL;
g_assert (NM_IS_SETTING_TEAM (setting) || is_port);
setting_clone = nm_setting_duplicate (setting);
if (!is_port) {
if (nm_setting_team_get_runner (NM_SETTING_TEAM (setting)) == NULL) {
/* such a setting is invalid. We must first coerce it so that it becomes
* valid. */
setting = setting_clone;
g_object_set (setting,
NM_SETTING_TEAM_RUNNER,
NM_SETTING_TEAM_RUNNER_DEFAULT,
NULL);
}
}
setting2 = g_object_new (G_OBJECT_TYPE (setting),
is_port
? NM_SETTING_TEAM_PORT_CONFIG
: NM_SETTING_TEAM_CONFIG,
is_port
? nm_setting_team_port_get_config (NM_SETTING_TEAM_PORT (setting))
: nm_setting_team_get_config (NM_SETTING_TEAM (setting)),
NULL);
if (WITH_JSON_VALIDATION)
nmtst_assert_setting_is_equal (setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT);
g_clear_object (&setting2);
nmtst_assert_setting_dbus_roundtrip (setting);
/* OK, now parse the setting only from the D-Bus variant, but removing the JSON config.
* For that, we have to "drop" the JSON and we do that by resetting the property.
* This causes JSON to be regenerated and it's in a normalized form that will compare
* equal. */
setting = setting_clone;
if (is_port) {
g_object_set (setting,
NM_SETTING_TEAM_PORT_STICKY,
nm_setting_team_port_get_sticky (NM_SETTING_TEAM_PORT (setting)),
NULL);
} else {
g_object_set (setting,
NM_SETTING_TEAM_RUNNER_SYS_PRIO,
nm_setting_team_get_runner_sys_prio (NM_SETTING_TEAM (setting)),
NULL);
}
variant2 = _nm_setting_to_dbus (setting, NULL, NM_CONNECTION_SERIALIZE_ALL);
variant3 = nm_utils_gvariant_vardict_filter_drop_one (variant2, "config");
setting2 = nmtst_assert_setting_dbus_new (G_OBJECT_TYPE (setting), variant3);
nmtst_assert_setting_is_equal (setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT);
}
static void
@ -1393,11 +1448,6 @@ test_team_setting (void)
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher1 = nm_team_link_watcher_new_nsna_ping (1, 3, 4, "bbb", NULL);
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher2 = nm_team_link_watcher_new_arp_ping2 (1, 3, 4, -1, "ccc", "ddd", 0, NULL);
if (!WITH_JSON_VALIDATION) {
g_test_skip ("disabled test without json-validation");
return;
}
g_assert (watcher1);
g_assert (watcher2);
@ -1410,7 +1460,6 @@ test_team_setting (void)
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}}");
g_assert_cmpint (nm_setting_team_get_num_link_watchers (NM_SETTING_TEAM (setting)), ==, 1);
g_object_set (setting,
@ -1420,19 +1469,36 @@ test_team_setting (void)
_check_team_setting (setting);
g_assert_cmpint (nm_setting_team_get_num_link_watchers (NM_SETTING_TEAM (setting)), ==, 1);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}, \"runner\": {\"sys_prio\": 10}}");
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"ethtool\"} }");
nm_setting_team_remove_link_watcher (NM_SETTING_TEAM (setting), 0);
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}, \"runner\": {\"sys_prio\": 10}}");
g_assert_cmpint (nm_setting_team_get_num_link_watchers (NM_SETTING_TEAM (setting)), ==, 0);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 } }");
nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher1);
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}, \"runner\": {\"sys_prio\": 10}}");
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4} }");
nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher2);
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{\"link_watch\": {\"name\": \"ethtool\"}, \"runner\": {\"sys_prio\": 10}}");
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"sys_prio\": 10 }, \"link_watch\": [ { \"name\": \"nsna_ping\", \"target_host\": \"bbb\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4}, { \"name\": \"arp_ping\", \"target_host\": \"ccc\", \"source_host\": \"ddd\", \"init_wait\": 1, \"interval\": 3, \"missed_max\": 4} ] }");
nm_setting_team_remove_link_watcher (NM_SETTING_TEAM (setting), 0);
nm_setting_team_remove_link_watcher (NM_SETTING_TEAM (setting), 0);
g_object_set (setting,
NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL,
(int) 5,
NULL);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"tx_balancer\": { \"balancing_interval\": 5 }, \"sys_prio\": 10 } }");
g_object_set (setting,
NM_SETTING_TEAM_RUNNER,
NULL,
NULL);
_check_team_setting (setting);
g_assert_cmpstr (nm_setting_team_get_config (NM_SETTING_TEAM (setting)), ==, "{ \"runner\": { \"tx_balancer\": { \"balancing_interval\": 5 }, \"sys_prio\": 10 } }");
}
/*****************************************************************************/

View file

@ -165,6 +165,8 @@ def get_default_value(setting, pspec, propxml):
default_value = '[]'
elif str(default_value).startswith('<'):
default_value = None
elif str(default_value).startswith('['):
default_value = None
return default_value

View file

@ -102,6 +102,7 @@ libnm-core/nm-setting-wireless-security.c
libnm-core/nm-setting-wireless.c
libnm-core/nm-setting-wpan.c
libnm-core/nm-setting.c
libnm-core/nm-team-utils.c
libnm-core/nm-utils.c
libnm-core/nm-vpn-editor-plugin.c
libnm-core/nm-vpn-plugin-info.c

View file

@ -8939,11 +8939,15 @@ test_read_team_master_invalid (gconstpointer user_data)
{
const char *const PATH_NAME = user_data;
gs_free_error GError *error = NULL;
gs_unref_object NMConnection *connection = NULL;
_connection_from_file_fail (PATH_NAME, NULL, TYPE_ETHERNET, &error);
if (WITH_JSON_VALIDATION) {
_connection_from_file_fail (PATH_NAME, NULL, TYPE_ETHERNET, &error);
g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
g_assert (strstr (error->message, "JSON"));
g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
g_assert (strstr (error->message, _("invalid json")));
} else
connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
}
static void