core: do a better job of applying bond configuration

Reset all known bond options to their default values, not just the
ones that NMSettingBond allows overriding. Also, remove any bond
slaves that were already attached to the bond before we managed it.

Only update bond parameters that need to be updated. In particular,
setting either arp_interval or miimon to 0 has the side effect of also
setting the other one to 0, so don't do that if it's already 0.

Fix the handling of arp_ip_target; the sysfs arp_ip_target node does
not work the same way as the ifcfg BONDING_OPTS line (which is what
the code was assuming before).
This commit is contained in:
Dan Winship 2012-03-20 11:16:01 -04:00
parent c4994bba54
commit 49105f7115

View file

@ -1226,70 +1226,126 @@ nm_system_device_set_priority (int ifindex,
}
}
static gboolean
set_bond_attr (const char *iface, const char *attr, const char *value)
static const struct {
const char *option;
const char *default_value;
} bonding_defaults[] = {
{ "mode", "balance-rr" },
{ "arp_interval", "0" },
{ "miimon", "0" },
{ "ad_select", "stable" },
{ "arp_validate", "none" },
{ "downdelay", "0" },
{ "fail_over_mac", "none" },
{ "lacp_rate", "slow" },
{ "min_links", "0" },
{ "num_grat_arp", "1" },
{ "num_unsol_na", "1" },
{ "primary", "" },
{ "primary_reselect", "always" },
{ "resend_igmp", "1" },
{ "updelay", "0" },
{ "use_carrier", "1" },
{ "xmit_hash_policy", "layer2" },
{ NULL, NULL }
};
static void
remove_bonding_entries (const char *iface, const char *path)
{
char file[FILENAME_MAX];
char cmd[20];
char *value, **entries;
gboolean ret;
int i;
snprintf (file, sizeof (file), "/sys/class/net/%s/bonding/%s", iface, attr);
ret = nm_utils_do_sysctl (file, value);
if (!ret) {
nm_log_warn (LOGD_HW, "(%s): failed to set bonding attribute "
"'%s' to '%s'", iface, attr, value);
if (!g_file_get_contents (path, &value, NULL, NULL))
return;
entries = g_strsplit (value, " ", -1);
for (i = 0; entries[i]; i++) {
snprintf (cmd, sizeof (cmd), "-%s", g_strstrip (entries[i]));
ret = nm_utils_do_sysctl (path, cmd);
if (!ret) {
nm_log_warn (LOGD_HW, "(%s): failed to remove entry '%s' from '%s'",
iface, entries[i], path);
}
}
g_strfreev (entries);
}
return ret;
static gboolean
option_valid_for_nm_setting (const char *option, const char **valid_opts)
{
while (*valid_opts) {
if (strcmp (option, *valid_opts) == 0)
return TRUE;
valid_opts++;
}
return FALSE;
}
gboolean
nm_system_apply_bonding_config (const char *iface, NMSettingBond *s_bond)
{
const char **opts, **iter;
const char **valid_opts;
const char *option, *value;
char path[FILENAME_MAX];
char *current, *space;
gboolean ret;
int i;
g_return_val_if_fail (iface != NULL, FALSE);
/*
* FIXME:
*
* ifup-eth contains code to append targets if the value is prefixed
* with '+':
*
* if [ "${key}" = "arp_ip_target" -a "${value:0:1}" != "+" ]; then
* OLDIFS=$IFS;
* IFS=',';
* for arp_ip in $value; do
* if ! grep -q $arp_ip /sys/class/net/${DEVICE}/bonding/$key; then
* echo +$arp_ip > /sys/class/net/${DEVICE}/bonding/$key
* fi
* done
*
* Not sure if this is actually being used and it seems dangerous as
* the result is pretty much unforeseeable.
*/
/* Remove old slaves and arp_ip_targets */
snprintf (path, sizeof (path), "/sys/class/net/%s/bonding/arp_ip_target", iface);
remove_bonding_entries (iface, path);
snprintf (path, sizeof (path), "/sys/class/net/%s/bonding/slaves", iface);
remove_bonding_entries (iface, path);
/* Set bonding options; if the setting didn't specify a value for the
* option then use the default value to ensure there's no leakage of
* options from any previous connections to this one.
*/
opts = nm_setting_bond_get_valid_options (s_bond);
for (iter = opts; iter && *iter; iter++) {
const char *value;
gboolean is_default = FALSE;
/* Apply config/defaults */
valid_opts = nm_setting_bond_get_valid_options (s_bond);
for (i = 0; bonding_defaults[i].option; i++) {
option = bonding_defaults[i].option;
if (option_valid_for_nm_setting (option, valid_opts))
value = nm_setting_bond_get_option_by_name (s_bond, option);
else
value = NULL;
if (!value)
value = bonding_defaults[i].default_value;
value = nm_setting_bond_get_option_by_name (s_bond, *iter);
if (!value) {
value = nm_setting_bond_get_option_default (s_bond, *iter); /* use the default value */
is_default = TRUE;
snprintf (path, sizeof (path), "/sys/class/net/%s/bonding/%s", iface, option);
if (g_file_get_contents (path, &current, NULL, NULL)) {
g_strstrip (current);
space = strchr (current, ' ');
if (space)
*space = '\0';
if (strcmp (current, value) != 0) {
ret = nm_utils_do_sysctl (path, value);
if (!ret) {
nm_log_warn (LOGD_HW, "(%s): failed to set bonding attribute "
"'%s' to '%s'", iface, option, value);
}
}
}
}
nm_log_dbg (LOGD_DEVICE, "(%s): setting bond option '%s' to %s'%s'",
iface,
*iter,
is_default ? "default " : "",
value);
/* Handle arp_ip_target */
value = nm_setting_bond_get_option_by_name (s_bond, "arp_ip_target");
if (value) {
char **addresses, cmd[20];
set_bond_attr (iface, *iter, value);
snprintf (path, sizeof (path), "/sys/class/net/%s/bonding/arp_ip_target", iface);
addresses = g_strsplit (value, ",", -1);
for (i = 0; addresses[i]; i++) {
snprintf (cmd, sizeof (cmd), "+%s", g_strstrip (addresses[i]));
ret = nm_utils_do_sysctl (path, cmd);
if (!ret) {
nm_log_warn (LOGD_HW, "(%s): failed to add arp_ip_target '%s'",
iface, addresses[i]);
}
}
g_strfreev (addresses);
}
return TRUE;