|
@@ -94,6 +94,7 @@ static int downdelay;
|
|
|
static int use_carrier = 1;
|
|
|
static char *mode;
|
|
|
static char *primary;
|
|
|
+static char *primary_reselect;
|
|
|
static char *lacp_rate;
|
|
|
static char *ad_select;
|
|
|
static char *xmit_hash_policy;
|
|
@@ -126,6 +127,14 @@ MODULE_PARM_DESC(mode, "Mode of operation : 0 for balance-rr, "
|
|
|
"6 for balance-alb");
|
|
|
module_param(primary, charp, 0);
|
|
|
MODULE_PARM_DESC(primary, "Primary network device to use");
|
|
|
+module_param(primary_reselect, charp, 0);
|
|
|
+MODULE_PARM_DESC(primary_reselect, "Reselect primary slave "
|
|
|
+ "once it comes up; "
|
|
|
+ "0 for always (default), "
|
|
|
+ "1 for only if speed of primary is "
|
|
|
+ "better, "
|
|
|
+ "2 for only on active slave "
|
|
|
+ "failure");
|
|
|
module_param(lacp_rate, charp, 0);
|
|
|
MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner "
|
|
|
"(slow/fast)");
|
|
@@ -200,6 +209,13 @@ const struct bond_parm_tbl fail_over_mac_tbl[] = {
|
|
|
{ NULL, -1},
|
|
|
};
|
|
|
|
|
|
+const struct bond_parm_tbl pri_reselect_tbl[] = {
|
|
|
+{ "always", BOND_PRI_RESELECT_ALWAYS},
|
|
|
+{ "better", BOND_PRI_RESELECT_BETTER},
|
|
|
+{ "failure", BOND_PRI_RESELECT_FAILURE},
|
|
|
+{ NULL, -1},
|
|
|
+};
|
|
|
+
|
|
|
struct bond_parm_tbl ad_select_tbl[] = {
|
|
|
{ "stable", BOND_AD_STABLE},
|
|
|
{ "bandwidth", BOND_AD_BANDWIDTH},
|
|
@@ -1070,6 +1086,25 @@ out:
|
|
|
|
|
|
}
|
|
|
|
|
|
+static bool bond_should_change_active(struct bonding *bond)
|
|
|
+{
|
|
|
+ struct slave *prim = bond->primary_slave;
|
|
|
+ struct slave *curr = bond->curr_active_slave;
|
|
|
+
|
|
|
+ if (!prim || !curr || curr->link != BOND_LINK_UP)
|
|
|
+ return true;
|
|
|
+ if (bond->force_primary) {
|
|
|
+ bond->force_primary = false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER &&
|
|
|
+ (prim->speed < curr->speed ||
|
|
|
+ (prim->speed == curr->speed && prim->duplex <= curr->duplex)))
|
|
|
+ return false;
|
|
|
+ if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE)
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* find_best_interface - select the best available slave to be the active one
|
|
@@ -1094,7 +1129,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
|
|
|
}
|
|
|
|
|
|
if ((bond->primary_slave) &&
|
|
|
- bond->primary_slave->link == BOND_LINK_UP) {
|
|
|
+ bond->primary_slave->link == BOND_LINK_UP &&
|
|
|
+ bond_should_change_active(bond)) {
|
|
|
new_active = bond->primary_slave;
|
|
|
}
|
|
|
|
|
@@ -1678,8 +1714,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
|
|
|
|
|
if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
|
|
|
/* if there is a primary slave, remember it */
|
|
|
- if (strcmp(bond->params.primary, new_slave->dev->name) == 0)
|
|
|
+ if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
|
|
|
bond->primary_slave = new_slave;
|
|
|
+ bond->force_primary = true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
write_lock_bh(&bond->curr_slave_lock);
|
|
@@ -3201,11 +3239,14 @@ static void bond_info_show_master(struct seq_file *seq)
|
|
|
}
|
|
|
|
|
|
if (USES_PRIMARY(bond->params.mode)) {
|
|
|
- seq_printf(seq, "Primary Slave: %s\n",
|
|
|
+ seq_printf(seq, "Primary Slave: %s",
|
|
|
(bond->primary_slave) ?
|
|
|
bond->primary_slave->dev->name : "None");
|
|
|
+ if (bond->primary_slave)
|
|
|
+ seq_printf(seq, " (primary_reselect %s)",
|
|
|
+ pri_reselect_tbl[bond->params.primary_reselect].modename);
|
|
|
|
|
|
- seq_printf(seq, "Currently Active Slave: %s\n",
|
|
|
+ seq_printf(seq, "\nCurrently Active Slave: %s\n",
|
|
|
(curr) ? curr->dev->name : "None");
|
|
|
}
|
|
|
|
|
@@ -4646,7 +4687,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
|
|
|
|
|
|
static int bond_check_params(struct bond_params *params)
|
|
|
{
|
|
|
- int arp_validate_value, fail_over_mac_value;
|
|
|
+ int arp_validate_value, fail_over_mac_value, primary_reselect_value;
|
|
|
|
|
|
/*
|
|
|
* Convert string parameters.
|
|
@@ -4945,6 +4986,20 @@ static int bond_check_params(struct bond_params *params)
|
|
|
primary = NULL;
|
|
|
}
|
|
|
|
|
|
+ if (primary && primary_reselect) {
|
|
|
+ primary_reselect_value = bond_parse_parm(primary_reselect,
|
|
|
+ pri_reselect_tbl);
|
|
|
+ if (primary_reselect_value == -1) {
|
|
|
+ pr_err(DRV_NAME
|
|
|
+ ": Error: Invalid primary_reselect \"%s\"\n",
|
|
|
+ primary_reselect ==
|
|
|
+ NULL ? "NULL" : primary_reselect);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ primary_reselect_value = BOND_PRI_RESELECT_ALWAYS;
|
|
|
+ }
|
|
|
+
|
|
|
if (fail_over_mac) {
|
|
|
fail_over_mac_value = bond_parse_parm(fail_over_mac,
|
|
|
fail_over_mac_tbl);
|
|
@@ -4976,6 +5031,7 @@ static int bond_check_params(struct bond_params *params)
|
|
|
params->use_carrier = use_carrier;
|
|
|
params->lacp_fast = lacp_fast;
|
|
|
params->primary[0] = 0;
|
|
|
+ params->primary_reselect = primary_reselect_value;
|
|
|
params->fail_over_mac = fail_over_mac_value;
|
|
|
|
|
|
if (primary) {
|