mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-05 01:47:58 +02:00
libnm/team: merge branch 'th/libnm-team-fixes'
https://github.com/NetworkManager/NetworkManager/pull/318
This commit is contained in:
commit
c7864fc1b2
9 changed files with 386 additions and 194 deletions
|
|
@ -284,7 +284,6 @@ char ** _nm_utils_slist_to_strv (GSList *slist, gboolean deep_copy);
|
|||
|
||||
GPtrArray * _nm_utils_strv_to_ptrarray (char **strv);
|
||||
char ** _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray);
|
||||
gboolean _nm_utils_strv_equal (char **strv1, char **strv2);
|
||||
|
||||
gboolean _nm_utils_check_file (const char *filename,
|
||||
gint64 check_owner,
|
||||
|
|
@ -538,6 +537,8 @@ gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean _nm_team_link_watchers_equal (GPtrArray *a, 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,
|
||||
|
|
|
|||
|
|
@ -396,31 +396,18 @@ compare_property (const NMSettInfoSetting *sett_info,
|
|||
{
|
||||
NMSettingTeamPortPrivate *a_priv;
|
||||
NMSettingTeamPortPrivate *b_priv;
|
||||
guint i, j;
|
||||
|
||||
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 (other) {
|
||||
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
|
||||
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
|
||||
|
||||
if (a_priv->link_watchers->len != b_priv->link_watchers->len)
|
||||
return FALSE;
|
||||
for (i = 0; i < a_priv->link_watchers->len; i++) {
|
||||
for (j = 0; j < b_priv->link_watchers->len; j++) {
|
||||
if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
|
||||
b_priv->link_watchers->pdata[j])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == b_priv->link_watchers->len)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
if (!other)
|
||||
return TRUE;
|
||||
a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
|
||||
b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
|
||||
return _nm_team_link_watchers_equal (a_priv->link_watchers,
|
||||
b_priv->link_watchers,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_PORT_CONFIG)) {
|
||||
|
|
|
|||
|
|
@ -396,6 +396,34 @@ nm_team_link_watcher_equal (NMTeamLinkWatcher *watcher, NMTeamLinkWatcher *other
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_nm_team_link_watchers_equal (GPtrArray *a, GPtrArray *b, gboolean ignore_order)
|
||||
{
|
||||
guint i, j;
|
||||
|
||||
if (a->len != b->len)
|
||||
return FALSE;
|
||||
if (ignore_order) {
|
||||
/* FIXME: comparing this way is O(n^2). Don't do that, instead
|
||||
* add nm_team_link_watcher_cmp(), sort both lists, and
|
||||
* compare step by step. */
|
||||
for (i = 0; i < a->len; i++) {
|
||||
for (j = 0; j < b->len; j++) {
|
||||
if (nm_team_link_watcher_equal (a->pdata[i], b->pdata[j]))
|
||||
break;
|
||||
}
|
||||
if (j == b->len)
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < a->len; i++) {
|
||||
if (!nm_team_link_watcher_equal (a->pdata[i], b->pdata[i]))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_team_link_watcher_dup:
|
||||
* @watcher: the #NMTeamLinkWatcher
|
||||
|
|
@ -929,13 +957,14 @@ nm_setting_team_remove_runner_tx_hash_by_value (NMSettingTeam *setting,
|
|||
|
||||
g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), FALSE);
|
||||
g_return_val_if_fail (txhash != NULL, FALSE);
|
||||
g_return_val_if_fail (txhash[0] != '\0', FALSE);
|
||||
|
||||
for (i = 0; i < priv->runner_tx_hash->len; i++) {
|
||||
if (nm_streq (txhash, priv->runner_tx_hash->pdata[i])) {
|
||||
g_ptr_array_remove_index (priv->runner_tx_hash, i);
|
||||
_notify (setting, PROP_RUNNER_TX_HASH);
|
||||
return TRUE;
|
||||
if (priv->runner_tx_hash) {
|
||||
for (i = 0; i < priv->runner_tx_hash->len; i++) {
|
||||
if (nm_streq (txhash, priv->runner_tx_hash->pdata[i])) {
|
||||
g_ptr_array_remove_index (priv->runner_tx_hash, i);
|
||||
_notify (setting, PROP_RUNNER_TX_HASH);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
|
@ -1239,9 +1268,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
|
|||
|
||||
if (!name) {
|
||||
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
|
||||
_("missing link watcher name"));
|
||||
_("missing link watcher name"));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting),
|
||||
NM_SETTING_TEAM_LINK_WATCHERS);
|
||||
NM_SETTING_TEAM_LINK_WATCHERS);
|
||||
return FALSE;
|
||||
}
|
||||
if (!NM_IN_STRSET (name,
|
||||
|
|
@ -1249,9 +1278,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
|
|||
NM_TEAM_LINK_WATCHER_ARP_PING,
|
||||
NM_TEAM_LINK_WATCHER_NSNA_PING)) {
|
||||
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
|
||||
_("unknown link watcher \"%s\""), name);
|
||||
_("unknown link watcher \"%s\""), name);
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting),
|
||||
NM_SETTING_TEAM_LINK_WATCHERS);
|
||||
NM_SETTING_TEAM_LINK_WATCHERS);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1260,17 +1289,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
|
|||
NM_TEAM_LINK_WATCHER_NSNA_PING)
|
||||
&& !nm_team_link_watcher_get_target_host (link_watcher)) {
|
||||
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
|
||||
_("missing target host"));
|
||||
_("missing target host"));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting),
|
||||
NM_SETTING_TEAM_LINK_WATCHERS);
|
||||
NM_SETTING_TEAM_LINK_WATCHERS);
|
||||
return FALSE;
|
||||
}
|
||||
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING)
|
||||
&& !nm_team_link_watcher_get_source_host (link_watcher)) {
|
||||
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING,
|
||||
_("missing source address"));
|
||||
_("missing source address"));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting),
|
||||
NM_SETTING_TEAM_LINK_WATCHERS);
|
||||
NM_SETTING_TEAM_LINK_WATCHERS);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1288,31 +1317,17 @@ compare_property (const NMSettInfoSetting *sett_info,
|
|||
NMSettingCompareFlags flags)
|
||||
{
|
||||
NMSettingTeamPrivate *a_priv, *b_priv;
|
||||
guint i, j;
|
||||
|
||||
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_LINK_WATCHERS)) {
|
||||
|
||||
if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
|
||||
return NM_TERNARY_DEFAULT;
|
||||
|
||||
if (other) {
|
||||
a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
|
||||
b_priv = NM_SETTING_TEAM_GET_PRIVATE (other);
|
||||
|
||||
if (a_priv->link_watchers->len != b_priv->link_watchers->len)
|
||||
return FALSE;
|
||||
for (i = 0; i < a_priv->link_watchers->len; i++) {
|
||||
for (j = 0; j < b_priv->link_watchers->len; j++) {
|
||||
if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
|
||||
b_priv->link_watchers->pdata[j])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == b_priv->link_watchers->len)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
if (!other)
|
||||
return TRUE;
|
||||
a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
|
||||
b_priv = NM_SETTING_TEAM_GET_PRIVATE (other);
|
||||
return _nm_team_link_watchers_equal (a_priv->link_watchers,
|
||||
b_priv->link_watchers,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_CONFIG)) {
|
||||
|
|
@ -1350,7 +1365,7 @@ _align_team_properties (NMSettingTeam *setting)
|
|||
{
|
||||
NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
|
||||
char **strv;
|
||||
int i;
|
||||
gsize i;
|
||||
|
||||
priv->notify_peers_count = JSON_TO_VAL (int, PROP_NOTIFY_PEERS_COUNT);
|
||||
priv->notify_peers_interval = JSON_TO_VAL (int, PROP_NOTIFY_PEERS_INTERVAL);
|
||||
|
|
@ -1372,16 +1387,24 @@ _align_team_properties (NMSettingTeam *setting)
|
|||
priv->runner_tx_balancer = JSON_TO_VAL (string, PROP_RUNNER_TX_BALANCER);
|
||||
priv->runner_agg_select_policy = JSON_TO_VAL (string, PROP_RUNNER_AGG_SELECT_POLICY);
|
||||
|
||||
if (priv->runner_tx_hash) {
|
||||
g_ptr_array_unref (priv->runner_tx_hash);
|
||||
priv->runner_tx_hash = NULL;
|
||||
}
|
||||
strv = JSON_TO_VAL (strv, PROP_RUNNER_TX_HASH);
|
||||
if (strv) {
|
||||
for (i = 0; strv[i]; i++)
|
||||
nm_setting_team_add_runner_tx_hash (setting, strv[i]);
|
||||
g_strfreev (strv);
|
||||
if (_nm_utils_strv_cmp_n (( priv->runner_tx_hash
|
||||
? (const char *const*) priv->runner_tx_hash->pdata
|
||||
: NULL),
|
||||
( priv->runner_tx_hash
|
||||
? (gssize) priv->runner_tx_hash->len
|
||||
: (gssize) -1),
|
||||
NM_CAST_STRV_CC (strv),
|
||||
-1) != 0) {
|
||||
nm_clear_pointer (&priv->runner_tx_hash, g_ptr_array_unref);
|
||||
if (strv) {
|
||||
priv->runner_tx_hash = g_ptr_array_new_full (NM_PTRARRAY_LEN (strv), g_free);
|
||||
for (i = 0; strv[i]; i++)
|
||||
g_ptr_array_add (priv->runner_tx_hash, strv[i]);
|
||||
nm_clear_g_free (&strv);
|
||||
}
|
||||
}
|
||||
nm_clear_pointer (&strv, g_strfreev);
|
||||
|
||||
g_ptr_array_unref (priv->link_watchers);
|
||||
priv->link_watchers = JSON_TO_VAL (ptr_array, PROP_LINK_WATCHERS);
|
||||
|
|
@ -1419,8 +1442,10 @@ get_property (GObject *object, guint prop_id,
|
|||
g_value_set_string (value, nm_setting_team_get_runner_hwaddr_policy (setting));
|
||||
break;
|
||||
case PROP_RUNNER_TX_HASH:
|
||||
g_value_take_boxed (value, priv->runner_tx_hash ?
|
||||
_nm_utils_ptrarray_to_strv (priv->runner_tx_hash): NULL);
|
||||
g_value_take_boxed (value,
|
||||
priv->runner_tx_hash
|
||||
? _nm_utils_ptrarray_to_strv (priv->runner_tx_hash)
|
||||
: NULL);
|
||||
break;
|
||||
case PROP_RUNNER_TX_BALANCER:
|
||||
g_value_set_string (value, nm_setting_team_get_runner_tx_balancer (setting));
|
||||
|
|
@ -1772,9 +1797,9 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
|
|||
obj_properties[PROP_RUNNER_TX_HASH] =
|
||||
g_param_spec_boxed (NM_SETTING_TEAM_RUNNER_TX_HASH, "", "",
|
||||
G_TYPE_STRV,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_READWRITE |
|
||||
NM_SETTING_PARAM_INFERRABLE |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* NMSettingTeam:runner-tx-balancer:
|
||||
|
|
|
|||
|
|
@ -105,6 +105,16 @@ gboolean _nm_sriov_vf_parse_vlans (NMSriovVF *vf, const char *str, GError **e
|
|||
|
||||
/* 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;
|
||||
|
|
@ -121,16 +131,13 @@ _nm_utils_json_extract_int (char *conf,
|
|||
_NMUtilsTeamPropertyKeys key,
|
||||
gboolean is_port)
|
||||
{
|
||||
gs_free GValue *t_value = NULL;
|
||||
int ret;
|
||||
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)
|
||||
if ( !t_value
|
||||
|| !G_VALUE_HOLDS_INT (t_value))
|
||||
return key.default_int;
|
||||
|
||||
ret = g_value_get_int (t_value);
|
||||
g_value_unset (t_value);
|
||||
return ret;
|
||||
return g_value_get_int (t_value);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
|
|
@ -138,16 +145,13 @@ _nm_utils_json_extract_boolean (char *conf,
|
|||
_NMUtilsTeamPropertyKeys key,
|
||||
gboolean is_port)
|
||||
{
|
||||
gs_free GValue *t_value = NULL;
|
||||
gboolean ret;
|
||||
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)
|
||||
if ( !t_value
|
||||
|| !G_VALUE_HOLDS_BOOLEAN (t_value))
|
||||
return key.default_bool;
|
||||
|
||||
ret = g_value_get_boolean (t_value);
|
||||
g_value_unset (t_value);
|
||||
return ret;
|
||||
return g_value_get_boolean (t_value);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
|
|
@ -155,16 +159,13 @@ _nm_utils_json_extract_string (char *conf,
|
|||
_NMUtilsTeamPropertyKeys key,
|
||||
gboolean is_port)
|
||||
{
|
||||
gs_free GValue *t_value = NULL;
|
||||
char *ret;
|
||||
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)
|
||||
if ( !t_value
|
||||
|| !G_VALUE_HOLDS_STRING (t_value))
|
||||
return g_strdup (key.default_str);
|
||||
|
||||
ret = g_value_dup_string (t_value);
|
||||
g_value_unset (t_value);
|
||||
return ret;
|
||||
return g_value_dup_string (t_value);
|
||||
}
|
||||
|
||||
static inline char **
|
||||
|
|
@ -172,39 +173,37 @@ _nm_utils_json_extract_strv (char *conf,
|
|||
_NMUtilsTeamPropertyKeys key,
|
||||
gboolean is_port)
|
||||
{
|
||||
gs_free GValue *t_value = NULL;
|
||||
char **ret;
|
||||
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)
|
||||
if ( !t_value
|
||||
|| !G_TYPE_CHECK_VALUE_TYPE (t_value, G_TYPE_STRV))
|
||||
return NULL;
|
||||
|
||||
ret = g_strdupv (g_value_get_boxed (t_value));
|
||||
g_value_unset (t_value);
|
||||
return ret;
|
||||
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)
|
||||
_NMUtilsTeamPropertyKeys key,
|
||||
gboolean is_port)
|
||||
{
|
||||
gs_free GValue *t_value = NULL;
|
||||
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)
|
||||
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_dup (data->pdata[i]));
|
||||
g_value_unset (t_value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1034,30 +1034,6 @@ _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray)
|
|||
return strv;
|
||||
}
|
||||
|
||||
/**
|
||||
* _nm_utils_strv_equal:
|
||||
* @strv1: a string array
|
||||
* @strv2: a string array
|
||||
*
|
||||
* Compare NULL-terminated string arrays for equality.
|
||||
*
|
||||
* Returns: %TRUE if the arrays are equal, %FALSE otherwise.
|
||||
**/
|
||||
gboolean
|
||||
_nm_utils_strv_equal (char **strv1, char **strv2)
|
||||
{
|
||||
if (strv1 == strv2)
|
||||
return TRUE;
|
||||
|
||||
if (!strv1 || !strv2)
|
||||
return FALSE;
|
||||
|
||||
for ( ; *strv1 && *strv2 && !strcmp (*strv1, *strv2); strv1++, strv2++)
|
||||
;
|
||||
|
||||
return !*strv1 && !*strv2;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
device_supports_ap_ciphers (guint32 dev_caps,
|
||||
guint32 ap_flags,
|
||||
|
|
@ -5430,11 +5406,11 @@ _json_team_add_defaults (json_t *json,
|
|||
|
||||
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_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));
|
||||
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)) {
|
||||
|| 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"));
|
||||
|
|
@ -5922,11 +5898,9 @@ _nm_utils_team_config_get (const char *conf,
|
|||
if (json_is_string (str_element))
|
||||
g_ptr_array_add (data, g_strdup (json_string_value (str_element)));
|
||||
}
|
||||
if (data->len) {
|
||||
g_value_init (value, G_TYPE_STRV);
|
||||
g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (data));
|
||||
}
|
||||
g_ptr_array_free (data, TRUE);
|
||||
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);
|
||||
|
|
@ -5948,14 +5922,13 @@ _nm_utils_team_config_set (char **conf,
|
|||
const char *key3,
|
||||
const GValue *value)
|
||||
{
|
||||
json_t *json, *json_element, *json_link, *json_value = NULL;
|
||||
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;
|
||||
gboolean updated = FALSE;
|
||||
char **strv;
|
||||
GPtrArray *array;
|
||||
const char *iter_key = key;
|
||||
int i;
|
||||
NMTeamLinkWatcher *watcher;
|
||||
gs_free char *conf_new = NULL;
|
||||
|
||||
g_return_val_if_fail (key, FALSE);
|
||||
|
||||
|
|
@ -5966,14 +5939,12 @@ _nm_utils_team_config_set (char **conf,
|
|||
if (!json)
|
||||
return FALSE;
|
||||
|
||||
/* no new value? delete element */
|
||||
if (!value) {
|
||||
updated = _json_del_object (json, key, key2, key3);
|
||||
if (!_json_del_object (json, key, key2, key3))
|
||||
return FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* insert new value */
|
||||
updated = TRUE;
|
||||
if (G_VALUE_HOLDS_STRING (value))
|
||||
json_value = json_string (g_value_get_string (value));
|
||||
else if (G_VALUE_HOLDS_INT (value))
|
||||
|
|
@ -5982,53 +5953,56 @@ _nm_utils_team_config_set (char **conf,
|
|||
json_value = json_boolean (g_value_get_boolean (value));
|
||||
else if (G_VALUE_HOLDS_BOXED (value)) {
|
||||
if (nm_streq (key, "link_watch")) {
|
||||
array = g_value_get_boxed (value);
|
||||
if (!array || !array->len) {
|
||||
updated = FALSE;
|
||||
goto done;
|
||||
}
|
||||
gboolean has_array = FALSE;
|
||||
GPtrArray *array;
|
||||
guint i;
|
||||
|
||||
array = g_value_get_boxed (value);
|
||||
if (!array || !array->len)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* json_value: will hold the final link_watcher json (array) object
|
||||
* json_element: is the next link_watcher to append to json_value
|
||||
* json_link: used to transit the json_value from a single link_watcher
|
||||
* object to an array of link watcher objects
|
||||
*/
|
||||
json_value = NULL;
|
||||
for (i = 0; i < array->len; i++) {
|
||||
watcher = array->pdata[i];
|
||||
json_element = _nm_utils_team_link_watcher_to_json (watcher);
|
||||
if (!json_element)
|
||||
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 = json_element;
|
||||
json_value = el;
|
||||
continue;
|
||||
}
|
||||
if (!json_is_array (json_value)) {
|
||||
json_link = json_value;
|
||||
json_value = json_array ();
|
||||
json_array_append_new (json_value, json_link);
|
||||
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, json_element);
|
||||
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) {
|
||||
updated = FALSE;
|
||||
goto done;
|
||||
}
|
||||
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 {
|
||||
updated = FALSE;
|
||||
goto done;
|
||||
nm_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
} else { /* G_VALUE_HOLDS_? */
|
||||
g_assert_not_reached ();
|
||||
updated = FALSE;
|
||||
goto done;
|
||||
nm_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Simplest case: first level key only */
|
||||
|
|
@ -6054,22 +6028,19 @@ _nm_utils_team_config_set (char **conf,
|
|||
iter_key = key3;
|
||||
}
|
||||
|
||||
json_object_set_new (json_element, iter_key, json_value);
|
||||
json_object_set_new (json_element, iter_key, g_steal_pointer (&json_value));
|
||||
|
||||
done:
|
||||
if (updated) {
|
||||
_json_team_normalize_defaults (json, ( nm_streq0 (key, "runner")
|
||||
&& nm_streq0 (key2, "name")));
|
||||
g_free (*conf);
|
||||
*conf = json_dumps (json, JSON_PRESERVE_ORDER);
|
||||
/* Don't save an empty config */
|
||||
if (nm_streq0 (*conf, "{}")) {
|
||||
g_free (*conf);
|
||||
*conf = NULL;
|
||||
}
|
||||
}
|
||||
json_decref (json);
|
||||
return updated;
|
||||
_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 */
|
||||
|
|
|
|||
|
|
@ -2318,6 +2318,57 @@ _nm_utils_strv_sort (const char **strv, gssize len)
|
|||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* _nm_utils_strv_cmp_n:
|
||||
* @strv1: a string array
|
||||
* @len1: the length of @strv1, or -1 for NULL terminated array.
|
||||
* @strv2: a string array
|
||||
* @len2: the length of @strv2, or -1 for NULL terminated array.
|
||||
*
|
||||
* Note that
|
||||
* - len == -1 && strv == NULL
|
||||
* is treated like a %NULL argument and compares differently from
|
||||
* other arrays.
|
||||
*
|
||||
* Note that an empty array can be represented as
|
||||
* - len == -1 && strv && !strv[0]
|
||||
* - len == 0 && !strv
|
||||
* - len == 0 && strv
|
||||
* These 3 forms all compare equal.
|
||||
* It also means, if length is 0, then it is permissible for strv to be %NULL.
|
||||
*
|
||||
* The strv arrays may contain %NULL strings (if len is positive).
|
||||
*
|
||||
* Returns: 0 if the arrays are equal (using strcmp).
|
||||
**/
|
||||
int
|
||||
_nm_utils_strv_cmp_n (const char *const*strv1,
|
||||
gssize len1,
|
||||
const char *const*strv2,
|
||||
gssize len2)
|
||||
{
|
||||
gsize n, n2;
|
||||
|
||||
if (len1 < 0) {
|
||||
if (!strv1)
|
||||
return (len2 < 0 && !strv2) ? 0 : -1;
|
||||
n = NM_PTRARRAY_LEN (strv1);
|
||||
} else
|
||||
n = len1;
|
||||
|
||||
if (len2 < 0) {
|
||||
if (!strv2)
|
||||
return 1;
|
||||
n2 = NM_PTRARRAY_LEN (strv2);
|
||||
} else
|
||||
n2 = len2;
|
||||
|
||||
NM_CMP_DIRECT (n, n2);
|
||||
for (; n > 0; n--, strv1++, strv2++)
|
||||
NM_CMP_DIRECT_STRCMP0 (*strv1, *strv2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gpointer
|
||||
|
|
|
|||
|
|
@ -941,6 +941,18 @@ gboolean nm_utils_hash_table_equal (const GHashTable *a,
|
|||
void _nm_utils_strv_sort (const char **strv, gssize len);
|
||||
#define nm_utils_strv_sort(strv, len) _nm_utils_strv_sort (NM_CAST_STRV_MC (strv), len)
|
||||
|
||||
int _nm_utils_strv_cmp_n (const char *const*strv1,
|
||||
gssize len1,
|
||||
const char *const*strv2,
|
||||
gssize len2);
|
||||
|
||||
static inline gboolean
|
||||
_nm_utils_strv_equal (char **strv1, char **strv2)
|
||||
{
|
||||
return _nm_utils_strv_cmp_n ((const char *const*) strv1, -1,
|
||||
(const char *const*) strv2, -1) == 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define NM_UTILS_NS_PER_SECOND ((gint64) 1000000000)
|
||||
|
|
|
|||
|
|
@ -1136,12 +1136,13 @@ nmtst_uuid_generate (void)
|
|||
|
||||
#endif
|
||||
|
||||
#define NMTST_SWAP(x,y) \
|
||||
#define NMTST_SWAP(x, y) \
|
||||
G_STMT_START { \
|
||||
char __nmtst_swap_temp[sizeof(x) == sizeof(y) ? (signed) sizeof(x) : -1]; \
|
||||
memcpy(__nmtst_swap_temp, &y, sizeof(x)); \
|
||||
memcpy(&y, &x, sizeof(x)); \
|
||||
memcpy(&x, __nmtst_swap_temp, sizeof(x)); \
|
||||
char __nmtst_swap_temp[sizeof((x)) == sizeof((y)) ? (signed) sizeof((x)) : -1]; \
|
||||
\
|
||||
memcpy(__nmtst_swap_temp, &(y), sizeof (__nmtst_swap_temp)); \
|
||||
memcpy(&(y), &(x), sizeof (__nmtst_swap_temp)); \
|
||||
memcpy(&(x), __nmtst_swap_temp, sizeof (__nmtst_swap_temp)); \
|
||||
} G_STMT_END
|
||||
|
||||
#define nmtst_assert_str_has_substr(str, substr) \
|
||||
|
|
|
|||
|
|
@ -248,6 +248,150 @@ test_unaligned (void)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_strv_cmp_fuzz_input (const char *const*in,
|
||||
gssize l,
|
||||
const char ***out_strv_free_shallow,
|
||||
char ***out_strv_free_deep,
|
||||
const char *const* *out_s1,
|
||||
const char *const* *out_s2)
|
||||
{
|
||||
const char **strv;
|
||||
gsize i;
|
||||
|
||||
/* Fuzz the input argument. It will return two output arrays that are semantically
|
||||
* equal the input. */
|
||||
|
||||
if (nmtst_get_rand_bool ()) {
|
||||
char **ss;
|
||||
|
||||
if (l < 0)
|
||||
ss = g_strdupv ((char **) in);
|
||||
else if (l == 0) {
|
||||
ss = nmtst_get_rand_bool ()
|
||||
? NULL
|
||||
: g_new0 (char *, 1);
|
||||
} else {
|
||||
ss = nm_memdup (in, sizeof (const char *) * l);
|
||||
for (i = 0; i < (gsize) l; i++)
|
||||
ss[i] = g_strdup (ss[i]);
|
||||
}
|
||||
strv = (const char **) ss;
|
||||
*out_strv_free_deep = ss;
|
||||
} else {
|
||||
if (l < 0) {
|
||||
strv = in
|
||||
? nm_memdup (in, sizeof (const char *) * (NM_PTRARRAY_LEN (in) + 1))
|
||||
: NULL;
|
||||
} else if (l == 0) {
|
||||
strv = nmtst_get_rand_bool ()
|
||||
? NULL
|
||||
: g_new0 (const char *, 1);
|
||||
} else
|
||||
strv = nm_memdup (in, sizeof (const char *) * l);
|
||||
*out_strv_free_shallow = strv;
|
||||
}
|
||||
|
||||
*out_s1 = in;
|
||||
*out_s2 = strv;
|
||||
|
||||
if (nmtst_get_rand_bool ()) {
|
||||
/* randomly swap the original and the clone. That means, out_s1 is either
|
||||
* the input argument (as-is) or the sementically equal clone. */
|
||||
NMTST_SWAP (*out_s1, *out_s2);
|
||||
}
|
||||
if (nmtst_get_rand_bool ()) {
|
||||
/* randomly make s1 and s2 the same. This is for testing that
|
||||
* comparing two identical pointers yields the same result. */
|
||||
*out_s2 = *out_s1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_strv_cmp_free_deep (char **strv,
|
||||
gssize len)
|
||||
{
|
||||
gssize i;
|
||||
|
||||
if (strv) {
|
||||
if (len < 0)
|
||||
g_strfreev (strv);
|
||||
else {
|
||||
for (i = 0; i < len; i++)
|
||||
g_free (strv[i]);
|
||||
g_free (strv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_strv_cmp (void)
|
||||
{
|
||||
const char *const strv0[1] = { };
|
||||
const char *const strv1[2] = { "", };
|
||||
|
||||
#define _STRV_CMP(a1, l1, a2, l2, equal) \
|
||||
G_STMT_START { \
|
||||
gssize _l1 = (l1); \
|
||||
gssize _l2 = (l2); \
|
||||
const char *const*_a1; \
|
||||
const char *const*_a2; \
|
||||
const char *const*_a1x; \
|
||||
const char *const*_a2x; \
|
||||
char **_a1_free_deep = NULL; \
|
||||
char **_a2_free_deep = NULL; \
|
||||
gs_free const char **_a1_free_shallow = NULL; \
|
||||
gs_free const char **_a2_free_shallow = NULL; \
|
||||
int _c1, _c2; \
|
||||
\
|
||||
_strv_cmp_fuzz_input ((a1), _l1, &_a1_free_shallow, &_a1_free_deep, &_a1, &_a1x); \
|
||||
_strv_cmp_fuzz_input ((a2), _l2, &_a2_free_shallow, &_a2_free_deep, &_a2, &_a2x); \
|
||||
\
|
||||
_c1 = _nm_utils_strv_cmp_n (_a1, _l1, _a2, _l2); \
|
||||
_c2 = _nm_utils_strv_cmp_n (_a2, _l2, _a1, _l1); \
|
||||
if (equal) { \
|
||||
g_assert_cmpint (_c1, ==, 0); \
|
||||
g_assert_cmpint (_c2, ==, 0); \
|
||||
} else { \
|
||||
g_assert_cmpint (_c1, ==, -1); \
|
||||
g_assert_cmpint (_c2, ==, 1); \
|
||||
} \
|
||||
\
|
||||
/* Compare with self. _strv_cmp_fuzz_input() randomly swapped the arguments (_a1 and _a1x).
|
||||
* Either way, the arrays must compare equal to their semantically equal alternative. */ \
|
||||
g_assert_cmpint (_nm_utils_strv_cmp_n (_a1, _l1, _a1x, _l1), ==, 0); \
|
||||
g_assert_cmpint (_nm_utils_strv_cmp_n (_a2, _l2, _a2x, _l2), ==, 0); \
|
||||
\
|
||||
_strv_cmp_free_deep (_a1_free_deep, _l1); \
|
||||
_strv_cmp_free_deep (_a2_free_deep, _l2); \
|
||||
} G_STMT_END
|
||||
|
||||
_STRV_CMP (NULL, -1, NULL, -1, TRUE);
|
||||
|
||||
_STRV_CMP (NULL, -1, NULL, 0, FALSE);
|
||||
_STRV_CMP (NULL, -1, strv0, 0, FALSE);
|
||||
_STRV_CMP (NULL, -1, strv0, -1, FALSE);
|
||||
|
||||
_STRV_CMP (NULL, 0, NULL, 0, TRUE);
|
||||
_STRV_CMP (NULL, 0, strv0, 0, TRUE);
|
||||
_STRV_CMP (NULL, 0, strv0, -1, TRUE);
|
||||
_STRV_CMP (strv0, 0, strv0, 0, TRUE);
|
||||
_STRV_CMP (strv0, 0, strv0, -1, TRUE);
|
||||
_STRV_CMP (strv0, -1, strv0, -1, TRUE);
|
||||
|
||||
_STRV_CMP (NULL, 0, strv1, -1, FALSE);
|
||||
_STRV_CMP (NULL, 0, strv1, 1, FALSE);
|
||||
_STRV_CMP (strv0, 0, strv1, -1, FALSE);
|
||||
_STRV_CMP (strv0, 0, strv1, 1, FALSE);
|
||||
_STRV_CMP (strv0, -1, strv1, -1, FALSE);
|
||||
_STRV_CMP (strv0, -1, strv1, 1, FALSE);
|
||||
|
||||
_STRV_CMP (strv1, -1, strv1, 1, TRUE);
|
||||
_STRV_CMP (strv1, 1, strv1, 1, TRUE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE ();
|
||||
|
||||
int main (int argc, char **argv)
|
||||
|
|
@ -261,6 +405,7 @@ int main (int argc, char **argv)
|
|||
g_test_add_func ("/general/test_nm_strndup_a", test_nm_strndup_a);
|
||||
g_test_add_func ("/general/test_nm_ip4_addr_is_localhost", test_nm_ip4_addr_is_localhost);
|
||||
g_test_add_func ("/general/test_unaligned", test_unaligned);
|
||||
g_test_add_func ("/general/test_strv_cmp", test_strv_cmp);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue