diff options
-rw-r--r-- | cli/src/connections.c | 2 | ||||
-rw-r--r-- | libnm-util/libnm-util.ver | 15 | ||||
-rw-r--r-- | libnm-util/nm-setting-bond.c | 1370 | ||||
-rw-r--r-- | libnm-util/nm-setting-bond.h | 77 | ||||
-rw-r--r-- | libnm-util/tests/test-general.c | 2 | ||||
-rw-r--r-- | src/devices/nm-device-bond.c | 115 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/reader.c | 156 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 6 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/writer.c | 70 |
9 files changed, 1339 insertions, 474 deletions
diff --git a/cli/src/connections.c b/cli/src/connections.c index 8ae9ce3337..e5b5182309 100644 --- a/cli/src/connections.c +++ b/cli/src/connections.c @@ -3725,7 +3725,7 @@ cleanup_vlan: bond_primary); goto cleanup_bond; } - nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_PRIMARY, bond_primary); + g_object_set (s_bond, NM_SETTING_BOND_PRIMARY, bond_primary, NULL); } if (bond_miimon) nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_MIIMON, bond_miimon); diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index bcaa4260ae..6a1b2c810e 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -199,16 +199,29 @@ global: nm_setting_bond_add_option; nm_setting_bond_error_get_type; nm_setting_bond_error_quark; + nm_setting_bond_get_ad_select; + nm_setting_bond_get_arp_interval; + nm_setting_bond_get_arp_ip_target; + nm_setting_bond_get_arp_validate; + nm_setting_bond_get_downdelay; + nm_setting_bond_get_fail_over_mac; nm_setting_bond_get_interface_name; + nm_setting_bond_get_miimon; + nm_setting_bond_get_mode; nm_setting_bond_get_num_options; nm_setting_bond_get_option; nm_setting_bond_get_option_by_name; nm_setting_bond_get_option_default; + nm_setting_bond_get_primary; + nm_setting_bond_get_primary_reselect; + nm_setting_bond_get_resend_igmp; nm_setting_bond_get_type; + nm_setting_bond_get_updelay; + nm_setting_bond_get_use_carrier; nm_setting_bond_get_valid_options; + nm_setting_bond_get_xmit_hash_policy; nm_setting_bond_new; nm_setting_bond_remove_option; - nm_setting_bond_validate_option; nm_setting_bridge_error_get_type; nm_setting_bridge_error_quark; nm_setting_bridge_get_ageing_time; diff --git a/libnm-util/nm-setting-bond.c b/libnm-util/nm-setting-bond.c index 3fe5f51903..1177451a9f 100644 --- a/libnm-util/nm-setting-bond.c +++ b/libnm-util/nm-setting-bond.c @@ -34,6 +34,7 @@ #include "nm-utils.h" #include "nm-utils-private.h" #include "nm-dbus-glib-types.h" +#include "nm-glib-compat.h" #include "nm-setting-private.h" /** @@ -74,15 +75,48 @@ NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_BOND) typedef struct { char *interface_name; + char *mode; + guint miimon; + guint downdelay; + guint updelay; + guint arp_interval; + char **arp_ip_target; + char *arp_validate; + char *primary; + char *primary_reselect; + char *fail_over_mac; + char *ad_select; + char *xmit_hash_policy; + gboolean use_carrier; + guint resend_igmp; + GHashTable *options; } NMSettingBondPrivate; enum { PROP_0, PROP_INTERFACE_NAME, + + PROP_MODE, + PROP_MIIMON, + PROP_DOWNDELAY, + PROP_UPDELAY, + PROP_ARP_INTERVAL, + PROP_ARP_IP_TARGET, + PROP_ARP_VALIDATE, + PROP_PRIMARY, + PROP_PRIMARY_RESELECT, + PROP_FAIL_OVER_MAC, + PROP_USE_CARRIER, + PROP_AD_SELECT, + PROP_XMIT_HASH_POLICY, + PROP_RESEND_IGMP, + PROP_OPTIONS, LAST_PROP }; +#define _FIRST_LEGACY_PROP PROP_MODE +#define _LAST_LEGACY_PROP PROP_RESEND_IGMP enum { TYPE_INT, @@ -93,35 +127,34 @@ enum { }; typedef struct { - const char *opt; - const char *val; guint opt_type; - guint min; - guint max; - char *list[10]; -} BondDefault; - -static const BondDefault defaults[] = { - { NM_SETTING_BOND_OPTION_MODE, "balance-rr", TYPE_BOTH, 0, 6, - { "balance-rr", "active-backup", "balance-xor", "broadcast", "802.3ad", "balance-tlb", "balance-alb", NULL } }, - { NM_SETTING_BOND_OPTION_MIIMON, "100", TYPE_INT, 0, G_MAXINT }, - { NM_SETTING_BOND_OPTION_DOWNDELAY, "0", TYPE_INT, 0, G_MAXINT }, - { NM_SETTING_BOND_OPTION_UPDELAY, "0", TYPE_INT, 0, G_MAXINT }, - { NM_SETTING_BOND_OPTION_ARP_INTERVAL, "0", TYPE_INT, 0, G_MAXINT }, - { NM_SETTING_BOND_OPTION_ARP_IP_TARGET, "", TYPE_IP }, - { NM_SETTING_BOND_OPTION_ARP_VALIDATE, "0", TYPE_BOTH, 0, 3, - { "none", "active", "backup", "all", NULL } }, - { NM_SETTING_BOND_OPTION_PRIMARY, "", TYPE_IFNAME }, - { NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, "0", TYPE_BOTH, 0, 2, - { "always", "better", "failure", NULL } }, - { NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, "0", TYPE_BOTH, 0, 2, - { "none", "active", "follow", NULL } }, - { NM_SETTING_BOND_OPTION_USE_CARRIER, "1", TYPE_INT, 0, 1 }, - { NM_SETTING_BOND_OPTION_AD_SELECT, "0", TYPE_BOTH, 0, 2, - { "stable", "bandwidth", "count", NULL } }, - { NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, "0", TYPE_BOTH, 0, 2, - { "layer2", "layer3+4", "layer2+3", NULL } }, - { NM_SETTING_BOND_OPTION_RESEND_IGMP, "1", TYPE_INT, 0, 255 }, + const char *legacy_name; + const char *list[10]; + GParamSpec *pspec; + char *defval; +} BondProperty; + +static BondProperty props[ LAST_PROP + 1 ] = { + [PROP_MODE] = { TYPE_BOTH, NM_SETTING_BOND_OPTION_MODE, + { "balance-rr", "active-backup", "balance-xor", "broadcast", "802.3ad", "balance-tlb", "balance-alb" } }, + [PROP_MIIMON] = { TYPE_INT, NM_SETTING_BOND_OPTION_MIIMON }, + [PROP_DOWNDELAY] = { TYPE_INT, NM_SETTING_BOND_OPTION_DOWNDELAY }, + [PROP_UPDELAY] = { TYPE_INT, NM_SETTING_BOND_OPTION_UPDELAY }, + [PROP_ARP_INTERVAL] = { TYPE_INT, NM_SETTING_BOND_OPTION_ARP_INTERVAL }, + [PROP_ARP_IP_TARGET] = { TYPE_IP, NM_SETTING_BOND_OPTION_ARP_IP_TARGET }, + [PROP_ARP_VALIDATE] = { TYPE_BOTH, NULL, + { "none", "active", "backup", "all" } }, + [PROP_PRIMARY] = { TYPE_IFNAME, NULL }, + [PROP_PRIMARY_RESELECT] = { TYPE_BOTH, NULL, + { "always", "better", "failure" } }, + [PROP_FAIL_OVER_MAC] = { TYPE_BOTH, NULL, + { "none", "active", "follow" } }, + [PROP_USE_CARRIER] = { TYPE_INT }, + [PROP_AD_SELECT] = { TYPE_BOTH, NULL, + { "stable", "bandwidth", "count" } }, + [PROP_XMIT_HASH_POLICY] = { TYPE_STR, NULL, + { "layer2", "layer2+3", "layer3+4", "encap2+3", "encap3+4" } }, + [PROP_RESEND_IGMP] = { TYPE_INT }, }; /** @@ -137,6 +170,8 @@ nm_setting_bond_new (void) return (NMSetting *) g_object_new (NM_TYPE_SETTING_BOND, NULL); } +/*****************************************************************************/ + /** * nm_setting_bond_get_interface_name: * @setting: the #NMSettingBond @@ -152,21 +187,295 @@ nm_setting_bond_get_interface_name (NMSettingBond *setting) } /** + * nm_setting_bond_get_mode: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:mode property of the setting + * + * Since: 0.9.10 + **/ +const char * +nm_setting_bond_get_mode (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->mode; +} + +/** + * nm_setting_bond_get_miimon: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:miimon property of the setting + * + * Since: 0.9.10 + **/ +guint +nm_setting_bond_get_miimon (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), 0); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->miimon; +} + +/** + * nm_setting_bond_get_downdelay: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:downdelay property of the setting + * + * Since: 0.9.10 + **/ +guint +nm_setting_bond_get_downdelay (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), 0); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->downdelay; +} + +/** + * nm_setting_bond_get_updelay: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:updelay property of the setting + * + * Since: 0.9.10 + **/ +guint +nm_setting_bond_get_updelay (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), 0); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->updelay; +} + +/** + * nm_setting_bond_get_arp_interval: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:arp-interval property of the setting + * + * Since: 0.9.10 + **/ +guint +nm_setting_bond_get_arp_interval (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), 0); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->arp_interval; +} + +/** + * nm_setting_bond_get_arp_ip_target: + * @setting: the #NMSettingBond + * + * Returns: (transfer none): the #NMSettingBond:arp-ip-target property + * of the setting (which belongs to the setting and must not be freed). + * + * Since: 0.9.10 + **/ +const char *const* +nm_setting_bond_get_arp_ip_target (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + return (const char *const*) NM_SETTING_BOND_GET_PRIVATE (setting)->arp_ip_target; +} + +/** + * nm_setting_bond_get_arp_validate: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:arp-validate property of the setting + * + * Since: 0.9.10 + **/ +const char * +nm_setting_bond_get_arp_validate (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->arp_validate; +} + +/** + * nm_setting_bond_get_primary: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:primary property of the setting + * + * Since: 0.9.10 + **/ +const char * +nm_setting_bond_get_primary (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->primary; +} + +/** + * nm_setting_bond_get_primary_reselect: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:primary-reselect property of the setting + * + * Since: 0.9.10 + **/ +const char * +nm_setting_bond_get_primary_reselect (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->primary_reselect; +} + +/** + * nm_setting_bond_get_fail_over_mac: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:fail-over-mac property of the setting + * + * Since: 0.9.10 + **/ +const char * +nm_setting_bond_get_fail_over_mac (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->fail_over_mac; +} + +/** + * nm_setting_bond_get_use_carrier: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:use-carrier property of the setting + * + * Since: 0.9.10 + **/ +gboolean +nm_setting_bond_get_use_carrier (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->use_carrier; +} + +/** + * nm_setting_bond_get_ad_select: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:ad-select property of the setting + * + * Since: 0.9.10 + **/ +const char * +nm_setting_bond_get_ad_select (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->ad_select; +} + +/** + * nm_setting_bond_get_xmit_hash_policy: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:xmit-hash-policy property of the setting + * + * Since: 0.9.10 + **/ +const char * +nm_setting_bond_get_xmit_hash_policy (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->xmit_hash_policy; +} + +/** + * nm_setting_bond_get_resend_igmp: + * @setting: the #NMSettingBond + * + * Returns: the #NMSettingBond:resend-igmp property of the setting + * + * Since: 0.9.10 + **/ +guint +nm_setting_bond_get_resend_igmp (NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), 0); + + return NM_SETTING_BOND_GET_PRIVATE (setting)->resend_igmp; +} + +/*****************************************************************************/ + +static BondProperty * +find_property (const char *name, const char **out_new_name, guint *out_idx) +{ + guint i; + + g_return_val_if_fail (name != NULL, NULL); + + for (i = _FIRST_LEGACY_PROP; i <= _LAST_LEGACY_PROP; i++) { + const char *new_name = g_param_spec_get_name (props[i].pspec); + + if (strcmp (name, new_name) == 0 || g_strcmp0 (name, props[i].legacy_name) == 0) { + if (out_new_name) + *out_new_name = new_name; + if (out_idx) + *out_idx = i; + return &props[i]; + } + } + return NULL; +} + +/* For a new property or legacy option name, returns the new property name */ +static const char * +get_property_name (const char *name, const BondProperty **out_prop) +{ + const char *new_name = NULL; + + *out_prop = find_property (name, &new_name, NULL); + return *out_prop ? new_name : NULL; +} + +/* For a new property or legacy option name, returns the legacy option name */ +static const char * +get_legacy_name (GParamSpec *pspec) +{ + const BondProperty *prop; + const char *new_name = NULL; + + prop = find_property (g_param_spec_get_name (pspec), &new_name, NULL); + if (prop) + return prop->legacy_name ? prop->legacy_name : new_name; + + return NULL; +} + +/** * nm_setting_bond_get_num_options: * @setting: the #NMSettingBond * - * Returns the number of options that should be set for this bond when it - * is activated. This can be used to retrieve each option individually - * using nm_setting_bond_get_option(). + * Returns the number of options that are set in the legacy + * #NMSettingBond:options property. This does not include other bond + * properties which are not included in #NMSettingBond:options. + * + * Returns: the number of legacy bonding options * - * Returns: the number of bonding options + * Deprecated: use the option-specific getters instead. **/ guint32 nm_setting_bond_get_num_options (NMSettingBond *setting) { g_return_val_if_fail (NM_IS_SETTING_BOND (setting), 0); - return g_hash_table_size (NM_SETTING_BOND_GET_PRIVATE (setting)->options); + return _LAST_LEGACY_PROP - _FIRST_LEGACY_PROP; } /** @@ -188,6 +497,8 @@ nm_setting_bond_get_num_options (NMSettingBond *setting) * Returns: %TRUE on success if the index was valid and an option was found, * %FALSE if the index was invalid (ie, greater than the number of options * currently held by the setting) + * + * Deprecated: use the option-specific getters instead. **/ gboolean nm_setting_bond_get_option (NMSettingBond *setting, @@ -196,132 +507,173 @@ nm_setting_bond_get_option (NMSettingBond *setting, const char **out_value) { NMSettingBondPrivate *priv; - GList *keys; - const char *_key = NULL, *_value = NULL; + const char *legacy_name, *value; g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE); - priv = NM_SETTING_BOND_GET_PRIVATE (setting); - if (idx >= nm_setting_bond_get_num_options (setting)) - return FALSE; + idx += _FIRST_LEGACY_PROP; + g_return_val_if_fail (idx <= _LAST_LEGACY_PROP, FALSE); - keys = g_hash_table_get_keys (priv->options); - _key = g_list_nth_data (keys, idx); - _value = g_hash_table_lookup (priv->options, _key); + legacy_name = get_legacy_name (props[idx].pspec); + g_assert (legacy_name); + value = g_hash_table_lookup (priv->options, legacy_name); + if (!value) + return FALSE; if (out_name) - *out_name = _key; + *out_name = legacy_name; if (out_value) - *out_value = _value; - - g_list_free (keys); + *out_value = value; return TRUE; } static gboolean -validate_int (const char *name, const char *value, const BondDefault *def) +int_from_string (const char *s, glong *out_num) { - glong num; guint i; - for (i = 0; i < strlen (value); i++) { - if (!g_ascii_isdigit (value[i]) && value[i] != '-') + for (i = 0; i < strlen (s); i++) { + if (!g_ascii_isdigit (s[i]) && s[i] != '-') return FALSE; } errno = 0; - num = strtol (value, NULL, 10); - if (errno) + *out_num = strtol (s, NULL, 10); + return errno ? FALSE : TRUE; +} + +static gboolean +validate_int (const BondProperty *prop, const char *value) +{ + GParamSpecInt *ispec; + glong num = 0; + + if (!G_IS_PARAM_SPEC_INT (prop->pspec)) + return FALSE; + if (!value) return FALSE; - if (num < def->min || num > def->max) + if (!int_from_string (value, &num)) return FALSE; - return TRUE; + ispec = G_PARAM_SPEC_INT (prop->pspec); + return (num >= ispec->minimum && num <= ispec->maximum); } static gboolean -validate_list (const char *name, const char *value, const BondDefault *def) +validate_list (const BondProperty *prop, const char *value) { guint i; - for (i = 0; i < G_N_ELEMENTS (def->list) && def->list[i]; i++) { - if (g_strcmp0 (def->list[i], value) == 0) + if (!value) + return FALSE; + + for (i = 0; i < G_N_ELEMENTS (prop->list) && prop->list[i]; i++) { + if (g_strcmp0 (prop->list[i], value) == 0) return TRUE; } /* empty validation list means all values pass */ - return def->list[0] == NULL ? TRUE : FALSE; + return prop->list[0] == NULL ? TRUE : FALSE; } static gboolean -validate_ip (const char *name, const char *value) +validate_both (const BondProperty *prop, const char *value) +{ + glong num = -1; + + g_assert (prop->list); + + if (!value) + return FALSE; + + if (validate_list (prop, value)) + return TRUE; + + if (!int_from_string (value, &num)) + return FALSE; + + /* Ensure number is within bounds of string list */ + return num >= 0 && num < G_N_ELEMENTS (prop->list); +} + +static char ** +parse_ip (const char *value, gboolean warn_on_error) { char **ips, **iter; - gboolean success = TRUE; struct in_addr addr; - if (!value || !value[0]) - return FALSE; + if (!value || !value[0]) { + /* missing value is valid, we just NULL instead of an empty array. */ + return NULL; + } ips = g_strsplit_set (value, ",", 0); - for (iter = ips; iter && *iter && success; iter++) - success = !!inet_aton (*iter, &addr); - g_strfreev (ips); - - return success; + for (iter = ips; *iter; iter++) { + if (!inet_aton (*iter, &addr)) { + g_strfreev (ips); + g_return_val_if_fail (!warn_on_error, NULL); + return NULL; + } + } + return ips; } static gboolean -validate_ifname (const char *name, const char *value) +validate_ip (const char *value) { - if (!value || !value[0]) + char **ips; + + if (!value || !value[0]) { + /* there is only one TYPE_IP, and that property is not mandatory. + * Accept empty as valid. + **/ + return TRUE; + } + + /* make reuse of parse_ip, as it should validate the input anyway. */ + ips = parse_ip (value, FALSE); + if (!ips) return FALSE; + g_strfreev (ips); + return TRUE; +} + +static gboolean +validate_ifname (const char *value) +{ + if (!value || !value[0]) { + /* there is only one TYPE_IFNAME, and that property is not mandatory. + * Accept empty as valid. + **/ + return TRUE; + } + return nm_utils_iface_valid_name (value); } -/** - * nm_setting_bond_validate_option: - * @name: the name of the option to validate - * @value: the value of the option to validate - * - * Checks whether @name is a valid bond option and @value is a valid value for - * the @name. If @value is NULL, the function only validates the option name. +/* Checks whether @value is is a valid value for @prop. * * Returns: TRUE, if the @value is valid for the given name. - * If the @name is not a valid option, FALSE will be returned. - * - * Since: 0.9.10 + * If @value is NULL, false will be returned. **/ -gboolean -nm_setting_bond_validate_option (const char *name, - const char *value) +static gboolean +validate_property (const BondProperty *prop, const char *value) { - guint i; - - if (!name || !name[0]) - return FALSE; - - for (i = 0; i < G_N_ELEMENTS (defaults); i++) { - if (g_strcmp0 (defaults[i].opt, name) == 0) { - if (value == NULL) - return TRUE; - switch (defaults[i].opt_type) { - case TYPE_INT: - return validate_int (name, value, &defaults[i]); - case TYPE_STR: - return validate_list (name, value, &defaults[i]); - case TYPE_BOTH: - return validate_int (name, value, &defaults[i]) - || validate_list (name, value, &defaults[i]); - case TYPE_IP: - return validate_ip (name, value); - case TYPE_IFNAME: - return validate_ifname (name, value); - } - return FALSE; - } + switch (prop->opt_type) { + case TYPE_INT: + return validate_int (prop, value); + case TYPE_STR: + return validate_list (prop, value); + case TYPE_BOTH: + return validate_both (prop, value); + case TYPE_IP: + return validate_ip (value); + case TYPE_IFNAME: + return validate_ifname (value); + default: + g_assert_not_reached(); } return FALSE; } @@ -336,6 +688,8 @@ nm_setting_bond_validate_option (const char *name, * * Returns: the value, or %NULL if the key/value pair was never added to the * setting; the value is owned by the setting and must not be modified + * + * Deprecated: use the option-specific getters instead. **/ const char * nm_setting_bond_get_option_by_name (NMSettingBond *setting, @@ -343,9 +697,6 @@ nm_setting_bond_get_option_by_name (NMSettingBond *setting, { g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); - if (!nm_setting_bond_validate_option (name, NULL)) - return NULL; - return g_hash_table_lookup (NM_SETTING_BOND_GET_PRIVATE (setting)->options, name); } @@ -365,6 +716,8 @@ nm_setting_bond_get_option_by_name (NMSettingBond *setting, * * Returns: %TRUE if the option was valid and was added to the internal option * list, %FALSE if it was not. + * + * Deprecated: use the option-specific properties instead. **/ gboolean nm_setting_bond_add_option (NMSettingBond *setting, @@ -372,28 +725,60 @@ nm_setting_bond_add_option (NMSettingBond *setting, const char *value) { NMSettingBondPrivate *priv; + GObject *object = G_OBJECT (setting); + const BondProperty *prop = NULL; + const char *prop_name; + glong num = 0; g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE); - if (!value || !nm_setting_bond_validate_option (name, value)) + priv = NM_SETTING_BOND_GET_PRIVATE (setting); + + prop_name = get_property_name (name, &prop); + if (!prop_name) + return FALSE; + if (!validate_property (prop, value)) return FALSE; - priv = NM_SETTING_BOND_GET_PRIVATE (setting); + g_object_freeze_notify (object); - g_hash_table_insert (priv->options, g_strdup (name), g_strdup (value)); + switch (prop->opt_type) { + case TYPE_INT: + if (!int_from_string (value, &num)) + return FALSE; + g_object_set (object, prop_name, (gint) num, NULL); + break; + case TYPE_BOTH: { + const char *str_value = value; - if ( !strcmp (name, NM_SETTING_BOND_OPTION_MIIMON) - && strcmp (value, "0") != 0) { - g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - } else if ( !strcmp (name, NM_SETTING_BOND_OPTION_ARP_INTERVAL) - && strcmp (value, "0") != 0) { - g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_MIIMON); - g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_DOWNDELAY); - g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_UPDELAY); + /* Might be an integer-as-string; find the string */ + if (!validate_list (prop, value)) { + if (!int_from_string (value, &num)) + return FALSE; + /* Be paranoid although it's already been checked by validate_property() */ + g_assert (num >= 0 && num < G_N_ELEMENTS (prop->list)); + str_value = prop->list[num]; + } + g_object_set (object, prop_name, str_value, NULL); + break; } + case TYPE_IFNAME: + case TYPE_STR: + g_object_set (object, prop_name, value, NULL); + break; + case TYPE_IP: { + char **ip = parse_ip (value, TRUE); - g_object_notify (G_OBJECT (setting), NM_SETTING_BOND_OPTIONS); + g_object_set (object, prop_name, ip, NULL); + g_strfreev (ip); + break; + } + default: + g_assert_not_reached (); + break; + } + + g_object_thaw_notify (object); return TRUE; } @@ -408,22 +793,36 @@ nm_setting_bond_add_option (NMSettingBond *setting, * * Returns: %TRUE if the option was found and removed from the internal option * list, %FALSE if it was not. + * + * Deprecated: use the option-specific properties instead. **/ gboolean nm_setting_bond_remove_option (NMSettingBond *setting, const char *name) { - gboolean found; + GObject *object = G_OBJECT (setting); + NMSettingBondPrivate *priv; + const BondProperty *prop; + const char *prop_name; + GValue defval = G_VALUE_INIT; g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE); + priv = NM_SETTING_BOND_GET_PRIVATE (setting); - if (!nm_setting_bond_validate_option (name, NULL)) + prop_name = get_property_name (name, &prop); + if (!prop_name) return FALSE; - found = g_hash_table_remove (NM_SETTING_BOND_GET_PRIVATE (setting)->options, name); - if (found) - g_object_notify (G_OBJECT (setting), NM_SETTING_BOND_OPTIONS); - return found; + g_object_freeze_notify (object); + + /* we don't really remove the property, instead we reset the default value. */ + g_value_init (&defval, prop->pspec->value_type); + g_param_value_set_default (prop->pspec, &defval); + g_object_set_property (object, prop_name, &defval); + g_value_unset (&defval); + + g_object_thaw_notify (object); + return TRUE; } /** @@ -433,19 +832,25 @@ nm_setting_bond_remove_option (NMSettingBond *setting, * Returns a list of valid bond options. * * Returns: (transfer none): a %NULL-terminated array of strings of valid bond options. + * + * Deprecated: the valid options are defined by the #NMSettingBond + * properties. **/ const char ** nm_setting_bond_get_valid_options (NMSettingBond *setting) { - static const char *array[G_N_ELEMENTS (defaults) + 1] = { NULL }; - int i; + static const char *array[LAST_PROP + 1] = { NULL }; /* initialize the array once */ if (G_UNLIKELY (array[0] == NULL)) { - for (i = 0; i < G_N_ELEMENTS (defaults); i++) - array[i] = defaults[i].opt; - array[i] = NULL; + guint prop, i; + + for (prop = _FIRST_LEGACY_PROP, i = 0; prop <= _LAST_LEGACY_PROP; prop++, i++) { + array[i] = props[prop].legacy_name ? + props[prop].legacy_name : g_param_spec_get_name (props[prop].pspec); + } } + return array; } @@ -456,42 +861,77 @@ nm_setting_bond_get_valid_options (NMSettingBond *setting) * * Returns: the value of the bond option if not overridden by an entry in * the #NMSettingBond:options property. + * + * Deprecated: Use the default values of the option-specific properties. **/ const char * nm_setting_bond_get_option_default (NMSettingBond *setting, const char *name) { - guint i; + BondProperty *prop; + GValue defval = G_VALUE_INIT; + guint idx = 0; g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); - g_return_val_if_fail (nm_setting_bond_validate_option (name, NULL), NULL); - for (i = 0; i < G_N_ELEMENTS (defaults); i++) { - if (g_strcmp0 (defaults[i].opt, name) == 0) - return defaults[i].val; + prop = find_property (name, NULL, &idx); + if (!prop) + return NULL; + + if (G_UNLIKELY (prop->defval == NULL)) { + if (idx == PROP_ARP_IP_TARGET) + prop->defval = ""; + else { + g_value_init (&defval, prop->pspec->value_type); + g_param_value_set_default (prop->pspec, &defval); + prop->defval = g_strdup_value_contents (&defval); + g_value_unset (&defval); + } + } + return prop->defval; +} + +/*****************************************************************/ + +static void +set_properties_from_hash (NMSettingBond *self, GHashTable *options) +{ + const char *value; + guint i; + + g_object_freeze_notify (G_OBJECT (self)); + + /* Set each property to the value given by @options, or if not present + * in @options, to the default value. + */ + for (i = _FIRST_LEGACY_PROP; i <= _LAST_LEGACY_PROP; i++) { + const char *new_name = g_param_spec_get_name (props[i].pspec); + const char *legacy_name = new_name; + GValue defval = G_VALUE_INIT; + + value = g_hash_table_lookup (options, legacy_name); + if (!value) + legacy_name = props[i].legacy_name; + value = g_hash_table_lookup (options, legacy_name); + + if (value) + nm_setting_bond_add_option (self, legacy_name, value); + else { + g_value_init (&defval, props[i].pspec->value_type); + g_param_value_set_default (props[i].pspec, &defval); + g_object_set_property (G_OBJECT (self), new_name, &defval); + g_value_unset (&defval); + } } - /* Any option that passes nm_setting_bond_validate_option() should also be found in defaults */ - g_assert_not_reached (); + + g_object_thaw_notify (G_OBJECT (self)); } static gboolean verify (NMSetting *setting, GSList *all_settings, GError **error) { NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting); - GHashTableIter iter; - const char *key, *value; - const char *valid_modes[] = { "balance-rr", - "active-backup", - "balance-xor", - "broadcast", - "802.3ad", - "balance-tlb", - "balance-alb", - NULL }; - int miimon = 0, arp_interval = 0; - const char *arp_ip_target = NULL; - const char *primary; - - if (!priv->interface_name || !strlen(priv->interface_name)) { + + if (!priv->interface_name || !strlen (priv->interface_name)) { g_set_error_literal (error, NM_SETTING_BOND_ERROR, NM_SETTING_BOND_ERROR_MISSING_PROPERTY, @@ -499,7 +939,6 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_INTERFACE_NAME); return FALSE; } - if (!nm_utils_iface_valid_name (priv->interface_name)) { g_set_error_literal (error, NM_SETTING_BOND_ERROR, @@ -509,185 +948,215 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } - g_hash_table_iter_init (&iter, priv->options); - while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) { - if (!value[0] || !nm_setting_bond_validate_option (key, value)) { - g_set_error (error, - NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, - _("invalid option '%s' or its value '%s'"), - key, value); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); - return FALSE; - } - } - - value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_MIIMON); - if (value) - miimon = atoi (value); - value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - if (value) - arp_interval = atoi (value); - /* Can only set one of miimon and arp_interval */ - if (miimon > 0 && arp_interval > 0) { + if (priv->miimon > 0 && priv->arp_interval > 0) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, _("only one of '%s' and '%s' can be set"), NM_SETTING_BOND_OPTION_MIIMON, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - 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, + priv->arp_ip_target == NULL && priv->arp_ip_target[0] ? NM_SETTING_BOND_ARP_INTERVAL : NM_SETTING_BOND_MIIMON); } - value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_MODE); - if (!value) { + if (!priv->mode) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_MISSING_OPTION, - _("mandatory option '%s' is missing"), - NM_SETTING_BOND_OPTION_MODE); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_ERROR_MISSING_PROPERTY, + _("mandatory property '%s' is missing"), + NM_SETTING_BOND_MODE); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_MODE); return FALSE; } - if (!_nm_utils_string_in_list (value, valid_modes)) { + if (!validate_property (&props[PROP_MODE], priv->mode)) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, _("'%s' is not a valid value for '%s'"), - value, NM_SETTING_BOND_OPTION_MODE); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + priv->mode, NM_SETTING_BOND_MODE); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_MODE); return FALSE; } /* Make sure mode is compatible with other settings */ - if ( strcmp (value, "balance-alb") == 0 - || strcmp (value, "balance-tlb") == 0) { - if (arp_interval > 0) { + if ( strcmp (priv->mode, "balance-alb") == 0 + || strcmp (priv->mode, "balance-tlb") == 0) { + if (priv->arp_interval > 0) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, _("'%s=%s' is incompatible with '%s > 0'"), - NM_SETTING_BOND_OPTION_MODE, value, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_OPTION_MODE, priv->mode, + NM_SETTING_BOND_OPTION_ARP_INTERVAL); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_ARP_INTERVAL); return FALSE; } } - primary = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_PRIMARY); - if (strcmp (value, "active-backup") == 0) { - if (primary && !nm_utils_iface_valid_name (primary)) { + if (strcmp (priv->mode, "active-backup") == 0) { + if (priv->primary && !nm_utils_iface_valid_name (priv->primary)) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, - _("'%s' is not a valid interface name for '%s' option"), - primary, NM_SETTING_BOND_OPTION_PRIMARY); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid interface name"), + priv->primary); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_PRIMARY); return FALSE; } } else { - if (primary) { + if (priv->primary) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, - _("'%s' option is only valid for '%s=%s'"), - NM_SETTING_BOND_OPTION_PRIMARY, - NM_SETTING_BOND_OPTION_MODE, "active-backup"); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is only valid for '%s=%s'"), + NM_SETTING_BOND_PRIMARY, + NM_SETTING_BOND_MODE, "active-backup"); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_PRIMARY); return FALSE; } } if (nm_setting_find_in_list (all_settings, NM_SETTING_INFINIBAND_SETTING_NAME)) { - if (strcmp (value, "active-backup") != 0) { + if (strcmp (priv->mode, "active-backup") != 0) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, _("'%s=%s' is not a valid configuration for '%s'"), - NM_SETTING_BOND_OPTION_MODE, value, NM_SETTING_INFINIBAND_SETTING_NAME); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_OPTION_MODE, priv->mode, + NM_SETTING_INFINIBAND_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_MODE); return FALSE; } } - if (miimon == 0) { + if (priv->miimon == 0) { /* updelay and downdelay can only be used with miimon */ - if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_UPDELAY)) { + if (priv->updelay > 0) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, - _("'%s' option requires '%s' option to be set"), - NM_SETTING_BOND_OPTION_UPDELAY, NM_SETTING_BOND_OPTION_MIIMON); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' property requires '%s' property to be set"), + NM_SETTING_BOND_UPDELAY, NM_SETTING_BOND_MIIMON); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_UPDELAY); return FALSE; } - if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_DOWNDELAY)) { + if (priv->downdelay > 0) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, - _("'%s' option requires '%s' option to be set"), - NM_SETTING_BOND_OPTION_DOWNDELAY, NM_SETTING_BOND_OPTION_MIIMON); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' property requires '%s' property to be set"), + NM_SETTING_BOND_DOWNDELAY, NM_SETTING_BOND_MIIMON); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_DOWNDELAY); return FALSE; } } /* arp_ip_target can only be used with arp_interval, and must - * contain a comma-separated list of IPv4 addresses. + * contain IPv4 addresses. */ - arp_ip_target = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - if (arp_interval > 0) { - char **addrs; + if (priv->arp_interval > 0) { guint32 addr; int i; - if (!arp_ip_target) { + if (!priv->arp_ip_target) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_MISSING_OPTION, - _("'%s' option requires '%s' option to be set"), - NM_SETTING_BOND_OPTION_ARP_INTERVAL, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_ERROR_MISSING_PROPERTY, + _("'%s' property requires '%s' property to be set"), + NM_SETTING_BOND_ARP_INTERVAL, NM_SETTING_BOND_ARP_IP_TARGET); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_ARP_IP_TARGET); return FALSE; } - addrs = g_strsplit (arp_ip_target, ",", -1); - if (!addrs[0]) { + if (!priv->arp_ip_target[0]) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, - _("'%s' option is empty"), - NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); - g_strfreev (addrs); + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' property is empty"), + NM_SETTING_BOND_ARP_IP_TARGET); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_ARP_IP_TARGET); return FALSE; } - for (i = 0; addrs[i]; i++) { - if (!inet_pton (AF_INET, addrs[i], &addr)) { + for (i = 0; priv->arp_ip_target[i]; i++) { + if (!inet_pton (AF_INET, priv->arp_ip_target[i], &addr)) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, - _("'%s' is not a valid IPv4 address for '%s' option"), - NM_SETTING_BOND_OPTION_ARP_IP_TARGET, addrs[i]); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); - g_strfreev (addrs); + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid IPv4 address for '%s' property"), + priv->arp_ip_target[i], NM_SETTING_BOND_ARP_IP_TARGET); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_ARP_IP_TARGET); return FALSE; } } - g_strfreev (addrs); } else { - if (arp_ip_target) { + if (priv->arp_ip_target && priv->arp_ip_target[0]) { g_set_error (error, NM_SETTING_BOND_ERROR, - NM_SETTING_BOND_ERROR_INVALID_OPTION, - _("'%s' option requires '%s' option to be set"), - NM_SETTING_BOND_OPTION_ARP_IP_TARGET, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' property requires '%s' property to be set"), + NM_SETTING_BOND_ARP_IP_TARGET, NM_SETTING_BOND_ARP_INTERVAL); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_ARP_IP_TARGET); return FALSE; } } + /* FIXME: maybe we should not be too excessively about validating the strings, + * because the kernel might add new values (which we would then not support). + * OTOH, the checking above already requires some deep knowledge about the exact + * meaning of the flags, so, why check there, but not here? + **/ + if (priv->arp_validate && !validate_property (&props[PROP_ARP_VALIDATE], priv->arp_validate)) { + g_set_error (error, + NM_SETTING_BOND_ERROR, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for '%s'"), + priv->arp_validate, NM_SETTING_BOND_ARP_VALIDATE); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_ARP_VALIDATE); + return FALSE; + } + + if (priv->primary_reselect && !validate_property (&props[PROP_PRIMARY_RESELECT], priv->primary_reselect)) { + g_set_error (error, + NM_SETTING_BOND_ERROR, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for '%s'"), + priv->primary_reselect, NM_SETTING_BOND_PRIMARY_RESELECT); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_PRIMARY_RESELECT); + return FALSE; + } + + if (priv->fail_over_mac && !validate_property (&props[PROP_FAIL_OVER_MAC], priv->fail_over_mac)) { + g_set_error (error, + NM_SETTING_BOND_ERROR, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for '%s'"), + priv->fail_over_mac, NM_SETTING_BOND_FAIL_OVER_MAC); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_FAIL_OVER_MAC); + return FALSE; + } + + if (priv->ad_select && !validate_property (&props[PROP_FAIL_OVER_MAC], priv->ad_select)) { + g_set_error (error, + NM_SETTING_BOND_ERROR, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for '%s'"), + priv->ad_select, NM_SETTING_BOND_AD_SELECT); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_AD_SELECT); + return FALSE; + } + + if (priv->xmit_hash_policy && !validate_property (&props[PROP_FAIL_OVER_MAC], priv->xmit_hash_policy)) { + g_set_error (error, + NM_SETTING_BOND_ERROR, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for '%s'"), + priv->xmit_hash_policy, NM_SETTING_BOND_XMIT_HASH_POLICY); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_XMIT_HASH_POLICY); + return FALSE; + } + return TRUE; } @@ -704,13 +1173,9 @@ nm_setting_bond_init (NMSettingBond *setting) { NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting); - g_object_set (setting, NM_SETTING_NAME, NM_SETTING_BOND_SETTING_NAME, - NULL); + g_object_set (setting, NM_SETTING_NAME, NM_SETTING_BOND_SETTING_NAME, NULL); priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - - /* Default values: */ - nm_setting_bond_add_option (setting, NM_SETTING_BOND_OPTION_MODE, "balance-rr"); } static void @@ -719,52 +1184,159 @@ finalize (GObject *object) NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (object); g_free (priv->interface_name); + g_free (priv->mode); + g_free (priv->primary); + g_strfreev (priv->arp_ip_target); g_hash_table_destroy (priv->options); G_OBJECT_CLASS (nm_setting_bond_parent_class)->finalize (object); } static void -copy_hash (gpointer key, gpointer value, gpointer user_data) -{ - g_hash_table_insert ((GHashTable *) user_data, g_strdup (key), g_strdup (value)); -} - -static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + NMSettingBond *setting = NM_SETTING_BOND (object); NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (object); - GHashTable *new_hash; + const char *legacy_name = get_legacy_name (pspec); + char *legacy_value = NULL; switch (prop_id) { case PROP_INTERFACE_NAME: + g_free (priv->interface_name); priv->interface_name = g_value_dup_string (value); break; + case PROP_MODE: + g_free (priv->mode); + priv->mode = g_value_dup_string (value); + legacy_value = g_value_dup_string (value); + break; + case PROP_MIIMON: + priv->miimon = g_value_get_int (value); + legacy_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; + case PROP_DOWNDELAY: + priv->downdelay = g_value_get_int (value); + legacy_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; + case PROP_UPDELAY: + priv->updelay = g_value_get_int (value); + legacy_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; + case PROP_ARP_INTERVAL: + priv->arp_interval = g_value_get_int (value); + legacy_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; + case PROP_ARP_IP_TARGET: + g_strfreev (priv->arp_ip_target); + priv->arp_ip_target = g_value_dup_boxed (value); + legacy_value = priv->arp_ip_target ? g_strjoinv (",", priv->arp_ip_target) : g_strdup (""); + break; + case PROP_ARP_VALIDATE: + g_free (priv->arp_validate); + priv->arp_validate = g_value_dup_string (value); + legacy_value = g_value_dup_string (value); + break; + case PROP_PRIMARY: + g_free (priv->primary); + priv->primary = g_value_dup_string (value); + legacy_value = g_value_dup_string (value); + break; + case PROP_PRIMARY_RESELECT: + g_free (priv->primary_reselect); + priv->primary_reselect = g_value_dup_string (value); + legacy_value = g_value_dup_string (value); + break; + case PROP_FAIL_OVER_MAC: + g_free (priv->fail_over_mac); + priv->fail_over_mac = g_value_dup_string (value); + legacy_value = g_value_dup_string (value); + break; + case PROP_USE_CARRIER: + priv->use_carrier = g_value_get_int (value); + legacy_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; + case PROP_AD_SELECT: + g_free (priv->ad_select); + priv->ad_select = g_value_dup_string (value); + legacy_value = g_value_dup_string (value); + break; + case PROP_XMIT_HASH_POLICY: + g_free (priv->xmit_hash_policy); + priv->xmit_hash_policy = g_value_dup_string (value); + legacy_value = g_value_dup_string (value); + break; + case PROP_RESEND_IGMP: + priv->resend_igmp = g_value_get_int (value); + legacy_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; case PROP_OPTIONS: - /* Must make a deep copy of the hash table here... */ - g_hash_table_remove_all (priv->options); - new_hash = g_value_get_boxed (value); - if (new_hash) - g_hash_table_foreach (new_hash, copy_hash, priv->options); + set_properties_from_hash (setting, g_value_get_boxed (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } + + if (legacy_value) { + g_hash_table_insert (priv->options, g_strdup (legacy_name), legacy_value); + g_object_notify (object, NM_SETTING_BOND_OPTIONS); + } } static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (object); NMSettingBond *setting = NM_SETTING_BOND (object); + NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (object); switch (prop_id) { case PROP_INTERFACE_NAME: g_value_set_string (value, nm_setting_bond_get_interface_name (setting)); break; + case PROP_MODE: + g_value_set_string (value, nm_setting_bond_get_mode (setting)); + break; + case PROP_MIIMON: + g_value_set_int (value, nm_setting_bond_get_miimon (setting)); + break; + case PROP_DOWNDELAY: + g_value_set_int (value, nm_setting_bond_get_downdelay (setting)); + break; + case PROP_UPDELAY: + g_value_set_int (value, nm_setting_bond_get_updelay (setting)); + break; + case PROP_ARP_INTERVAL: + g_value_set_int (value, nm_setting_bond_get_arp_interval (setting)); + break; + case PROP_ARP_IP_TARGET: + g_value_set_boxed (value, nm_setting_bond_get_arp_ip_target (setting)); + break; + case PROP_ARP_VALIDATE: + g_value_set_string (value, nm_setting_bond_get_arp_validate (setting)); + break; + case PROP_PRIMARY: + g_value_set_string (value, nm_setting_bond_get_primary (setting)); + break; + case PROP_PRIMARY_RESELECT: + g_value_set_string (value, nm_setting_bond_get_primary_reselect (setting)); + break; + case PROP_FAIL_OVER_MAC: + g_value_set_string (value, nm_setting_bond_get_fail_over_mac (setting)); + break; + case PROP_USE_CARRIER: + g_value_set_int (value, nm_setting_bond_get_use_carrier (setting)); + break; + case PROP_AD_SELECT: + g_value_set_string (value, nm_setting_bond_get_ad_select (setting)); + break; + case PROP_XMIT_HASH_POLICY: + g_value_set_string (value, nm_setting_bond_get_xmit_hash_policy (setting)); + break; + case PROP_RESEND_IGMP: + g_value_set_int (value, nm_setting_bond_get_resend_igmp (setting)); + break; case PROP_OPTIONS: g_value_set_boxed (value, priv->options); break; @@ -779,6 +1351,7 @@ nm_setting_bond_class_init (NMSettingBondClass *setting_class) { GObjectClass *object_class = G_OBJECT_CLASS (setting_class); NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + guint i; g_type_class_add_private (setting_class, sizeof (NMSettingBondPrivate)); @@ -795,29 +1368,252 @@ nm_setting_bond_class_init (NMSettingBondClass *setting_class) * * The name of the virtual in-kernel bonding network interface **/ - g_object_class_install_property - (object_class, PROP_INTERFACE_NAME, - g_param_spec_string (NM_SETTING_BOND_INTERFACE_NAME, - "InterfaceName", - "The name of the virtual in-kernel bonding network interface", - NULL, - G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + props[PROP_INTERFACE_NAME].pspec = + g_param_spec_string (NM_SETTING_BOND_INTERFACE_NAME, + "InterfaceName", + "The name of the virtual in-kernel bonding network interface", + NULL, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:mode: + * + * The bonding mode. One of 'balance-rr', 'active-backup', + * 'balance-xor', 'broadcast', '802.3ad', 'balance-tlb', or + * 'balance-alb'. + **/ + props[PROP_MODE].pspec = + g_param_spec_string (NM_SETTING_BOND_MODE, + "Mode", + "The bonding mode", + "balance-rr", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:miimon: + * + * The MII link monitoring frequency, in milliseconds. Either this + * or #NMSettingBond:arp-interval should be set, and they can't + * both be set. + * + * Since: 0.9.10 + **/ + props[PROP_MIIMON].pspec = + g_param_spec_int (NM_SETTING_BOND_MIIMON, + "miimon", + "The MII link monitoring frequence", + 0, G_MAXINT, 100, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:downdelay: + * + * The time, in milliseconds, to wait before disabling a slave + * after it goes down. Only valid if #NMSettingBond:miimon is + * non-0. + * + * Since: 0.9.10 + **/ + props[PROP_DOWNDELAY].pspec = + g_param_spec_int (NM_SETTING_BOND_DOWNDELAY, + "downdelay", + "downdelay", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:updelay: + * + * The time, in milliseconds, to wait before enabling a slave + * after it comes up. Only valid if #NMSettingBond:miimon is + * non-0. + * + * Since: 0.9.10 + **/ + props[PROP_UPDELAY].pspec = + g_param_spec_int (NM_SETTING_BOND_UPDELAY, + "updelay", + "updelay", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:arp-interval: + * + * The ARP-based link monitoring frequency, in milliseconds. + * Either this or #NMSettingBond:miimon should be set, and they + * can't both be set. + * + * Since: 0.9.10 + **/ + props[PROP_ARP_INTERVAL].pspec = + g_param_spec_int (NM_SETTING_BOND_ARP_INTERVAL, + "ARP interval", + "The ARP-based link monitoring frequence", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:arp-ip-target: + * + * An array of IPv4 addresses to ping when using ARP-based link monitoring. + * This only has an effect when #NMSettingBond:arp-interval is also set. + * + * Since: 0.9.10 + **/ + props[PROP_ARP_IP_TARGET].pspec = + g_param_spec_boxed (NM_SETTING_BOND_ARP_IP_TARGET, + "ARP IP target", + "ARP monitoring target IP addresses", + G_TYPE_STRV, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:arp-validate: + * + * Specifies whether or not ARP probes and replies should be + * validated in the active-backup mode. One of + * 'none', 'active', 'backup', 'all'. + * + * Since: 0.9.10 + **/ + props[PROP_ARP_VALIDATE].pspec = + g_param_spec_string (NM_SETTING_BOND_ARP_VALIDATE, + "arp-validate", + "Specifies whether or not ARP probes and replies should " + "be validate in the active-backup mode", + "none", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:primary: + * + * The primary interface to use in 'active-backup' mode. + **/ + props[PROP_PRIMARY].pspec = + g_param_spec_string (NM_SETTING_BOND_PRIMARY, + "Primary", + "The primary interface", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:primary-reselect: + * + * Specifies the reselection policy for the primary slave. + * One of 'always', 'better', 'failure'. + * + * Since: 0.9.10 + **/ + props[PROP_PRIMARY_RESELECT].pspec = + g_param_spec_string (NM_SETTING_BOND_PRIMARY_RESELECT, + "primary-reselect", + "Specifies the reselection policy for the primary slave", + "always", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:fail-over-mac: + * + * Specifies whether active-backup mode should set all slaves to + * the same MAC address at enslavement (the traditional + * behavior), or, when enabled, perform special handling of the + * bond's MAC address in accordance with the selected policy. + * One of 'none', 'active', 'follow'. + * + * Since: 0.9.10 + **/ + props[PROP_FAIL_OVER_MAC].pspec = + g_param_spec_string (NM_SETTING_BOND_FAIL_OVER_MAC, + "fail-over-mac", + "fail_over_mac", + "none", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:use-carrier: + * + * Specifies whether or not miimon should use MII or ETHTOOL + * ioctls vs. netif_carrier_ok() to determine the link + * status. + * + * Since: 0.9.10 + **/ + props[PROP_USE_CARRIER].pspec = + g_param_spec_int (NM_SETTING_BOND_USE_CARRIER, + "use-carrier", + "use_carrier", + 0, 1, 1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:ad-select: + * + * Specifies the 802.3ad aggregation selection logic to use. + * One of 'stable', 'bandwidth', or 'count'. + **/ + props[PROP_AD_SELECT].pspec = + g_param_spec_string (NM_SETTING_BOND_AD_SELECT, + "ad-select", + "ad_select", + "stable", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:xmit-hash-policy: + * + * Selects the transmit hash policy to use for slave selection in + * balance-xor and 802.3ad modes. One of 'layer2', 'layer2+3', + * 'layer3+4', 'encap2+3', or 'encap3+4'. + * + **/ + props[PROP_XMIT_HASH_POLICY].pspec = + g_param_spec_string (NM_SETTING_BOND_XMIT_HASH_POLICY, + "xmit-hash-policy", + "xmit_hash_policy", + "layer2", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); + + /** + * NMSettingBond:resend-igmp: + * + * Specifies the number of IGMP membership reports to be issued after + * a failover event. One membership report is issued immediately after + * the failover, subsequent packets are sent in each 200ms interval. + * + * The valid range is 0 - 255; the default value is 1. A value of 0 + * prevents the IGMP membership report from being issued in response + * to the failover event. + * + * Since: 0.9.10 + **/ + props[PROP_RESEND_IGMP].pspec = + g_param_spec_int (NM_SETTING_BOND_RESEND_IGMP, + "resend-igmp", + "resend_igmp", + 0, 255, 1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE); /** * NMSettingBond:options: * * Dictionary of key/value pairs of bonding options. Both keys * and values must be strings. Option names must contain only - * alphanumeric characters (ie, [a-zA-Z0-9]). + * alphanumeric characters (ie, [a-zA-Z0-9_). + * + * Deprecated: use the specific properties **/ - g_object_class_install_property - (object_class, PROP_OPTIONS, - _nm_param_spec_specialized (NM_SETTING_BOND_OPTIONS, - "Options", - "Dictionary of key/value pairs of bonding " - "options. Both keys and values must be " - "strings. Option names must contain only " - "alphanumeric characters (ie, [a-zA-Z0-9]).", - DBUS_TYPE_G_MAP_OF_STRING, - G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + props[PROP_OPTIONS].pspec = + _nm_param_spec_specialized (NM_SETTING_BOND_OPTIONS, + "Options", + "Dictionary of key/value pairs of bonding " + "options. Both keys and values must be " + "strings. Option names must contain only " + "alphanumeric characters (ie, [a-zA-Z0-9_]).", + DBUS_TYPE_G_MAP_OF_STRING, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE); + + /* Skip PROP_0 */ + for (i = 1; i < LAST_PROP; i++) + g_object_class_install_property (object_class, i, props[i].pspec); } diff --git a/libnm-util/nm-setting-bond.h b/libnm-util/nm-setting-bond.h index 383e0eadb3..5a5676a053 100644 --- a/libnm-util/nm-setting-bond.h +++ b/libnm-util/nm-setting-bond.h @@ -55,24 +55,41 @@ typedef enum { #define NM_SETTING_BOND_ERROR nm_setting_bond_error_quark () GQuark nm_setting_bond_error_quark (void); -#define NM_SETTING_BOND_INTERFACE_NAME "interface-name" -#define NM_SETTING_BOND_OPTIONS "options" - -/* Valid options for the 'options' property */ -#define NM_SETTING_BOND_OPTION_MODE "mode" -#define NM_SETTING_BOND_OPTION_MIIMON "miimon" -#define NM_SETTING_BOND_OPTION_DOWNDELAY "downdelay" -#define NM_SETTING_BOND_OPTION_UPDELAY "updelay" -#define NM_SETTING_BOND_OPTION_ARP_INTERVAL "arp_interval" -#define NM_SETTING_BOND_OPTION_ARP_IP_TARGET "arp_ip_target" -#define NM_SETTING_BOND_OPTION_ARP_VALIDATE "arp_validate" -#define NM_SETTING_BOND_OPTION_PRIMARY "primary" -#define NM_SETTING_BOND_OPTION_PRIMARY_RESELECT "primary_reselect" -#define NM_SETTING_BOND_OPTION_FAIL_OVER_MAC "fail_over_mac" -#define NM_SETTING_BOND_OPTION_USE_CARRIER "use_carrier" -#define NM_SETTING_BOND_OPTION_AD_SELECT "ad_select" -#define NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY "xmit_hash_policy" -#define NM_SETTING_BOND_OPTION_RESEND_IGMP "resend_igmp" +#define NM_SETTING_BOND_INTERFACE_NAME "interface-name" +#define NM_SETTING_BOND_MODE "mode" +#define NM_SETTING_BOND_PRIMARY "primary" +#define NM_SETTING_BOND_MIIMON "miimon" +#define NM_SETTING_BOND_DOWNDELAY "downdelay" +#define NM_SETTING_BOND_UPDELAY "updelay" +#define NM_SETTING_BOND_ARP_INTERVAL "arp-interval" +#define NM_SETTING_BOND_ARP_IP_TARGET "arp-ip-target" +#define NM_SETTING_BOND_ARP_VALIDATE "arp-validate" +#define NM_SETTING_BOND_PRIMARY "primary" +#define NM_SETTING_BOND_PRIMARY_RESELECT "primary_reselect" +#define NM_SETTING_BOND_FAIL_OVER_MAC "fail-over-mac" +#define NM_SETTING_BOND_USE_CARRIER "use-carrier" +#define NM_SETTING_BOND_AD_SELECT "ad-select" +#define NM_SETTING_BOND_XMIT_HASH_POLICY "xmit-hash-policy" +#define NM_SETTING_BOND_RESEND_IGMP "resend-igmp" + +/* Deprecated */ +#define NM_SETTING_BOND_OPTIONS "options" + +/* Valid options for the 'options' property (deprecated) */ +#define NM_SETTING_BOND_OPTION_MODE "mode" +#define NM_SETTING_BOND_OPTION_MIIMON "miimon" +#define NM_SETTING_BOND_OPTION_DOWNDELAY "downdelay" +#define NM_SETTING_BOND_OPTION_UPDELAY "updelay" +#define NM_SETTING_BOND_OPTION_ARP_INTERVAL "arp_interval" +#define NM_SETTING_BOND_OPTION_ARP_IP_TARGET "arp_ip_target" + +#define __NM_SETTING_BOND_MODE_IS_balance_rr(mode) ((mode) && (!strcmp ((mode), "0") || !strcmp ((mode), "balance-rr"))) +#define __NM_SETTING_BOND_MODE_IS_active_backup(mode) ((mode) && (!strcmp ((mode), "1") || !strcmp ((mode), "active-backup"))) +#define __NM_SETTING_BOND_MODE_IS_balance_xor(mode) ((mode) && (!strcmp ((mode), "2") || !strcmp ((mode), "balance-xor"))) +#define __NM_SETTING_BOND_MODE_IS_broadcast(mode) ((mode) && (!strcmp ((mode), "3") || !strcmp ((mode), "broadcast"))) +#define __NM_SETTING_BOND_MODE_IS_802_3ad(mode) ((mode) && (!strcmp ((mode), "4") || !strcmp ((mode), "802.3ad"))) +#define __NM_SETTING_BOND_MODE_IS_balance_tlb(mode) ((mode) && (!strcmp ((mode), "5") || !strcmp ((mode), "balance-tlb"))) +#define __NM_SETTING_BOND_MODE_IS_balance_alb(mode) ((mode) && (!strcmp ((mode), "6") || !strcmp ((mode), "balance-alb"))) typedef struct { NMSetting parent; @@ -90,8 +107,25 @@ typedef struct { GType nm_setting_bond_get_type (void); -NMSetting * nm_setting_bond_new (void); -const char * nm_setting_bond_get_interface_name (NMSettingBond *setting); +NMSetting * nm_setting_bond_new (void); +const char * nm_setting_bond_get_interface_name (NMSettingBond *setting); + +const char * nm_setting_bond_get_mode (NMSettingBond *setting); +const char * nm_setting_bond_get_primary (NMSettingBond *setting); +guint nm_setting_bond_get_miimon (NMSettingBond *setting); +guint nm_setting_bond_get_downdelay (NMSettingBond *setting); +guint nm_setting_bond_get_updelay (NMSettingBond *setting); +guint nm_setting_bond_get_arp_interval (NMSettingBond *setting); +const char *const* nm_setting_bond_get_arp_ip_target (NMSettingBond *setting); +const char * nm_setting_bond_get_arp_validate (NMSettingBond *setting); +const char * nm_setting_bond_get_primary_reselect (NMSettingBond *setting); +const char * nm_setting_bond_get_fail_over_mac (NMSettingBond *setting); +gboolean nm_setting_bond_get_use_carrier (NMSettingBond *setting); +const char * nm_setting_bond_get_ad_select (NMSettingBond *setting); +const char * nm_setting_bond_get_xmit_hash_policy (NMSettingBond *setting); +guint nm_setting_bond_get_resend_igmp (NMSettingBond *setting); + +/* Deprecated */ guint32 nm_setting_bond_get_num_options (NMSettingBond *setting); gboolean nm_setting_bond_get_option (NMSettingBond *setting, guint32 idx, @@ -105,9 +139,6 @@ gboolean nm_setting_bond_add_option (NMSettingBond *setting, gboolean nm_setting_bond_remove_option (NMSettingBond *setting, const char *name); -gboolean nm_setting_bond_validate_option (const char *name, - const char *value); - const char **nm_setting_bond_get_valid_options (NMSettingBond *setting); const char * nm_setting_bond_get_option_default (NMSettingBond *setting, diff --git a/libnm-util/tests/test-general.c b/libnm-util/tests/test-general.c index 56d6e679e2..54d8f23dce 100644 --- a/libnm-util/tests/test-general.c +++ b/libnm-util/tests/test-general.c @@ -1758,7 +1758,7 @@ test_setting_bond_changed_signal (void) ASSERT_CHANGED (nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY, "10")); ASSERT_CHANGED (nm_setting_bond_remove_option (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY)); - ASSERT_UNCHANGED (nm_setting_bond_remove_option (s_bond, NM_SETTING_BOND_OPTION_UPDELAY)); + ASSERT_CHANGED (nm_setting_bond_remove_option (s_bond, NM_SETTING_BOND_OPTION_UPDELAY)); g_object_unref (connection); } diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 8d9939b096..4e191632aa 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -200,6 +200,16 @@ set_bond_attr (NMDevice *device, const char *attr, const char *value) return ret; } +static gboolean +set_bond_attr_int (NMDevice *device, const char *attr, int value) +{ + char buf[20]; + + snprintf (buf, sizeof (buf), "%d", value); + buf[sizeof (buf) -1] = 0; + return set_bond_attr (device, attr, buf); +} + /* Ignore certain bond options if they are zero (off/disabled) */ static gboolean ignore_if_zero (const char *option, const char *value) @@ -253,38 +263,21 @@ update_connection (NMDevice *device, NMConnection *connection) static void set_arp_targets (NMDevice *device, - const char *value, - const char *delim, + const char *const *values, const char *prefix) { - char **items, **iter, *tmp; + char *tmp; - if (!value || !*value) + if (!values) return; - items = g_strsplit_set (value, delim, 0); - for (iter = items; iter && *iter; iter++) { - if (*iter[0]) { - tmp = g_strdup_printf ("%s%s", prefix, *iter); + for (; *values; values++) { + if (*values[0]) { + tmp = g_strconcat (prefix, *values, NULL); set_bond_attr (device, "arp_ip_target", tmp); g_free (tmp); } } - g_strfreev (items); -} - -static void -set_simple_option (NMDevice *device, - const char *attr, - NMSettingBond *s_bond, - const char *opt) -{ - const char *value; - - value = nm_setting_bond_get_option_by_name (s_bond, opt); - if (!value) - value = nm_setting_bond_get_option_default (s_bond, opt); - set_bond_attr (device, attr, value); } static NMActStageReturn @@ -294,6 +287,7 @@ apply_bonding_config (NMDevice *device) NMSettingBond *s_bond; int ifindex = nm_device_get_ifindex (device); const char *mode, *value; + int ivalue; char *contents; gboolean set_arp_interval = TRUE; @@ -315,78 +309,65 @@ apply_bonding_config (NMDevice *device) s_bond = nm_connection_get_setting_bond (connection); g_assert (s_bond); - mode = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MODE); - if (mode == NULL) - mode = "balance-rr"; + mode = nm_setting_bond_get_mode (s_bond); + g_assert (mode && !mode[0]); - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON); - if (value && atoi (value)) { + ivalue = nm_setting_bond_get_miimon (s_bond); + if (ivalue > 0) { /* clear arp interval */ set_bond_attr (device, "arp_interval", "0"); set_arp_interval = FALSE; - set_bond_attr (device, "miimon", value); - set_simple_option (device, "updelay", s_bond, NM_SETTING_BOND_OPTION_UPDELAY); - set_simple_option (device, "downdelay", s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY); - } else if (!value) { - /* If not given, and arp_interval is not given, default to 100 */ - long int val_int; - char *end; - - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - errno = 0; - val_int = strtol (value ? value : "0", &end, 10); - if (!value || (val_int == 0 && errno == 0 && *end == '\0')) - set_bond_attr (device, "miimon", "100"); + set_bond_attr_int (device, "miimon", ivalue); + set_bond_attr_int (device, "updelay", nm_setting_bond_get_updelay (s_bond)); + set_bond_attr_int (device, "downdelay", nm_setting_bond_get_downdelay (s_bond)); } /* The stuff after 'mode' requires the given mode or doesn't care */ set_bond_attr (device, "mode", mode); /* arp_interval not compatible with ALB, TLB */ - if (g_strcmp0 (mode, "balance-alb") == 0 || g_strcmp0 (mode, "balance-tlb") == 0) + if (__NM_SETTING_BOND_MODE_IS_balance_alb (mode) || __NM_SETTING_BOND_MODE_IS_balance_tlb (mode)) set_arp_interval = FALSE; if (set_arp_interval) { - set_simple_option (device, "arp_interval", s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); + set_bond_attr_int (device, "arp_interval", nm_setting_bond_get_arp_interval (s_bond)); /* Just let miimon get cleared automatically; even setting miimon to * 0 (disabled) clears arp_interval. */ } - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE); - /* arp_validate > 0 only valid in active-backup mode */ - if ( value - && g_strcmp0 (value, "0") != 0 - && g_strcmp0 (value, "none") != 0 - && g_strcmp0 (mode, "active-backup") == 0) - set_bond_attr (device, "arp_validate", value); - else - set_bond_attr (device, "arp_validate", "0"); - - if ( g_strcmp0 (mode, "active-backup") == 0 - || g_strcmp0 (mode, "balance-alb") == 0 - || g_strcmp0 (mode, "balance-tlb") == 0) { - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_PRIMARY); + value = nm_setting_bond_get_arp_validate (s_bond); + set_bond_attr (device, "arp_validate", value); + + if ( __NM_SETTING_BOND_MODE_IS_active_backup (mode) + || __NM_SETTING_BOND_MODE_IS_balance_alb (mode) + || __NM_SETTING_BOND_MODE_IS_balance_tlb (mode)) { + value = nm_setting_bond_get_primary (s_bond); set_bond_attr (device, "primary", value ? value : ""); } /* Clear ARP targets */ contents = nm_platform_master_get_option (ifindex, "arp_ip_target"); - set_arp_targets (device, contents, " \n", "-"); + if (contents && contents[0]) { + char **items; + + items = g_strsplit_set (contents, " \n", 0); + set_arp_targets (device, (const char *const*) items, "-"); + g_strfreev (items); + } g_free (contents); /* Add new ARP targets */ - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - set_arp_targets (device, value, ",", "+"); - - set_simple_option (device, "primary_reselect", s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT); - set_simple_option (device, "fail_over_mac", s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC); - set_simple_option (device, "use_carrier", s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER); - set_simple_option (device, "ad_select", s_bond, NM_SETTING_BOND_OPTION_AD_SELECT); - set_simple_option (device, "xmit_hash_policy", s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY); - set_simple_option (device, "resend_igmp", s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP); + set_arp_targets (device, nm_setting_bond_get_arp_ip_target (s_bond), "+"); + + set_bond_attr (device, "primary_reselect", nm_setting_bond_get_primary_reselect (s_bond)); + set_bond_attr (device, "fail_over_mac", nm_setting_bond_get_fail_over_mac (s_bond)); + set_bond_attr_int (device, "use_carrier", nm_setting_bond_get_use_carrier (s_bond)); + set_bond_attr (device, "ad_select", nm_setting_bond_get_ad_select (s_bond)); + set_bond_attr (device, "xmit_hash_policy", nm_setting_bond_get_xmit_hash_policy (s_bond)); + set_bond_attr_int (device, "resend_igmp", nm_setting_bond_get_resend_igmp (s_bond)); return NM_ACT_STAGE_RETURN_SUCCESS; } diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index e2cff0b2cf..e11e75eb05 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -4059,29 +4059,87 @@ infiniband_connection_from_ifcfg (const char *file, return connection; } +typedef void (*IfcfgRhOptFunc) (NMSetting *setting, + const char *key, + const char *value, + gpointer data); + static void -handle_bond_option (NMSettingBond *s_bond, - const char *key, - const char *value) +handle_ifcfg_rh_opts (NMSetting *setting, + const char *value, + IfcfgRhOptFunc func, + gpointer data) { - char *sanitized = NULL, *j; - const char *p = value; + char **items, **iter; - /* Remove any quotes or +/- from arp_ip_target */ - if (!g_strcmp0 (key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET) && value && value[0]) { - if (*p == '\'' || *p == '"') - p++; - j = sanitized = g_malloc0 (strlen (p) + 1); - while (*p) { - if (*p != '+' && *p != '-' && *p != '\'' && *p != '"') - *j++ = *p; - p++; + items = g_strsplit_set (value, " ", -1); + for (iter = items; iter && *iter; iter++) { + if (strlen (*iter)) { + char **keys, *key, *val; + + keys = g_strsplit_set (*iter, "=", 2); + if (keys && *keys) { + key = *keys; + val = *(keys + 1); + if (val && strlen(key) && strlen(val)) + func (setting, key, val, data); + } + + g_strfreev (keys); } } + g_strfreev (items); +} + +static void +handle_bond_option (NMSetting *setting, + const char *key, + const char *value, + gpointer data) +{ + NMSettingBond *s_bond = NM_SETTING_BOND (setting); + + if (!strcmp (key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) { + char **arp_ip_target; + char *sanitized = NULL, *j; + const char *p = value; + + /* Remove any quotes or +/- from arp_ip_target */ + if (value[0]) { + if (*p == '\'' || *p == '"') + p++; + j = sanitized = g_malloc0 (strlen (p) + 1); + while (*p) { + if (*p != '+' && *p != '-' && *p != '\'' && *p != '"') + *j++ = *p; + p++; + } + value = sanitized; + } + + arp_ip_target = g_strsplit (",", value, -1); + g_object_set (s_bond, NM_SETTING_BOND_ARP_IP_TARGET, arp_ip_target, NULL); + g_strfreev (arp_ip_target); + g_free (sanitized); + } else { + GValue gval = G_VALUE_INIT; + + /* We take advantage of the fact that ifcfg files and NMSettingBond use + * the same property names (which are also the ones the kernel uses). + * GObject will transform our string values to guints or gboolean as + * needed. + */ - if (!nm_setting_bond_add_option (s_bond, key, sanitized ? sanitized : value)) - PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid bonding option '%s'", key); - g_free (sanitized); + if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), key)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: unrecognized bond property '%s'", key); + return; + } + + g_value_init (&gval, G_TYPE_STRING); + g_value_set_string (&gval, value); + g_object_set_property (G_OBJECT (setting), key, &gval); + g_value_unset (&gval); + } } static NMSetting * @@ -4105,26 +4163,8 @@ make_bond_setting (shvarFile *ifcfg, value = svGetValue (ifcfg, "BONDING_OPTS", FALSE); if (value) { - char **items, **iter; - - items = g_strsplit_set (value, " ", -1); - for (iter = items; iter && *iter; iter++) { - if (strlen (*iter)) { - char **keys, *key, *val; - - keys = g_strsplit_set (*iter, "=", 2); - if (keys && *keys) { - key = *keys; - val = *(keys + 1); - if (val && strlen(key) && strlen(val)) - handle_bond_option (s_bond, key, val); - } - - g_strfreev (keys); - } - } + handle_ifcfg_rh_opts (NM_SETTING (s_bond), value, handle_bond_option, NULL); g_free (value); - g_strfreev (items); } return (NMSetting *) s_bond; @@ -4266,17 +4306,13 @@ team_connection_from_ifcfg (const char *file, return connection; } -typedef void (*BridgeOptFunc) (NMSetting *setting, - gboolean stp, - const char *key, - const char *value); - static void handle_bridge_option (NMSetting *setting, - gboolean stp, const char *key, - const char *value) + const char *value, + gpointer data) { + gboolean stp = GPOINTER_TO_INT (data); guint32 u = 0; if (!strcmp (key, "priority")) { @@ -4309,33 +4345,6 @@ handle_bridge_option (NMSetting *setting, PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: unhandled bridge option '%s'", key); } -static void -handle_bridging_opts (NMSetting *setting, - gboolean stp, - const char *value, - BridgeOptFunc func) -{ - char **items, **iter; - - items = g_strsplit_set (value, " ", -1); - for (iter = items; iter && *iter; iter++) { - if (strlen (*iter)) { - char **keys, *key, *val; - - keys = g_strsplit_set (*iter, "=", 2); - if (keys && *keys) { - key = *keys; - val = *(keys + 1); - if (val && strlen(key) && strlen(val)) - func (setting, stp, key, val); - } - - g_strfreev (keys); - } - } - g_strfreev (items); -} - static NMSetting * make_bridge_setting (shvarFile *ifcfg, const char *file, @@ -4391,7 +4400,8 @@ make_bridge_setting (shvarFile *ifcfg, value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE); if (value) { - handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option); + handle_ifcfg_rh_opts (NM_SETTING (s_bridge), value, handle_bridge_option, + GINT_TO_POINTER (stp)); g_free (value); } @@ -4442,9 +4452,9 @@ bridge_connection_from_ifcfg (const char *file, static void handle_bridge_port_option (NMSetting *setting, - gboolean stp, const char *key, - const char *value) + const char *value, + gpointer data) { guint32 u = 0; diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 14c4fb9f72..bc8c9740b9 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -12101,9 +12101,9 @@ test_read_bond_main (void) "bond-main", "failed to verify %s: DEVICE=%s does not match bond0", TEST_IFCFG_BOND_MAIN, nm_setting_bond_get_interface_name (s_bond)); - ASSERT (g_strcmp0 (nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON), "100") == 0, - "bond-main", "failed to verify %s: miimon=%s does not match 100", - TEST_IFCFG_BOND_MAIN, nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON)); + ASSERT (nm_setting_bond_get_miimon (s_bond) == 100, + "bond-main", "failed to verify %s: miimon=%u does not match 100", + TEST_IFCFG_BOND_MAIN, nm_setting_bond_get_miimon (s_bond)); g_free (unmanaged); g_free (keyfile); diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index 6abbe2a568..091a87ce6f 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -1245,12 +1245,30 @@ write_vlan_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, return TRUE; } +static const char *bonding_props[] = { + /* NM_SETTING_BOND_OPTION_MODE, */ + NM_SETTING_BOND_OPTION_MIIMON, + NM_SETTING_BOND_OPTION_DOWNDELAY, + NM_SETTING_BOND_OPTION_UPDELAY, + NM_SETTING_BOND_OPTION_ARP_INTERVAL, + NM_SETTING_BOND_OPTION_ARP_IP_TARGET, + NM_SETTING_BOND_OPTION_ARP_VALIDATE, + NM_SETTING_BOND_OPTION_PRIMARY, + NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, + NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, + NM_SETTING_BOND_OPTION_USE_CARRIER, + NM_SETTING_BOND_OPTION_AD_SELECT, + NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, + NM_SETTING_BOND_OPTION_RESEND_IGMP, + NULL +}; + static gboolean write_bonding_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { NMSettingBond *s_bond; const char *iface; - guint32 i, num_opts; + GString *str; s_bond = nm_connection_get_setting_bond (connection); if (!s_bond) { @@ -1268,28 +1286,44 @@ write_bonding_setting (NMConnection *connection, shvarFile *ifcfg, GError **erro svSetValue (ifcfg, "DEVICE", iface, FALSE); svSetValue (ifcfg, "BONDING_OPTS", NULL, FALSE); - num_opts = nm_setting_bond_get_num_options (s_bond); - if (num_opts > 0) { - GString *str = g_string_sized_new (64); - - for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) { - const char *key, *value; + str = g_string_sized_new (64); + g_string_append_printf (str, "mode=%s", nm_setting_bond_get_mode (s_bond)); + + for (i = 0; bonding_props[i]; i++) { + if (!strcmp (bonding_props[i], NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) { + char **arp_ip_target; + int j; + + arp_ip_target = nm_setting_bond_get_arp_ip_target (s_bond); + if (arp_ip_target) { + g_string_append (str, " arp_ip_target="); + for (j = 0; arp_ip_target[j]; j++) { + if (j > 0) + g_string_append_c (str, ','); + g_string_append (str, arp_ip_target[j]); + } + g_strfreev (arp_ip_target); + } + } else if (!strcmp (bonding_props[i], NM_SETTING_BOND_OPTION_USE_CARRIER)) { + if (!nm_setting_bond_get_use_carrier (s_bond)) + g_string_append (str, " use_carrier=0"); + } else { + GValue val = G_VALUE_INIT; + const char *strval; - if (!nm_setting_bond_get_option (s_bond, i, &key, &value)) - continue; + g_value_init (&val, G_TYPE_STRING); + g_object_get_property (G_OBJECT (s_bond), bonding_props[i], &val); + strval = g_value_get_string (&val); - if (str->len) - g_string_append_c (str, ' '); - - g_string_append_printf (str, "%s=%s", key, value); + if (strval && *strval && *strval != '0') + g_string_append_printf (str, " %s=%s", bonding_props[i], strval); + g_value_unset (&val); } - - if (str->len) - svSetValue (ifcfg, "BONDING_OPTS", str->str, FALSE); - - g_string_free (str, TRUE); } + svSetValue (ifcfg, "BONDING_OPTS", str->str, FALSE); + g_string_free (str, TRUE); + svSetValue (ifcfg, "TYPE", TYPE_BOND, FALSE); svSetValue (ifcfg, "BONDING_MASTER", "yes", FALSE); |