Ejemplo n.º 1
0
/**
 * nm_setting_bond_get_option_default:
 * @setting: the #NMSettingBond
 * @name: the name of the option
 *
 * Returns: the value of the bond option if not overridden by an entry in
 *   the #NMSettingBond:options property.
 **/
const char *
nm_setting_bond_get_option_default (NMSettingBond *setting, const char *name)
{
	const char *mode;
	guint i;

	g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL);
	g_return_val_if_fail (nm_setting_bond_validate_option (name, NULL), NULL);

	if (nm_streq (name, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM)) {
		/* The default value depends on the current mode */
		mode = nm_setting_bond_get_option_by_name (setting, NM_SETTING_BOND_OPTION_MODE);
		if (   nm_streq0 (mode, "4")
		    || nm_streq0 (mode, "802.3ad"))
			return "00:00:00:00:00:00";
		else
			return "";
	}

	for (i = 0; i < G_N_ELEMENTS (defaults); i++) {
		if (g_strcmp0 (defaults[i].opt, name) == 0)
			return defaults[i].val;
	}
	/* Any option that passes nm_setting_bond_validate_option() should also be found in defaults */
	g_assert_not_reached ();
}
Ejemplo n.º 2
0
/**
 * nm_setting_bond_add_option:
 * @setting: the #NMSettingBond
 * @name: name for the option
 * @value: value for the option
 *
 * 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
 * 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.
 **/
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;
}
Ejemplo n.º 3
0
/**
 * nm_setting_bond_get_option_by_name:
 * @setting: the #NMSettingBond
 * @name: the option name for which to retrieve the value
 *
 * Returns the value associated with the bonding option specified by
 * @name, if it exists.
 *
 * 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
 **/
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);
}
Ejemplo n.º 4
0
/**
 * nm_setting_bond_get_option_type:
 * @setting: the #NMSettingBond
 * @name: the name of the option
 *
 * Returns: the type of the bond option.
 **/
NMBondOptionType
_nm_setting_bond_get_option_type (NMSettingBond *setting, const char *name)
{
	guint i;

	g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NM_BOND_OPTION_TYPE_INT);
	g_return_val_if_fail (nm_setting_bond_validate_option (name, NULL), NM_BOND_OPTION_TYPE_INT);

	for (i = 0; i < G_N_ELEMENTS (defaults); i++) {
		if (nm_streq0 (defaults[i].opt, name))
			return defaults[i].opt_type;
	}
	/* Any option that passes nm_setting_bond_validate_option() should also be found in defaults */
	g_assert_not_reached ();
}
Ejemplo n.º 5
0
/**
 * nm_setting_bond_get_option_default:
 * @setting: the #NMSettingBond
 * @name: the name of the option
 *
 * Returns: the value of the bond option if not overridden by an entry in
 *   the #NMSettingBond:options property.
 **/
const char *
nm_setting_bond_get_option_default (NMSettingBond *setting, const char *name)
{
	guint i;

	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;
	}
	/* Any option that passes nm_setting_bond_validate_option() should also be found in defaults */
	g_assert_not_reached ();
}
Ejemplo n.º 6
0
/**
 * nm_setting_bond_remove_option:
 * @setting: the #NMSettingBond
 * @name: name of the option to remove
 *
 * Remove the bonding option referenced by @name from the internal option
 * list.
 *
 * Returns: %TRUE if the option was found and removed from the internal option
 * list, %FALSE if it was not.
 **/
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;
}
Ejemplo n.º 7
0
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
	NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting);
	GHashTableIter iter;
	const char *key, *value;
	int mode, miimon = 0, arp_interval = 0;
	int num_grat_arp = -1, num_unsol_na = -1;
	const char *mode_orig, *mode_new;
	const char *arp_ip_target = NULL;
	const char *lacp_rate;
	const char *primary;

	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_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("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);
	value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP);
	if (value)
		num_grat_arp = atoi (value);
	value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA);
	if (value)
		num_unsol_na = atoi (value);

	/* Can only set one of miimon and arp_interval */
	if (miimon > 0 && arp_interval > 0) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_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);
		return FALSE;
	}

	/* Verify bond mode */
	mode_orig = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_MODE);
	if (!mode_orig) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("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);
		return FALSE;
	}
	mode = nm_utils_bond_mode_string_to_int (mode_orig);
	if (mode == -1) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_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);
		return FALSE;
	}
	mode_new = nm_utils_bond_mode_int_to_string (mode);

	/* Make sure mode is compatible with other settings */
	if (   strcmp (mode_new, "balance-alb") == 0
	    || strcmp (mode_new, "balance-tlb") == 0) {
		if (arp_interval > 0) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s=%s' is incompatible with '%s > 0'"),
			             NM_SETTING_BOND_OPTION_MODE, mode_new, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	}

	primary = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_PRIMARY);
	if (strcmp (mode_new, "active-backup") == 0) {
		if (primary && !nm_utils_iface_valid_name (primary)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%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);
			return FALSE;
		}
	} else {
		if (primary) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%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);
			return FALSE;
		}
	}

	if (nm_connection_get_setting_infiniband (connection)) {
		if (strcmp (mode_new, "active-backup") != 0) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s=%s' is not a valid configuration for '%s'"),
			             NM_SETTING_BOND_OPTION_MODE, mode_new, NM_SETTING_INFINIBAND_SETTING_NAME);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	}

	if (miimon == 0) {
		/* updelay and downdelay can only be used with miimon */
		if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_UPDELAY)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%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);
			return FALSE;
		}
		if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_DOWNDELAY)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%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);
			return FALSE;
		}
	}

	/* arp_ip_target can only be used with arp_interval, and must
	 * contain a comma-separated list of IPv4 addresses.
	 */
	arp_ip_target = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
	if (arp_interval > 0) {
		char **addrs;
		guint32 addr;
		int i;

		if (!arp_ip_target) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%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);
			return FALSE;
		}

		addrs = g_strsplit (arp_ip_target, ",", -1);
		if (!addrs[0]) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%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);
			return FALSE;
		}

		for (i = 0; addrs[i]; i++) {
			if (!inet_pton (AF_INET, addrs[i], &addr)) {
				g_set_error (error,
				             NM_CONNECTION_ERROR,
				             NM_CONNECTION_ERROR_INVALID_PROPERTY,
				             _("'%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);
				return FALSE;
			}
		}
		g_strfreev (addrs);
	} else {
		if (arp_ip_target) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%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);
			return FALSE;
		}
	}

	lacp_rate = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_LACP_RATE);
	if (   lacp_rate
	    && g_strcmp0 (mode_new, "802.3ad")
	    && strcmp (lacp_rate, "slow") != 0
	    && strcmp (lacp_rate, "0") != 0) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%s' option is only valid with mode '%s'"),
		             NM_SETTING_BOND_OPTION_LACP_RATE, "802.3ad");
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return FALSE;
	}

	if (   (num_grat_arp != -1 && num_unsol_na != -1)
	    && (num_grat_arp != num_unsol_na)) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%s' and '%s' cannot have different values"),
		             NM_SETTING_BOND_OPTION_NUM_GRAT_ARP,
		             NM_SETTING_BOND_OPTION_NUM_UNSOL_NA);
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return FALSE;
	}

	if (!_nm_connection_verify_required_interface_name (connection, error))
		return FALSE;

	/* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */

	if (g_strcmp0 (mode_orig, mode_new) != 0) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%s' option should be string"),
		             NM_SETTING_BOND_OPTION_MODE);
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return NM_SETTING_VERIFY_NORMALIZABLE;
	}

	return TRUE;
}
Ejemplo n.º 8
0
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)) {
		g_set_error_literal (error,
		                     NM_SETTING_BOND_ERROR,
		                     NM_SETTING_BOND_ERROR_MISSING_PROPERTY,
		                     _("property is missing"));
		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,
		                     NM_SETTING_BOND_ERROR_INVALID_PROPERTY,
		                     _("property is invalid"));
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_INTERFACE_NAME);
		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) {
		g_set_error (error,
		             NM_SETTING_BOND_ERROR,
		             NM_SETTING_BOND_ERROR_INVALID_OPTION,
		             _("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);
	}

	value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_MODE);
	if (!value) {
		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);
		return FALSE;
	}
	if (!_nm_utils_string_in_list (value, valid_modes)) {
		g_set_error (error,
		             NM_SETTING_BOND_ERROR,
		             NM_SETTING_BOND_ERROR_INVALID_OPTION,
		             _("'%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);
		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) {
			g_set_error (error,
			             NM_SETTING_BOND_ERROR,
			             NM_SETTING_BOND_ERROR_INVALID_OPTION,
			             _("'%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);
			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)) {
			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);
			return FALSE;
		}
	} else {
		if (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);
			return FALSE;
		}
	}

	if (nm_setting_find_in_list (all_settings, NM_SETTING_INFINIBAND_SETTING_NAME)) {
		if (strcmp (value, "active-backup") != 0) {
			g_set_error (error,
			             NM_SETTING_BOND_ERROR,
			             NM_SETTING_BOND_ERROR_INVALID_OPTION,
			             _("'%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);
			return FALSE;
		}
	}

	if (miimon == 0) {
		/* updelay and downdelay can only be used with miimon */
		if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_UPDELAY)) {
			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);
			return FALSE;
		}
		if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_DOWNDELAY)) {
			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);
			return FALSE;
		}
	}

	/* arp_ip_target can only be used with arp_interval, and must
	 * contain a comma-separated list of IPv4 addresses.
	 */
	arp_ip_target = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
	if (arp_interval > 0) {
		char **addrs;
		guint32 addr;
		int i;

		if (!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);
			return FALSE;
		}

		addrs = g_strsplit (arp_ip_target, ",", -1);
		if (!addrs[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);
			return FALSE;
		}

		for (i = 0; addrs[i]; i++) {
			if (!inet_pton (AF_INET, addrs[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);
				return FALSE;
			}
		}
		g_strfreev (addrs);
	} else {
		if (arp_ip_target) {
			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);
			return FALSE;
		}
	}

	return TRUE;
}