diff --git a/src/nm-system.c b/src/nm-system.c index ed75b3f7f6..7368dc35b4 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -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, ¤t, 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;