libnm: verify bond option in defined order

verify() should validate options in a deterministic order, so that
the same profile (with same libnm version) gives the same failure
reason every time.

Hence, visit the options in sorted order, like we do for nm_setting_bond_get_option().
This commit is contained in:
Thomas Haller
2020-02-19 16:47:36 +01:00
parent ae1008b239
commit 8775c25c33

View File

@@ -210,6 +210,13 @@ _get_option_sort (gconstpointer p_a, gconstpointer p_b, gpointer _unused)
return 0; return 0;
} }
static void
_ensure_options_idx_cache (NMSettingBondPrivate *priv)
{
if (!G_UNLIKELY (priv->options_idx_cache))
priv->options_idx_cache = nm_utils_named_values_from_str_dict_with_sort (priv->options, NULL, _get_option_sort, NULL);
}
/** /**
* nm_setting_bond_get_option: * nm_setting_bond_get_option:
* @setting: the #NMSettingBond * @setting: the #NMSettingBond
@@ -248,8 +255,7 @@ nm_setting_bond_get_option (NMSettingBond *setting,
if (idx >= len) if (idx >= len)
return FALSE; return FALSE;
if (!G_UNLIKELY (priv->options_idx_cache)) _ensure_options_idx_cache (priv);
priv->options_idx_cache = nm_utils_named_values_from_str_dict_with_sort (priv->options, NULL, _get_option_sort, NULL);
NM_SET_OUT (out_name, priv->options_idx_cache[idx].name); NM_SET_OUT (out_name, priv->options_idx_cache[idx].name);
NM_SET_OUT (out_value, priv->options_idx_cache[idx].value_str); NM_SET_OUT (out_value, priv->options_idx_cache[idx].value_str);
@@ -596,26 +602,37 @@ static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error) verify (NMSetting *setting, NMConnection *connection, GError **error)
{ {
NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting); NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting);
GHashTableIter iter; int mode;
const char *key, *value; int miimon = 0;
int mode, miimon = 0, arp_interval = 0; int arp_interval = 0;
int num_grat_arp = -1, num_unsol_na = -1; int num_grat_arp = -1;
const char *mode_orig, *mode_new; int num_unsol_na = -1;
const char *mode_orig;
const char *mode_new;
const char *arp_ip_target = NULL; const char *arp_ip_target = NULL;
const char *lacp_rate; const char *lacp_rate;
const char *primary; const char *primary;
NMBondMode bond_mode; NMBondMode bond_mode;
guint i;
const NMUtilsNamedValue *n;
const char *value;
g_hash_table_iter_init (&iter, priv->options); _ensure_options_idx_cache (priv);
while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) {
if (!value[0] || !nm_setting_bond_validate_option (key, value)) { if (priv->options_idx_cache) {
g_set_error (error, for (i = 0; priv->options_idx_cache[i].name; i++) {
NM_CONNECTION_ERROR, n = &priv->options_idx_cache[i];
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("invalid option '%s' or its value '%s'"), if ( !n->value_str
key, value); || !nm_setting_bond_validate_option (n->name, n->value_str)) {
g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); g_set_error (error,
return FALSE; NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("invalid option '%s' or its value '%s'"),
n->name, n->value_str);
g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
return FALSE;
}
} }
} }
@@ -841,16 +858,14 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
/* normalize unsupported options for the current mode */ /* normalize unsupported options for the current mode */
bond_mode = _nm_setting_bond_mode_from_string (mode_new); bond_mode = _nm_setting_bond_mode_from_string (mode_new);
g_hash_table_iter_init (&iter, priv->options); for (i = 0; priv->options_idx_cache[i].name; i++) {
while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL)) { n = &priv->options_idx_cache[i];
if (nm_streq (key, "mode")) if (!_nm_setting_bond_option_supported (n->name, bond_mode)) {
continue;
if (!_nm_setting_bond_option_supported (key, bond_mode)) {
g_set_error (error, g_set_error (error,
NM_CONNECTION_ERROR, NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("'%s' option is not valid with mode '%s'"), _("'%s' option is not valid with mode '%s'"),
key, mode_new); n->name, mode_new);
g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
return NM_SETTING_VERIFY_NORMALIZABLE; return NM_SETTING_VERIFY_NORMALIZABLE;
} }