diff options
Diffstat (limited to 'libnm-util/nm-setting-bond.c')
-rw-r--r-- | libnm-util/nm-setting-bond.c | 1852 |
1 files changed, 1500 insertions, 352 deletions
diff --git a/libnm-util/nm-setting-bond.c b/libnm-util/nm-setting-bond.c index 3459300ec9..39e1494de3 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,17 +75,52 @@ NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_BOND) typedef struct { char *interface_name; + + char *mode; + int miimon; + int downdelay; + int updelay; + int arp_interval; + char **arp_ip_target; + char *arp_validate; + char *primary; + char *primary_reselect; + char *fail_over_mac; + int use_carrier; + char *ad_select; + char *xmit_hash_policy; + int 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_KERNEL_PROP PROP_MODE +#define _LAST_KERNEL_PROP PROP_RESEND_IGMP enum { + TYPE_NONE, /* must be 0, so that it is the default in props if not explicitly set. */ TYPE_INT, TYPE_STR, TYPE_BOTH, @@ -93,35 +129,37 @@ 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 *kernel_name; + const char *list[7]; + const char *list_sentinel[1]; /* dummy, to NULL terminate the previous 'list' array */ + GParamSpec *pspec; + char *defval; +} BondProperty; + +static BondProperty props[LAST_PROP] = { + /* specifying the kernel name is only necessary, when it differs from the property name. */ + + [PROP_MODE] = { TYPE_BOTH, NULL, + { "balance-rr", "active-backup", "balance-xor", "broadcast", "802.3ad", "balance-tlb", "balance-alb" } }, + [PROP_MIIMON] = { TYPE_INT }, + [PROP_DOWNDELAY] = { TYPE_INT }, + [PROP_UPDELAY] = { TYPE_INT }, + [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, NM_SETTING_BOND_OPTION_ARP_VALIDATE, + { "none", "active", "backup", "all" } }, + [PROP_PRIMARY] = { TYPE_IFNAME }, + [PROP_PRIMARY_RESELECT] = { TYPE_BOTH, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, + { "always", "better", "failure" } }, + [PROP_FAIL_OVER_MAC] = { TYPE_BOTH, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, + { "none", "active", "follow" } }, + [PROP_USE_CARRIER] = { TYPE_INT, NM_SETTING_BOND_OPTION_USE_CARRIER }, + [PROP_AD_SELECT] = { TYPE_BOTH, NM_SETTING_BOND_OPTION_AD_SELECT, + { "stable", "bandwidth", "count" } }, + [PROP_XMIT_HASH_POLICY] = { TYPE_STR, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, + { "layer2", "layer2+3", "layer3+4", "encap2+3", "encap3+4" } }, + [PROP_RESEND_IGMP] = { TYPE_INT, NM_SETTING_BOND_OPTION_RESEND_IGMP }, }; /** @@ -137,6 +175,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 @@ -144,7 +184,7 @@ nm_setting_bond_new (void) * Returns: the #NMSettingBond:interface-name property of the setting **/ const char * -nm_setting_bond_get_interface_name (NMSettingBond *setting) +nm_setting_bond_get_interface_name (const NMSettingBond *setting) { g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); @@ -152,178 +192,796 @@ nm_setting_bond_get_interface_name (NMSettingBond *setting) } /** - * nm_setting_bond_get_num_options: + * nm_setting_bond_get_mode: * @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 #NMSettingBond:mode property of the setting * - * Returns: the number of bonding options + * Since: 0.9.10 **/ -guint32 -nm_setting_bond_get_num_options (NMSettingBond *setting) +const char * +nm_setting_bond_get_mode (const 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 (const 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 NM_SETTING_BOND_GET_PRIVATE (setting)->miimon; } /** - * nm_setting_bond_get_option: + * nm_setting_bond_get_downdelay: * @setting: the #NMSettingBond - * @idx: index of the desired option, from 0 to - * nm_setting_bond_get_num_options() - 1 - * @out_name: (out): on return, the name of the bonding option; this - * value is owned by the setting and should not be modified - * @out_value: (out): on return, the value of the name of the bonding - * option; this value is owned by the setting and should not be modified * - * Given an index, return the value of the bonding option at that index. Indexes - * are *not* guaranteed to be static across modifications to options done by - * nm_setting_bond_add_option() and nm_setting_bond_remove_option(), - * and should not be used to refer to options except for short periods of time - * such as during option iteration. + * Returns: the #NMSettingBond:downdelay property of the 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) + * Since: 0.9.10 **/ -gboolean -nm_setting_bond_get_option (NMSettingBond *setting, - guint32 idx, - const char **out_name, - const char **out_value) +guint +nm_setting_bond_get_downdelay (const NMSettingBond *setting) { - NMSettingBondPrivate *priv; - GList *keys; - const char *_key = NULL, *_value = NULL; + 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 (const 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 (const 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 (const 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 (const 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 (const 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 (const 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 (const 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 (const NMSettingBond *setting) +{ g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE); - priv = NM_SETTING_BOND_GET_PRIVATE (setting); + return NM_SETTING_BOND_GET_PRIVATE (setting)->use_carrier; +} - if (idx >= nm_setting_bond_get_num_options (setting)) - return FALSE; +/** + * 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 (const NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); - keys = g_hash_table_get_keys (priv->options); - _key = g_list_nth_data (keys, idx); - _value = g_hash_table_lookup (priv->options, _key); + return NM_SETTING_BOND_GET_PRIVATE (setting)->ad_select; +} - if (out_name) - *out_name = _key; - if (out_value) - *out_value = _value; +/** + * 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 (const NMSettingBond *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); - g_list_free (keys); - return TRUE; + return NM_SETTING_BOND_GET_PRIVATE (setting)->xmit_hash_policy; } -static gboolean -validate_int (const char *name, const char *value, const BondDefault *def) +/** + * 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 (const NMSettingBond *setting) { - glong num; - guint i; + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), 0); - for (i = 0; i < strlen (value); i++) { - if (!g_ascii_isdigit (value[i]) && value[i] != '-') - return FALSE; + return NM_SETTING_BOND_GET_PRIVATE (setting)->resend_igmp; +} + +/*****************************************************************************/ + +static BondProperty * +find_property_by_pspec (const GParamSpec *pspec, guint *out_idx, gboolean kernel_only) +{ + guint i = kernel_only ? _FIRST_KERNEL_PROP : PROP_0 + 1; + guint end = kernel_only ? _LAST_KERNEL_PROP + 1 : LAST_PROP; + + g_return_val_if_fail (pspec != NULL, NULL); + + for (; i < end; i++) { + if (props[i].pspec == pspec) { + if (out_idx) + *out_idx = i; + return &props[i]; + } } + if (out_idx) + *out_idx = LAST_PROP; + return NULL; +} - errno = 0; - num = strtol (value, NULL, 10); - if (errno) - return FALSE; - if (num < def->min || num > def->max) +/* Depending on kernel_only, find only kernel properties. */ +static BondProperty * +find_property_by_name (const char *name, guint *out_idx, gboolean kernel_only) +{ + guint i = kernel_only ? _FIRST_KERNEL_PROP : PROP_0 + 1; + guint end = kernel_only ? _LAST_KERNEL_PROP + 1 : LAST_PROP; + + g_return_val_if_fail (name != NULL, NULL); + + for (; i < end; i++) { + const char *new_name = g_param_spec_get_name (props[i].pspec); + + if (strcmp (name, new_name) == 0 || g_strcmp0 (name, props[i].kernel_name) == 0) { + if (out_idx) + *out_idx = i; + return &props[i]; + } + } + if (out_idx) + *out_idx = LAST_PROP; + return NULL; +} + +/* For a property or kernel name, returns the property name */ +static const char * +get_property_name (const BondProperty *prop) +{ + return prop ? g_param_spec_get_name (prop->pspec) : NULL; +} + +/* For a property or kernel name, returns the kernel option name */ +static const char * +get_kernel_name (const BondProperty *prop) +{ + if (!prop) + return NULL; + return prop->kernel_name ? prop->kernel_name : g_param_spec_get_name (prop->pspec); +} + +static gboolean +int_from_string (const char *s, glong *out_num) +{ + long int n; + char *end; + + if (!s) return FALSE; + errno = 0; + n = strtol (s, &end, 10); + if (out_num) + *out_num = n; + return !errno && !*end; +} - return TRUE; +static gboolean +validate_int (const BondProperty *prop, const char *value, int *out_num) +{ + GParamSpecInt *ispec; + glong num = 0; + gboolean success = FALSE; + + g_assert (G_IS_PARAM_SPEC_INT (prop->pspec)); + if (!int_from_string (value, &num)) + goto out; + + ispec = G_PARAM_SPEC_INT (prop->pspec); + success = (num >= ispec->minimum && num <= ispec->maximum); +out: + if (out_num) + *out_num = success ? num : 0; + return success; } static gboolean -validate_list (const char *name, const char *value, const BondDefault *def) +validate_list (const BondProperty *prop, const char *value) { - guint i; + const char *const*ptr; - for (i = 0; i < G_N_ELEMENTS (def->list) && def->list[i]; i++) { - if (g_strcmp0 (def->list[i], value) == 0) - return TRUE; + if (value) { + for (ptr = prop->list; *ptr; ptr++) { + if (strcmp (*ptr, value) == 0) + return TRUE; + } } - - /* empty validation list means all values pass */ - return def->list[0] == NULL ? TRUE : FALSE; + return FALSE; } +/* by making it a macro, we don't have to worry about using glong as type of idx (otherwise, we would have to check for integer overflow too. */ +#define IS_VALID_LIST_INDEX(prop, idx) ( ((idx) >= 0) && ((idx) < g_strv_length ((char **) (prop)->list)) ) + static gboolean -validate_ip (const char *name, const char *value) +validate_both (const BondProperty *prop, const char *value) +{ + glong num = -1; + + 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 IS_VALID_LIST_INDEX (prop, num); +} + +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]) + if (!value || !value[0]) { + /* missing value is valid, just return NULL instead of an empty array. */ + return NULL; + } + + /* lets be more forgiving when accepting the input string. */ + ips = g_strsplit_set (value, " ,", 0); + for (iter = ips; *iter; iter++) { + if (!*iter) { + /* don't be so strict, just skip over empty values. */ + continue; + } + if (!inet_aton (*iter, &addr)) { + g_strfreev (ips); + g_return_val_if_fail (!warn_on_error, NULL); + return NULL; + } + } + return ips; +} + +static gboolean +validate_ip (const char *value) +{ + 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; - ips = g_strsplit_set (value, ",", 0); - for (iter = ips; iter && *iter && success; iter++) - success = !!inet_aton (*iter, &addr); g_strfreev (ips); - - return success; + return TRUE; } static gboolean -validate_ifname (const char *name, const char *value) +validate_ifname (const char *value) { - if (!value || !value[0]) - return FALSE; + 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); } +/* Checks whether @value is is a valid value for @prop. + * + * Returns: TRUE, if the @value is valid for the given name. + * If @value is NULL, false will be returned. + **/ +static gboolean +validate_property (const BondProperty *prop, const char *value) +{ + switch (prop->opt_type) { + case TYPE_INT: + return validate_int (prop, value, NULL); + 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); + case TYPE_NONE: + default: + g_assert_not_reached(); + } + return FALSE; +} + +/*****************************************************************************/ + +const char * +nm_setting_bond_get_property_name (const char *name) +{ + return get_property_name (find_property_by_name (name, NULL, TRUE)); +} + +const char * +nm_setting_bond_get_kernel_name (const char *name) +{ + return get_kernel_name (find_property_by_name (name, NULL, TRUE)); +} + +const char *const* +nm_setting_bond_get_kernel_names () +{ + static const char *array[_LAST_KERNEL_PROP - _FIRST_KERNEL_PROP + 1 + 1] = { NULL }; + + /* initialize the array once */ + if (G_UNLIKELY (array[0] == NULL)) { + guint prop, i; + + for (prop = _FIRST_KERNEL_PROP, i = 0; prop <= _LAST_KERNEL_PROP; prop++, i++) + array[i] = get_kernel_name (&props[prop]); + } + + return array; +} + /** - * nm_setting_bond_validate_option: - * @name: the name of the option to validate - * @value: the value of the option to validate + * nm_setting_bond_get_string: + * @setting: the #NMSettingBond + * @name: the option name for which to retrieve the value * - * 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. + * Returns the value for the given name, converted to string. * - * Returns: TRUE, if the @value is valid for the given name. - * If the @name is not a valid option, FALSE will be returned. + * Returns: the value as string, or %NULL if the name does not + * exist. + **/ +const char * +nm_setting_bond_get_string (const NMSettingBond *setting, + const char *name) +{ + NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting); + const char *value; + gboolean result; + BondProperty *prop; + + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL); + + if (!name) + return NULL; + + result = g_hash_table_lookup_extended (priv->options, name, NULL, (void **) &value); + if (result) + return value; + + /* Try to lookup by property name instead of the kernel name that is used + * to index the options hash table... */ + prop = find_property_by_name (name, NULL, TRUE); + if (!prop) + return NULL; + + /* 'name' is a valid property name, but we did not find it in the options hash. + * Since every element *must* be in the options hash, this can only mean, that + * the user tried to lookup by property name for items that have a different + * kernel_name. Support lookup by this alias. */ + result = g_hash_table_lookup_extended (priv->options, get_kernel_name (prop), NULL, (void **) &value); + g_assert (result); + + return value; +} + +gboolean +nm_setting_bond_is_default (const NMSettingBond *setting, const char *name, GValue *default_value) +{ + GValue val = G_VALUE_INIT; + GValue def = G_VALUE_INIT; + BondProperty *prop; + gboolean is_default; + + if (!NM_IS_SETTING_BOND (setting)) + goto ERROR_OUT; + prop = find_property_by_name (name, NULL, TRUE); + if (!prop) + goto ERROR_OUT; + + g_value_init (&val, prop->pspec->value_type); + g_value_init (&def, prop->pspec->value_type); + + g_object_get_property (G_OBJECT (setting), get_property_name (prop), &val); + g_param_value_set_default (prop->pspec, &def); + + if (G_VALUE_HOLDS_INT (&val)) + is_default = g_value_get_int (&val) == g_value_get_int (&def); + else if (G_VALUE_HOLDS_STRING (&val)) + is_default = g_strcmp0 (g_value_get_string (&val), g_value_get_string (&def)) == 0; + else if (G_VALUE_HOLDS (&val, G_TYPE_STRV)) { + char **v, **d; + + v = (char **) g_value_get_boxed (&val); + d = (char **) g_value_get_boxed (&def); + + is_default = v == d; + if (!is_default && v && d) { + /* We know, that our only STRV type (ARP_IP_TARGET) has a default value of NULL, + * so don't implement any further comparison now. */ + g_assert_not_reached (); + } + } else + g_assert_not_reached(); + + if (default_value) + g_value_copy (&def, default_value); + + g_value_unset (&val); + g_value_unset (&def); + + return is_default; + +ERROR_OUT: + if (default_value) + g_value_unset (default_value); + g_return_val_if_fail (FALSE, FALSE); + return FALSE; +} + +/** + * nm_setting_bond_set_string: + * @setting: the #NMSettingBond + * @name: name for the option + * @value: value for the option + * + * Set a parameter to a value given as string. The value will be + * converted into the proper type. If the string cannot be converted + * the function does nothing and returns %FALSE. + * + * Returns: %TRUE if the option was valid and successfully set, %FALSE if it was not. * * Since: 0.9.10 **/ gboolean -nm_setting_bond_validate_option (const char *name, - const char *value) +nm_setting_bond_set_string (NMSettingBond *setting, + const char *name, + const char *value) { - guint i; + 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); + + priv = NM_SETTING_BOND_GET_PRIVATE (setting); - if (!name || !name[0]) + prop = find_property_by_name (name, NULL, TRUE); + prop_name = get_property_name (prop); + if (!prop_name) + return FALSE; + if (!validate_property (prop, value)) 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: + if (!int_from_string (value, &num)) + g_assert_not_reached (); + g_object_set (object, prop_name, (gint) num, NULL); + break; + case TYPE_BOTH: { + const char *str_value = value; + + /* Might be an integer-as-string; find the string */ + if (int_from_string (value, &num)) { + /* FIXME: do we really want to coerce the value? verify() currently accepts numeric values + * for the TYPE_BOTH items. NMDeviceBond has to cope with the ambiguity of the options + * names anyway. It might be better, to support the same names as the kernel does, + * including numeric values. Also, when reading the value from sysfs, we will also + * encounter numeric values (so, either we ~always~ coerce -> set_property), or not at all. + **/ + str_value = prop->list[num]; } + g_object_set (object, prop_name, str_value, NULL); + break; } - return FALSE; + 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_set (object, prop_name, ip, NULL); + g_strfreev (ip); + break; + } + case TYPE_NONE: + default: + g_assert_not_reached (); + break; + } + + return TRUE; +} + +/** + * nm_setting_bond_set_default: + * @setting: the #NMSettingBond + * @name: name of the option to remove + * + * Resets the bonding option to the default value. + * + * Since: 0.9.10 + **/ +void +nm_setting_bond_set_default (NMSettingBond *setting, + const char *name) +{ + 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); + + prop = find_property_by_name (name, NULL, TRUE); + prop_name = get_property_name (prop); + if (!prop_name) + return; + + 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); +} + +/** + * nm_setting_bond_validate_default: + * @name: the name of the option + * @value: name value to be validated. + * @error: (out) (allow-none): The error description + * + * Validates a given name and value, where the value is as string. + * + * Since: 0.9.10 + **/ +gboolean +nm_setting_bond_validate_string (const char *name, const char *value, GError **error) +{ + const BondProperty *prop = find_property_by_name (name, NULL, TRUE); + + if (!prop) { + g_set_error_literal (error, + NM_SETTING_BOND_ERROR, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("property is invalid")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, name); + return FALSE; + } + + if (!validate_property (prop, value)) { + g_set_error (error, + NM_SETTING_BOND_ERROR, + NM_SETTING_BOND_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for '%s'"), + value, name); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, name); + return FALSE; + } + + return TRUE; +} + + +/*****************************************************************************/ + +/** + * nm_setting_bond_get_num_options: + * @setting: the #NMSettingBond + * + * 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 + * + * 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 _LAST_KERNEL_PROP - _FIRST_KERNEL_PROP + 1; +} + +/** + * nm_setting_bond_get_option: + * @setting: the #NMSettingBond + * @idx: index of the desired option, from 0 to + * nm_setting_bond_get_num_options() - 1 + * @out_name: (out): on return, the name of the bonding option; this + * value is owned by the setting and should not be modified + * @out_value: (out): on return, the value of the name of the bonding + * option; this value is owned by the setting and should not be modified + * + * Given an index, return the value of the bonding option at that index. Indexes + * are *not* guaranteed to be static across modifications to options done by + * nm_setting_bond_add_option() and nm_setting_bond_remove_option(), + * and should not be used to refer to options except for short periods of time + * such as during option iteration. + * + * 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, + guint32 idx, + const char **out_name, + const char **out_value) +{ + NMSettingBondPrivate *priv; + const char *kernel_name = NULL, *value = NULL; + gboolean result = FALSE; + + g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE); + priv = NM_SETTING_BOND_GET_PRIVATE (setting); + + if (idx >= _LAST_KERNEL_PROP - _FIRST_KERNEL_PROP) + goto out; + idx += _FIRST_KERNEL_PROP; + + kernel_name = get_kernel_name (&props[idx]); + g_assert (kernel_name); + result = g_hash_table_lookup_extended (priv->options, kernel_name, NULL, (void **) &value); + g_assert (result); + +out: + if (out_name) + *out_name = kernel_name; + if (out_value) + *out_value = value; + return result; } /** @@ -336,17 +994,14 @@ 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, const char *name) { - 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); + return nm_setting_bond_get_string (setting, name); } /** @@ -357,45 +1012,20 @@ nm_setting_bond_get_option_by_name (NMSettingBond *setting, * * Add an option to the table. The option is compared to an internal list * of allowed options. Option names may contain only alphanumeric characters - * (ie [a-zA-Z0-9]). Adding a new name replaces any existing name/value pair + * (ie [a-zA-Z0-9_]). Adding a new name replaces any existing name/value pair * that may already exist. * - * The order of how to set several options is relevant because there are options - * that conflict with each other. - * * 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 or nm_setting_bond_set_string() **/ gboolean nm_setting_bond_add_option (NMSettingBond *setting, const char *name, const char *value) { - NMSettingBondPrivate *priv; - - g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE); - - if (!value || !nm_setting_bond_validate_option (name, value)) - return FALSE; - - priv = NM_SETTING_BOND_GET_PRIVATE (setting); - - g_hash_table_insert (priv->options, g_strdup (name), g_strdup (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); - } - - g_object_notify (G_OBJECT (setting), NM_SETTING_BOND_OPTIONS); - - return TRUE; + return nm_setting_bond_set_string (setting, name, value); } /** @@ -404,26 +1034,24 @@ nm_setting_bond_add_option (NMSettingBond *setting, * @name: name of the option to remove * * Remove the bonding option referenced by @name from the internal option - * list. + * list. As the option list is deprected, you can no longer actually remove + * an item from the option hash. Removing it is now equivalent to resetting + * the default value. * * 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; - - g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE); - - if (!nm_setting_bond_validate_option (name, NULL)) - 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; + /* We don't really remove the property, instead we reset the default value. + * Thus, the number of options is always constant (all of them) and the option + * hash always contains every kernel option. */ + nm_setting_bond_set_default (setting, name); + return TRUE; } /** @@ -433,20 +1061,14 @@ 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; - - /* 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; - } - return array; + return (const char **) nm_setting_bond_get_kernel_names (); } /** @@ -456,42 +1078,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; 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_by_name (name, NULL, TRUE); + + if (!prop) + return NULL; + + if (G_UNLIKELY (prop->defval == NULL)) { + 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); + g_return_val_if_fail (prop->defval, NULL); + } + 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_KERNEL_PROP; i <= _LAST_KERNEL_PROP; i++) { + const char *property_name = get_property_name (&props[i]); + const char *kernel_name = get_kernel_name (&props[i]); + GValue defval = G_VALUE_INIT; + + if (!g_hash_table_lookup_extended (options, kernel_name, NULL, (void **)&value)) { + /* for setting options, we also support the new property names instead + * of the kernel names + **/ + if (!g_hash_table_lookup_extended (options, property_name, NULL, (void **)&value)) + value = NULL; + } + + if (value) + nm_setting_bond_set_string (self, kernel_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), property_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 +1156,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 +1165,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); + NM_SETTING_BOND_MIIMON, + NM_SETTING_BOND_ARP_INTERVAL); + 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 (__NM_SETTING_BOND_MODE_IS_balance_alb (priv->mode) || + __NM_SETTING_BOND_MODE_IS_balance_tlb (priv->mode)) { + 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_MODE, priv->mode, + NM_SETTING_BOND_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 (__NM_SETTING_BOND_MODE_IS_active_backup (priv->mode)) { + 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 (__NM_SETTING_BOND_MODE_IS_active_backup (priv->mode)) { 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_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_AD_SELECT], 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_XMIT_HASH_POLICY], 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; } @@ -699,18 +1385,140 @@ get_virtual_iface_name (NMSetting *setting) return nm_setting_bond_get_interface_name (self); } +static gboolean +compare_property (NMSetting *setting, + NMSetting *other, + const GParamSpec *prop_spec, + NMSettingCompareFlags flags) +{ + BondProperty *prop = find_property_by_pspec (prop_spec, NULL, TRUE); + gboolean result = FALSE; + + if (!prop) + goto CHAIN; + + switch (prop->opt_type) { + case TYPE_BOTH: { + char *a0, *b0; + const char *a, *b; + + g_object_get (setting, prop_spec->name, &a0, NULL); + g_object_get (setting, prop_spec->name, &b0, NULL); + + a = a0; + b = b0; + if (!a || !b) + result = (a == b); + else if (strcmp (a, b) == 0) + result = TRUE; + else { + int idx; + + if (validate_int (prop, a, &idx)) { + if (!IS_VALID_LIST_INDEX (prop, idx)) + goto BOTH_FINISHED; + a = prop->list[idx]; + } + if (validate_int (prop, b, &idx)) { + if (!IS_VALID_LIST_INDEX (prop, idx)) + goto BOTH_FINISHED; + b = prop->list[idx]; + } + result = (strcmp (a, b) == 0); + } + +BOTH_FINISHED: + g_free (a0); + g_free (b0); + return result; + } + case TYPE_IP: { + char **a, **b; + struct in_addr *addr_a = NULL, *addr_b = NULL; + + g_object_get (setting, prop_spec->name, &a, NULL); + g_object_get (setting, prop_spec->name, &b, NULL); + + if (!a || !a[0] || !b || !b[0]) + result = ((a ? a[0] : NULL) == (b ? b[0] : NULL)); + else { + /* both arrays are not empty. We compare them by + * converting every item into a struct in_addr and looking + * whether we find it in the other array (and vice versa). + * If one of the addresses cannot be converted, the result + * is always false (because nothing compares to an invalid property). + **/ + + guint i, j; + guint alen = g_strv_length (a); + guint blen = g_strv_length (b); + + /* convert all strings to struct in_addr */ + addr_a = g_new (struct in_addr, alen); + for (i = 0; i < alen; i++) { + if (!inet_aton (a[i], &addr_a[i])) + goto IP_FINISHED; + } + + addr_b = g_new (struct in_addr, blen); + for (i = 0; i < blen; i++) { + if (!inet_aton (b[i], &addr_b[i])) + goto IP_FINISHED; + } + + /* ensure that we find every address in the other array too */ + for (i = 0; i < alen; i++) { + for (j = 0; j < blen; j++) { + if (addr_a[i].s_addr == addr_b[j].s_addr) + break; + } + if (j >= blen) + goto IP_FINISHED; + } + + for (i = 0; i < blen; i++) { + for (j = 0; j < alen; j++) { + if (addr_b[i].s_addr == addr_a[j].s_addr) + break; + } + if (j >= alen) + goto IP_FINISHED; + } + result = TRUE; + } +IP_FINISHED: + g_free (addr_a); + g_free (addr_b); + g_strfreev (a); + g_strfreev (b); + return result; + } + default: + /* other types shall be compared by the default implementation. */ + goto CHAIN; + } + +CHAIN: + return NM_SETTING_CLASS (nm_setting_bond_parent_class)->compare_property (setting, other, prop_spec, flags); +} + + static void 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); + priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); - priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_object_set (setting, NM_SETTING_NAME, NM_SETTING_BOND_SETTING_NAME, NULL); +} + +static void +constructed (GObject *object) +{ + G_OBJECT_CLASS (nm_setting_bond_parent_class)->constructed (object); - /* Default values: */ - nm_setting_bond_add_option (setting, NM_SETTING_BOND_OPTION_MODE, "balance-rr"); + g_assert (g_hash_table_size (NM_SETTING_BOND_GET_PRIVATE (object)->options) == (_LAST_KERNEL_PROP - _FIRST_KERNEL_PROP + 1)); } static void @@ -718,54 +1526,168 @@ finalize (GObject *object) { NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (object); + g_assert (g_hash_table_size (priv->options) == (_LAST_KERNEL_PROP - _FIRST_KERNEL_PROP + 1)); + 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; + BondProperty *prop = find_property_by_pspec (pspec, NULL, TRUE); + char *kernel_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); + kernel_value = g_value_dup_string (value); + break; + case PROP_MIIMON: + priv->miimon = g_value_get_int (value); + kernel_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; + case PROP_DOWNDELAY: + priv->downdelay = g_value_get_int (value); + kernel_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; + case PROP_UPDELAY: + priv->updelay = g_value_get_int (value); + kernel_value = g_strdup_printf ("%u", g_value_get_int (value)); + break; + case PROP_ARP_INTERVAL: + priv->arp_interval = g_value_get_int (value); + kernel_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); + kernel_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); + kernel_value = g_value_dup_string (value); + break; + case PROP_PRIMARY: + g_free (priv->primary); + priv->primary = g_value_dup_string (value); + kernel_value = g_value_dup_string (value); + break; + case PROP_PRIMARY_RESELECT: + g_free (priv->primary_reselect); + priv->primary_reselect = g_value_dup_string (value); + kernel_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); + kernel_value = g_value_dup_string (value); + break; + case PROP_USE_CARRIER: + priv->use_carrier = !!g_value_get_int (value); + kernel_value = g_strdup_printf ("%u", priv->use_carrier); + break; + case PROP_AD_SELECT: + g_free (priv->ad_select); + priv->ad_select = g_value_dup_string (value); + kernel_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); + kernel_value = g_value_dup_string (value); + break; + case PROP_RESEND_IGMP: + priv->resend_igmp = g_value_get_int (value); + kernel_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 (prop) { + const char *kernel_name = get_kernel_name (prop); + const char *old_value; + + if ( !g_hash_table_lookup_extended (priv->options, kernel_name, NULL, (void **) &old_value) + || g_strcmp0 (old_value, kernel_value)) { + g_hash_table_insert (priv->options, (void *) kernel_name, kernel_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; @@ -780,14 +1702,17 @@ 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)); /* virtual methods */ - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->finalize = finalize; - parent_class->verify = verify; + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->constructed = constructed; + object_class->finalize = finalize; + parent_class->verify = verify; + parent_class->compare_property = compare_property; parent_class->get_virtual_iface_name = get_virtual_iface_name; /* Properties */ @@ -796,29 +1721,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)); + 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); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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 | G_PARAM_CONSTRUCT); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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); /** * 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)); + 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); + + /* Skip PROP_0 */ + for (i = 1; i < LAST_PROP; i++) + g_object_class_install_property (object_class, i, props[i].pspec); } |