diff options
-rw-r--r-- | Documentation/networking/bonding.txt | 42 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 66 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 53 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 11 |
4 files changed, 164 insertions, 8 deletions
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index d5181ce9ff62..61f516b135b4 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt | |||
@@ -1,7 +1,7 @@ | |||
1 | 1 | ||
2 | Linux Ethernet Bonding Driver HOWTO | 2 | Linux Ethernet Bonding Driver HOWTO |
3 | 3 | ||
4 | Latest update: 12 November 2007 | 4 | Latest update: 23 September 2009 |
5 | 5 | ||
6 | Initial release : Thomas Davis <tadavis at lbl.gov> | 6 | Initial release : Thomas Davis <tadavis at lbl.gov> |
7 | Corrections, HA extensions : 2000/10/03-15 : | 7 | Corrections, HA extensions : 2000/10/03-15 : |
@@ -614,6 +614,46 @@ primary | |||
614 | 614 | ||
615 | The primary option is only valid for active-backup mode. | 615 | The primary option is only valid for active-backup mode. |
616 | 616 | ||
617 | primary_reselect | ||
618 | |||
619 | Specifies the reselection policy for the primary slave. This | ||
620 | affects how the primary slave is chosen to become the active slave | ||
621 | when failure of the active slave or recovery of the primary slave | ||
622 | occurs. This option is designed to prevent flip-flopping between | ||
623 | the primary slave and other slaves. Possible values are: | ||
624 | |||
625 | always or 0 (default) | ||
626 | |||
627 | The primary slave becomes the active slave whenever it | ||
628 | comes back up. | ||
629 | |||
630 | better or 1 | ||
631 | |||
632 | The primary slave becomes the active slave when it comes | ||
633 | back up, if the speed and duplex of the primary slave is | ||
634 | better than the speed and duplex of the current active | ||
635 | slave. | ||
636 | |||
637 | failure or 2 | ||
638 | |||
639 | The primary slave becomes the active slave only if the | ||
640 | current active slave fails and the primary slave is up. | ||
641 | |||
642 | The primary_reselect setting is ignored in two cases: | ||
643 | |||
644 | If no slaves are active, the first slave to recover is | ||
645 | made the active slave. | ||
646 | |||
647 | When initially enslaved, the primary slave is always made | ||
648 | the active slave. | ||
649 | |||
650 | Changing the primary_reselect policy via sysfs will cause an | ||
651 | immediate selection of the best active slave according to the new | ||
652 | policy. This may or may not result in a change of the active | ||
653 | slave, depending upon the circumstances. | ||
654 | |||
655 | This option was added for bonding version 3.6.0. | ||
656 | |||
617 | updelay | 657 | updelay |
618 | 658 | ||
619 | Specifies the time, in milliseconds, to wait before enabling a | 659 | Specifies the time, in milliseconds, to wait before enabling a |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 69c5b15e22da..19d57d537ec1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -94,6 +94,7 @@ static int downdelay; | |||
94 | static int use_carrier = 1; | 94 | static int use_carrier = 1; |
95 | static char *mode; | 95 | static char *mode; |
96 | static char *primary; | 96 | static char *primary; |
97 | static char *primary_reselect; | ||
97 | static char *lacp_rate; | 98 | static char *lacp_rate; |
98 | static char *ad_select; | 99 | static char *ad_select; |
99 | static char *xmit_hash_policy; | 100 | static char *xmit_hash_policy; |
@@ -126,6 +127,14 @@ MODULE_PARM_DESC(mode, "Mode of operation : 0 for balance-rr, " | |||
126 | "6 for balance-alb"); | 127 | "6 for balance-alb"); |
127 | module_param(primary, charp, 0); | 128 | module_param(primary, charp, 0); |
128 | MODULE_PARM_DESC(primary, "Primary network device to use"); | 129 | MODULE_PARM_DESC(primary, "Primary network device to use"); |
130 | module_param(primary_reselect, charp, 0); | ||
131 | MODULE_PARM_DESC(primary_reselect, "Reselect primary slave " | ||
132 | "once it comes up; " | ||
133 | "0 for always (default), " | ||
134 | "1 for only if speed of primary is " | ||
135 | "better, " | ||
136 | "2 for only on active slave " | ||
137 | "failure"); | ||
129 | module_param(lacp_rate, charp, 0); | 138 | module_param(lacp_rate, charp, 0); |
130 | MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner " | 139 | MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner " |
131 | "(slow/fast)"); | 140 | "(slow/fast)"); |
@@ -200,6 +209,13 @@ const struct bond_parm_tbl fail_over_mac_tbl[] = { | |||
200 | { NULL, -1}, | 209 | { NULL, -1}, |
201 | }; | 210 | }; |
202 | 211 | ||
212 | const struct bond_parm_tbl pri_reselect_tbl[] = { | ||
213 | { "always", BOND_PRI_RESELECT_ALWAYS}, | ||
214 | { "better", BOND_PRI_RESELECT_BETTER}, | ||
215 | { "failure", BOND_PRI_RESELECT_FAILURE}, | ||
216 | { NULL, -1}, | ||
217 | }; | ||
218 | |||
203 | struct bond_parm_tbl ad_select_tbl[] = { | 219 | struct bond_parm_tbl ad_select_tbl[] = { |
204 | { "stable", BOND_AD_STABLE}, | 220 | { "stable", BOND_AD_STABLE}, |
205 | { "bandwidth", BOND_AD_BANDWIDTH}, | 221 | { "bandwidth", BOND_AD_BANDWIDTH}, |
@@ -1070,6 +1086,25 @@ out: | |||
1070 | 1086 | ||
1071 | } | 1087 | } |
1072 | 1088 | ||
1089 | static bool bond_should_change_active(struct bonding *bond) | ||
1090 | { | ||
1091 | struct slave *prim = bond->primary_slave; | ||
1092 | struct slave *curr = bond->curr_active_slave; | ||
1093 | |||
1094 | if (!prim || !curr || curr->link != BOND_LINK_UP) | ||
1095 | return true; | ||
1096 | if (bond->force_primary) { | ||
1097 | bond->force_primary = false; | ||
1098 | return true; | ||
1099 | } | ||
1100 | if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER && | ||
1101 | (prim->speed < curr->speed || | ||
1102 | (prim->speed == curr->speed && prim->duplex <= curr->duplex))) | ||
1103 | return false; | ||
1104 | if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE) | ||
1105 | return false; | ||
1106 | return true; | ||
1107 | } | ||
1073 | 1108 | ||
1074 | /** | 1109 | /** |
1075 | * find_best_interface - select the best available slave to be the active one | 1110 | * 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) | |||
1094 | } | 1129 | } |
1095 | 1130 | ||
1096 | if ((bond->primary_slave) && | 1131 | if ((bond->primary_slave) && |
1097 | bond->primary_slave->link == BOND_LINK_UP) { | 1132 | bond->primary_slave->link == BOND_LINK_UP && |
1133 | bond_should_change_active(bond)) { | ||
1098 | new_active = bond->primary_slave; | 1134 | new_active = bond->primary_slave; |
1099 | } | 1135 | } |
1100 | 1136 | ||
@@ -1678,8 +1714,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1678 | 1714 | ||
1679 | if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { | 1715 | if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { |
1680 | /* if there is a primary slave, remember it */ | 1716 | /* if there is a primary slave, remember it */ |
1681 | if (strcmp(bond->params.primary, new_slave->dev->name) == 0) | 1717 | if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { |
1682 | bond->primary_slave = new_slave; | 1718 | bond->primary_slave = new_slave; |
1719 | bond->force_primary = true; | ||
1720 | } | ||
1683 | } | 1721 | } |
1684 | 1722 | ||
1685 | write_lock_bh(&bond->curr_slave_lock); | 1723 | write_lock_bh(&bond->curr_slave_lock); |
@@ -3201,11 +3239,14 @@ static void bond_info_show_master(struct seq_file *seq) | |||
3201 | } | 3239 | } |
3202 | 3240 | ||
3203 | if (USES_PRIMARY(bond->params.mode)) { | 3241 | if (USES_PRIMARY(bond->params.mode)) { |
3204 | seq_printf(seq, "Primary Slave: %s\n", | 3242 | seq_printf(seq, "Primary Slave: %s", |
3205 | (bond->primary_slave) ? | 3243 | (bond->primary_slave) ? |
3206 | bond->primary_slave->dev->name : "None"); | 3244 | bond->primary_slave->dev->name : "None"); |
3245 | if (bond->primary_slave) | ||
3246 | seq_printf(seq, " (primary_reselect %s)", | ||
3247 | pri_reselect_tbl[bond->params.primary_reselect].modename); | ||
3207 | 3248 | ||
3208 | seq_printf(seq, "Currently Active Slave: %s\n", | 3249 | seq_printf(seq, "\nCurrently Active Slave: %s\n", |
3209 | (curr) ? curr->dev->name : "None"); | 3250 | (curr) ? curr->dev->name : "None"); |
3210 | } | 3251 | } |
3211 | 3252 | ||
@@ -4646,7 +4687,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) | |||
4646 | 4687 | ||
4647 | static int bond_check_params(struct bond_params *params) | 4688 | static int bond_check_params(struct bond_params *params) |
4648 | { | 4689 | { |
4649 | int arp_validate_value, fail_over_mac_value; | 4690 | int arp_validate_value, fail_over_mac_value, primary_reselect_value; |
4650 | 4691 | ||
4651 | /* | 4692 | /* |
4652 | * Convert string parameters. | 4693 | * Convert string parameters. |
@@ -4945,6 +4986,20 @@ static int bond_check_params(struct bond_params *params) | |||
4945 | primary = NULL; | 4986 | primary = NULL; |
4946 | } | 4987 | } |
4947 | 4988 | ||
4989 | if (primary && primary_reselect) { | ||
4990 | primary_reselect_value = bond_parse_parm(primary_reselect, | ||
4991 | pri_reselect_tbl); | ||
4992 | if (primary_reselect_value == -1) { | ||
4993 | pr_err(DRV_NAME | ||
4994 | ": Error: Invalid primary_reselect \"%s\"\n", | ||
4995 | primary_reselect == | ||
4996 | NULL ? "NULL" : primary_reselect); | ||
4997 | return -EINVAL; | ||
4998 | } | ||
4999 | } else { | ||
5000 | primary_reselect_value = BOND_PRI_RESELECT_ALWAYS; | ||
5001 | } | ||
5002 | |||
4948 | if (fail_over_mac) { | 5003 | if (fail_over_mac) { |
4949 | fail_over_mac_value = bond_parse_parm(fail_over_mac, | 5004 | fail_over_mac_value = bond_parse_parm(fail_over_mac, |
4950 | fail_over_mac_tbl); | 5005 | fail_over_mac_tbl); |
@@ -4976,6 +5031,7 @@ static int bond_check_params(struct bond_params *params) | |||
4976 | params->use_carrier = use_carrier; | 5031 | params->use_carrier = use_carrier; |
4977 | params->lacp_fast = lacp_fast; | 5032 | params->lacp_fast = lacp_fast; |
4978 | params->primary[0] = 0; | 5033 | params->primary[0] = 0; |
5034 | params->primary_reselect = primary_reselect_value; | ||
4979 | params->fail_over_mac = fail_over_mac_value; | 5035 | params->fail_over_mac = fail_over_mac_value; |
4980 | 5036 | ||
4981 | if (primary) { | 5037 | if (primary) { |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ff449de6f3c0..dca7d82f7b97 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -1213,6 +1213,58 @@ static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, | |||
1213 | bonding_show_primary, bonding_store_primary); | 1213 | bonding_show_primary, bonding_store_primary); |
1214 | 1214 | ||
1215 | /* | 1215 | /* |
1216 | * Show and set the primary_reselect flag. | ||
1217 | */ | ||
1218 | static ssize_t bonding_show_primary_reselect(struct device *d, | ||
1219 | struct device_attribute *attr, | ||
1220 | char *buf) | ||
1221 | { | ||
1222 | struct bonding *bond = to_bond(d); | ||
1223 | |||
1224 | return sprintf(buf, "%s %d\n", | ||
1225 | pri_reselect_tbl[bond->params.primary_reselect].modename, | ||
1226 | bond->params.primary_reselect); | ||
1227 | } | ||
1228 | |||
1229 | static ssize_t bonding_store_primary_reselect(struct device *d, | ||
1230 | struct device_attribute *attr, | ||
1231 | const char *buf, size_t count) | ||
1232 | { | ||
1233 | int new_value, ret = count; | ||
1234 | struct bonding *bond = to_bond(d); | ||
1235 | |||
1236 | if (!rtnl_trylock()) | ||
1237 | return restart_syscall(); | ||
1238 | |||
1239 | new_value = bond_parse_parm(buf, pri_reselect_tbl); | ||
1240 | if (new_value < 0) { | ||
1241 | pr_err(DRV_NAME | ||
1242 | ": %s: Ignoring invalid primary_reselect value %.*s.\n", | ||
1243 | bond->dev->name, | ||
1244 | (int) strlen(buf) - 1, buf); | ||
1245 | ret = -EINVAL; | ||
1246 | goto out; | ||
1247 | } | ||
1248 | |||
1249 | bond->params.primary_reselect = new_value; | ||
1250 | pr_info(DRV_NAME ": %s: setting primary_reselect to %s (%d).\n", | ||
1251 | bond->dev->name, pri_reselect_tbl[new_value].modename, | ||
1252 | new_value); | ||
1253 | |||
1254 | read_lock(&bond->lock); | ||
1255 | write_lock_bh(&bond->curr_slave_lock); | ||
1256 | bond_select_active_slave(bond); | ||
1257 | write_unlock_bh(&bond->curr_slave_lock); | ||
1258 | read_unlock(&bond->lock); | ||
1259 | out: | ||
1260 | rtnl_unlock(); | ||
1261 | return ret; | ||
1262 | } | ||
1263 | static DEVICE_ATTR(primary_reselect, S_IRUGO | S_IWUSR, | ||
1264 | bonding_show_primary_reselect, | ||
1265 | bonding_store_primary_reselect); | ||
1266 | |||
1267 | /* | ||
1216 | * Show and set the use_carrier flag. | 1268 | * Show and set the use_carrier flag. |
1217 | */ | 1269 | */ |
1218 | static ssize_t bonding_show_carrier(struct device *d, | 1270 | static ssize_t bonding_show_carrier(struct device *d, |
@@ -1501,6 +1553,7 @@ static struct attribute *per_bond_attrs[] = { | |||
1501 | &dev_attr_num_unsol_na.attr, | 1553 | &dev_attr_num_unsol_na.attr, |
1502 | &dev_attr_miimon.attr, | 1554 | &dev_attr_miimon.attr, |
1503 | &dev_attr_primary.attr, | 1555 | &dev_attr_primary.attr, |
1556 | &dev_attr_primary_reselect.attr, | ||
1504 | &dev_attr_use_carrier.attr, | 1557 | &dev_attr_use_carrier.attr, |
1505 | &dev_attr_active_slave.attr, | 1558 | &dev_attr_active_slave.attr, |
1506 | &dev_attr_mii_status.attr, | 1559 | &dev_attr_mii_status.attr, |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 68247714466f..9c03c2ee074d 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -23,8 +23,8 @@ | |||
23 | #include "bond_3ad.h" | 23 | #include "bond_3ad.h" |
24 | #include "bond_alb.h" | 24 | #include "bond_alb.h" |
25 | 25 | ||
26 | #define DRV_VERSION "3.5.0" | 26 | #define DRV_VERSION "3.6.0" |
27 | #define DRV_RELDATE "November 4, 2008" | 27 | #define DRV_RELDATE "September 26, 2009" |
28 | #define DRV_NAME "bonding" | 28 | #define DRV_NAME "bonding" |
29 | #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" | 29 | #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" |
30 | 30 | ||
@@ -131,6 +131,7 @@ struct bond_params { | |||
131 | int lacp_fast; | 131 | int lacp_fast; |
132 | int ad_select; | 132 | int ad_select; |
133 | char primary[IFNAMSIZ]; | 133 | char primary[IFNAMSIZ]; |
134 | int primary_reselect; | ||
134 | __be32 arp_targets[BOND_MAX_ARP_TARGETS]; | 135 | __be32 arp_targets[BOND_MAX_ARP_TARGETS]; |
135 | }; | 136 | }; |
136 | 137 | ||
@@ -190,6 +191,7 @@ struct bonding { | |||
190 | struct slave *curr_active_slave; | 191 | struct slave *curr_active_slave; |
191 | struct slave *current_arp_slave; | 192 | struct slave *current_arp_slave; |
192 | struct slave *primary_slave; | 193 | struct slave *primary_slave; |
194 | bool force_primary; | ||
193 | s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ | 195 | s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ |
194 | rwlock_t lock; | 196 | rwlock_t lock; |
195 | rwlock_t curr_slave_lock; | 197 | rwlock_t curr_slave_lock; |
@@ -258,6 +260,10 @@ static inline bool bond_is_lb(const struct bonding *bond) | |||
258 | || bond->params.mode == BOND_MODE_ALB; | 260 | || bond->params.mode == BOND_MODE_ALB; |
259 | } | 261 | } |
260 | 262 | ||
263 | #define BOND_PRI_RESELECT_ALWAYS 0 | ||
264 | #define BOND_PRI_RESELECT_BETTER 1 | ||
265 | #define BOND_PRI_RESELECT_FAILURE 2 | ||
266 | |||
261 | #define BOND_FOM_NONE 0 | 267 | #define BOND_FOM_NONE 0 |
262 | #define BOND_FOM_ACTIVE 1 | 268 | #define BOND_FOM_ACTIVE 1 |
263 | #define BOND_FOM_FOLLOW 2 | 269 | #define BOND_FOM_FOLLOW 2 |
@@ -348,6 +354,7 @@ extern const struct bond_parm_tbl bond_mode_tbl[]; | |||
348 | extern const struct bond_parm_tbl xmit_hashtype_tbl[]; | 354 | extern const struct bond_parm_tbl xmit_hashtype_tbl[]; |
349 | extern const struct bond_parm_tbl arp_validate_tbl[]; | 355 | extern const struct bond_parm_tbl arp_validate_tbl[]; |
350 | extern const struct bond_parm_tbl fail_over_mac_tbl[]; | 356 | extern const struct bond_parm_tbl fail_over_mac_tbl[]; |
357 | extern const struct bond_parm_tbl pri_reselect_tbl[]; | ||
351 | extern struct bond_parm_tbl ad_select_tbl[]; | 358 | extern struct bond_parm_tbl ad_select_tbl[]; |
352 | 359 | ||
353 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 360 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |