diff options
-rw-r--r-- | Documentation/networking/bonding.txt | 42 | ||||
-rw-r--r-- | drivers/net/bonding/bond_3ad.c | 326 | ||||
-rw-r--r-- | drivers/net/bonding/bond_3ad.h | 10 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 30 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 49 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 5 |
6 files changed, 333 insertions, 129 deletions
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 3f4d0fae7081..5ede7473b425 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt | |||
@@ -194,6 +194,48 @@ or, for backwards compatibility, the option value. E.g., | |||
194 | 194 | ||
195 | The parameters are as follows: | 195 | The parameters are as follows: |
196 | 196 | ||
197 | ad_select | ||
198 | |||
199 | Specifies the 802.3ad aggregation selection logic to use. The | ||
200 | possible values and their effects are: | ||
201 | |||
202 | stable or 0 | ||
203 | |||
204 | The active aggregator is chosen by largest aggregate | ||
205 | bandwidth. | ||
206 | |||
207 | Reselection of the active aggregator occurs only when all | ||
208 | slaves of the active aggregator are down or the active | ||
209 | aggregator has no slaves. | ||
210 | |||
211 | This is the default value. | ||
212 | |||
213 | bandwidth or 1 | ||
214 | |||
215 | The active aggregator is chosen by largest aggregate | ||
216 | bandwidth. Reselection occurs if: | ||
217 | |||
218 | - A slave is added to or removed from the bond | ||
219 | |||
220 | - Any slave's link state changes | ||
221 | |||
222 | - Any slave's 802.3ad association state changes | ||
223 | |||
224 | - The bond's adminstrative state changes to up | ||
225 | |||
226 | count or 2 | ||
227 | |||
228 | The active aggregator is chosen by the largest number of | ||
229 | ports (slaves). Reselection occurs as described under the | ||
230 | "bandwidth" setting, above. | ||
231 | |||
232 | The bandwidth and count selection policies permit failover of | ||
233 | 802.3ad aggregations when partial failure of the active aggregator | ||
234 | occurs. This keeps the aggregator with the highest availability | ||
235 | (either in bandwidth or in number of ports) active at all times. | ||
236 | |||
237 | This option was added in bonding version 3.4.0. | ||
238 | |||
197 | arp_interval | 239 | arp_interval |
198 | 240 | ||
199 | Specifies the ARP link monitoring frequency in milliseconds. | 241 | Specifies the ARP link monitoring frequency in milliseconds. |
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 6106660a4a44..ba1372f2f144 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/netdevice.h> | 27 | #include <linux/netdevice.h> |
28 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
29 | #include <linux/ethtool.h> | 29 | #include <linux/ethtool.h> |
30 | #include <linux/etherdevice.h> | ||
30 | #include <linux/if_bonding.h> | 31 | #include <linux/if_bonding.h> |
31 | #include <linux/pkt_sched.h> | 32 | #include <linux/pkt_sched.h> |
32 | #include <net/net_namespace.h> | 33 | #include <net/net_namespace.h> |
@@ -236,6 +237,17 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator) | |||
236 | return &(SLAVE_AD_INFO(slave->next).aggregator); | 237 | return &(SLAVE_AD_INFO(slave->next).aggregator); |
237 | } | 238 | } |
238 | 239 | ||
240 | /* | ||
241 | * __agg_has_partner | ||
242 | * | ||
243 | * Return nonzero if aggregator has a partner (denoted by a non-zero ether | ||
244 | * address for the partner). Return 0 if not. | ||
245 | */ | ||
246 | static inline int __agg_has_partner(struct aggregator *agg) | ||
247 | { | ||
248 | return !is_zero_ether_addr(agg->partner_system.mac_addr_value); | ||
249 | } | ||
250 | |||
239 | /** | 251 | /** |
240 | * __disable_port - disable the port's slave | 252 | * __disable_port - disable the port's slave |
241 | * @port: the port we're looking at | 253 | * @port: the port we're looking at |
@@ -274,14 +286,14 @@ static inline int __port_is_enabled(struct port *port) | |||
274 | * __get_agg_selection_mode - get the aggregator selection mode | 286 | * __get_agg_selection_mode - get the aggregator selection mode |
275 | * @port: the port we're looking at | 287 | * @port: the port we're looking at |
276 | * | 288 | * |
277 | * Get the aggregator selection mode. Can be %BANDWIDTH or %COUNT. | 289 | * Get the aggregator selection mode. Can be %STABLE, %BANDWIDTH or %COUNT. |
278 | */ | 290 | */ |
279 | static inline u32 __get_agg_selection_mode(struct port *port) | 291 | static inline u32 __get_agg_selection_mode(struct port *port) |
280 | { | 292 | { |
281 | struct bonding *bond = __get_bond_by_port(port); | 293 | struct bonding *bond = __get_bond_by_port(port); |
282 | 294 | ||
283 | if (bond == NULL) { | 295 | if (bond == NULL) { |
284 | return AD_BANDWIDTH; | 296 | return BOND_AD_STABLE; |
285 | } | 297 | } |
286 | 298 | ||
287 | return BOND_AD_INFO(bond).agg_select_mode; | 299 | return BOND_AD_INFO(bond).agg_select_mode; |
@@ -1414,9 +1426,82 @@ static void ad_port_selection_logic(struct port *port) | |||
1414 | // else set ready=FALSE in all aggregator's ports | 1426 | // else set ready=FALSE in all aggregator's ports |
1415 | __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); | 1427 | __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); |
1416 | 1428 | ||
1417 | if (!__check_agg_selection_timer(port) && (aggregator = __get_first_agg(port))) { | 1429 | aggregator = __get_first_agg(port); |
1418 | ad_agg_selection_logic(aggregator); | 1430 | ad_agg_selection_logic(aggregator); |
1431 | } | ||
1432 | |||
1433 | /* | ||
1434 | * Decide if "agg" is a better choice for the new active aggregator that | ||
1435 | * the current best, according to the ad_select policy. | ||
1436 | */ | ||
1437 | static struct aggregator *ad_agg_selection_test(struct aggregator *best, | ||
1438 | struct aggregator *curr) | ||
1439 | { | ||
1440 | /* | ||
1441 | * 0. If no best, select current. | ||
1442 | * | ||
1443 | * 1. If the current agg is not individual, and the best is | ||
1444 | * individual, select current. | ||
1445 | * | ||
1446 | * 2. If current agg is individual and the best is not, keep best. | ||
1447 | * | ||
1448 | * 3. Therefore, current and best are both individual or both not | ||
1449 | * individual, so: | ||
1450 | * | ||
1451 | * 3a. If current agg partner replied, and best agg partner did not, | ||
1452 | * select current. | ||
1453 | * | ||
1454 | * 3b. If current agg partner did not reply and best agg partner | ||
1455 | * did reply, keep best. | ||
1456 | * | ||
1457 | * 4. Therefore, current and best both have partner replies or | ||
1458 | * both do not, so perform selection policy: | ||
1459 | * | ||
1460 | * BOND_AD_COUNT: Select by count of ports. If count is equal, | ||
1461 | * select by bandwidth. | ||
1462 | * | ||
1463 | * BOND_AD_STABLE, BOND_AD_BANDWIDTH: Select by bandwidth. | ||
1464 | */ | ||
1465 | if (!best) | ||
1466 | return curr; | ||
1467 | |||
1468 | if (!curr->is_individual && best->is_individual) | ||
1469 | return curr; | ||
1470 | |||
1471 | if (curr->is_individual && !best->is_individual) | ||
1472 | return best; | ||
1473 | |||
1474 | if (__agg_has_partner(curr) && !__agg_has_partner(best)) | ||
1475 | return curr; | ||
1476 | |||
1477 | if (!__agg_has_partner(curr) && __agg_has_partner(best)) | ||
1478 | return best; | ||
1479 | |||
1480 | switch (__get_agg_selection_mode(curr->lag_ports)) { | ||
1481 | case BOND_AD_COUNT: | ||
1482 | if (curr->num_of_ports > best->num_of_ports) | ||
1483 | return curr; | ||
1484 | |||
1485 | if (curr->num_of_ports < best->num_of_ports) | ||
1486 | return best; | ||
1487 | |||
1488 | /*FALLTHROUGH*/ | ||
1489 | case BOND_AD_STABLE: | ||
1490 | case BOND_AD_BANDWIDTH: | ||
1491 | if (__get_agg_bandwidth(curr) > __get_agg_bandwidth(best)) | ||
1492 | return curr; | ||
1493 | |||
1494 | break; | ||
1495 | |||
1496 | default: | ||
1497 | printk(KERN_WARNING DRV_NAME | ||
1498 | ": %s: Impossible agg select mode %d\n", | ||
1499 | curr->slave->dev->master->name, | ||
1500 | __get_agg_selection_mode(curr->lag_ports)); | ||
1501 | break; | ||
1419 | } | 1502 | } |
1503 | |||
1504 | return best; | ||
1420 | } | 1505 | } |
1421 | 1506 | ||
1422 | /** | 1507 | /** |
@@ -1424,156 +1509,138 @@ static void ad_port_selection_logic(struct port *port) | |||
1424 | * @aggregator: the aggregator we're looking at | 1509 | * @aggregator: the aggregator we're looking at |
1425 | * | 1510 | * |
1426 | * It is assumed that only one aggregator may be selected for a team. | 1511 | * It is assumed that only one aggregator may be selected for a team. |
1427 | * The logic of this function is to select (at first time) the aggregator with | 1512 | * |
1428 | * the most ports attached to it, and to reselect the active aggregator only if | 1513 | * The logic of this function is to select the aggregator according to |
1429 | * the previous aggregator has no more ports related to it. | 1514 | * the ad_select policy: |
1515 | * | ||
1516 | * BOND_AD_STABLE: select the aggregator with the most ports attached to | ||
1517 | * it, and to reselect the active aggregator only if the previous | ||
1518 | * aggregator has no more ports related to it. | ||
1519 | * | ||
1520 | * BOND_AD_BANDWIDTH: select the aggregator with the highest total | ||
1521 | * bandwidth, and reselect whenever a link state change takes place or the | ||
1522 | * set of slaves in the bond changes. | ||
1523 | * | ||
1524 | * BOND_AD_COUNT: select the aggregator with largest number of ports | ||
1525 | * (slaves), and reselect whenever a link state change takes place or the | ||
1526 | * set of slaves in the bond changes. | ||
1430 | * | 1527 | * |
1431 | * FIXME: this function MUST be called with the first agg in the bond, or | 1528 | * FIXME: this function MUST be called with the first agg in the bond, or |
1432 | * __get_active_agg() won't work correctly. This function should be better | 1529 | * __get_active_agg() won't work correctly. This function should be better |
1433 | * called with the bond itself, and retrieve the first agg from it. | 1530 | * called with the bond itself, and retrieve the first agg from it. |
1434 | */ | 1531 | */ |
1435 | static void ad_agg_selection_logic(struct aggregator *aggregator) | 1532 | static void ad_agg_selection_logic(struct aggregator *agg) |
1436 | { | 1533 | { |
1437 | struct aggregator *best_aggregator = NULL, *active_aggregator = NULL; | 1534 | struct aggregator *best, *active, *origin; |
1438 | struct aggregator *last_active_aggregator = NULL, *origin_aggregator; | ||
1439 | struct port *port; | 1535 | struct port *port; |
1440 | u16 num_of_aggs=0; | ||
1441 | 1536 | ||
1442 | origin_aggregator = aggregator; | 1537 | origin = agg; |
1443 | 1538 | ||
1444 | //get current active aggregator | 1539 | active = __get_active_agg(agg); |
1445 | last_active_aggregator = __get_active_agg(aggregator); | 1540 | best = active; |
1446 | 1541 | ||
1447 | // search for the aggregator with the most ports attached to it. | ||
1448 | do { | 1542 | do { |
1449 | // count how many candidate lag's we have | 1543 | agg->is_active = 0; |
1450 | if (aggregator->lag_ports) { | 1544 | |
1451 | num_of_aggs++; | 1545 | if (agg->num_of_ports) |
1452 | } | 1546 | best = ad_agg_selection_test(best, agg); |
1453 | if (aggregator->is_active && !aggregator->is_individual && // if current aggregator is the active aggregator | 1547 | |
1454 | MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr))) { // and partner answers to 802.3ad PDUs | 1548 | } while ((agg = __get_next_agg(agg))); |
1455 | if (aggregator->num_of_ports) { // if any ports attached to the current aggregator | 1549 | |
1456 | best_aggregator=NULL; // disregard the best aggregator that was chosen by now | 1550 | if (best && |
1457 | break; // stop the selection of other aggregator if there are any ports attached to this active aggregator | 1551 | __get_agg_selection_mode(best->lag_ports) == BOND_AD_STABLE) { |
1458 | } else { // no ports attached to this active aggregator | 1552 | /* |
1459 | aggregator->is_active = 0; // mark this aggregator as not active anymore | 1553 | * For the STABLE policy, don't replace the old active |
1554 | * aggregator if it's still active (it has an answering | ||
1555 | * partner) or if both the best and active don't have an | ||
1556 | * answering partner. | ||
1557 | */ | ||
1558 | if (active && active->lag_ports && | ||
1559 | active->lag_ports->is_enabled && | ||
1560 | (__agg_has_partner(active) || | ||
1561 | (!__agg_has_partner(active) && !__agg_has_partner(best)))) { | ||
1562 | if (!(!active->actor_oper_aggregator_key && | ||
1563 | best->actor_oper_aggregator_key)) { | ||
1564 | best = NULL; | ||
1565 | active->is_active = 1; | ||
1460 | } | 1566 | } |
1461 | } | 1567 | } |
1462 | if (aggregator->num_of_ports) { // if any ports attached | 1568 | } |
1463 | if (best_aggregator) { // if there is a candidte aggregator | ||
1464 | //The reasons for choosing new best aggregator: | ||
1465 | // 1. if current agg is NOT individual and the best agg chosen so far is individual OR | ||
1466 | // current and best aggs are both individual or both not individual, AND | ||
1467 | // 2a. current agg partner reply but best agg partner do not reply OR | ||
1468 | // 2b. current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply AND | ||
1469 | // current has more ports/bandwidth, or same amount of ports but current has faster ports, THEN | ||
1470 | // current agg become best agg so far | ||
1471 | |||
1472 | //if current agg is NOT individual and the best agg chosen so far is individual change best_aggregator | ||
1473 | if (!aggregator->is_individual && best_aggregator->is_individual) { | ||
1474 | best_aggregator=aggregator; | ||
1475 | } | ||
1476 | // current and best aggs are both individual or both not individual | ||
1477 | else if ((aggregator->is_individual && best_aggregator->is_individual) || | ||
1478 | (!aggregator->is_individual && !best_aggregator->is_individual)) { | ||
1479 | // current and best aggs are both individual or both not individual AND | ||
1480 | // current agg partner reply but best agg partner do not reply | ||
1481 | if ((MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) && | ||
1482 | !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) { | ||
1483 | best_aggregator=aggregator; | ||
1484 | } | ||
1485 | // current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply | ||
1486 | else if (! (!MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) && | ||
1487 | MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) { | ||
1488 | if ((__get_agg_selection_mode(aggregator->lag_ports) == AD_BANDWIDTH)&& | ||
1489 | (__get_agg_bandwidth(aggregator) > __get_agg_bandwidth(best_aggregator))) { | ||
1490 | best_aggregator=aggregator; | ||
1491 | } else if (__get_agg_selection_mode(aggregator->lag_ports) == AD_COUNT) { | ||
1492 | if (((aggregator->num_of_ports > best_aggregator->num_of_ports) && | ||
1493 | (aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS))|| | ||
1494 | ((aggregator->num_of_ports == best_aggregator->num_of_ports) && | ||
1495 | ((u16)(aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS) > | ||
1496 | (u16)(best_aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS)))) { | ||
1497 | best_aggregator=aggregator; | ||
1498 | } | ||
1499 | } | ||
1500 | } | ||
1501 | } | ||
1502 | } else { | ||
1503 | best_aggregator=aggregator; | ||
1504 | } | ||
1505 | } | ||
1506 | aggregator->is_active = 0; // mark all aggregators as not active anymore | ||
1507 | } while ((aggregator = __get_next_agg(aggregator))); | ||
1508 | |||
1509 | // if we have new aggregator selected, don't replace the old aggregator if it has an answering partner, | ||
1510 | // or if both old aggregator and new aggregator don't have answering partner | ||
1511 | if (best_aggregator) { | ||
1512 | if (last_active_aggregator && last_active_aggregator->lag_ports && last_active_aggregator->lag_ports->is_enabled && | ||
1513 | (MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) || // partner answers OR | ||
1514 | (!MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) && // both old and new | ||
1515 | !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) // partner do not answer | ||
1516 | ) { | ||
1517 | // if new aggregator has link, and old aggregator does not, replace old aggregator.(do nothing) | ||
1518 | // -> don't replace otherwise. | ||
1519 | if (!(!last_active_aggregator->actor_oper_aggregator_key && best_aggregator->actor_oper_aggregator_key)) { | ||
1520 | best_aggregator=NULL; | ||
1521 | last_active_aggregator->is_active = 1; // don't replace good old aggregator | ||
1522 | 1569 | ||
1523 | } | 1570 | if (best && (best == active)) { |
1524 | } | 1571 | best = NULL; |
1572 | active->is_active = 1; | ||
1525 | } | 1573 | } |
1526 | 1574 | ||
1527 | // if there is new best aggregator, activate it | 1575 | // if there is new best aggregator, activate it |
1528 | if (best_aggregator) { | 1576 | if (best) { |
1529 | for (aggregator = __get_first_agg(best_aggregator->lag_ports); | 1577 | dprintk("best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", |
1530 | aggregator; | 1578 | best->aggregator_identifier, best->num_of_ports, |
1531 | aggregator = __get_next_agg(aggregator)) { | 1579 | best->actor_oper_aggregator_key, |
1532 | 1580 | best->partner_oper_aggregator_key, | |
1533 | dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", | 1581 | best->is_individual, best->is_active); |
1534 | aggregator->aggregator_identifier, aggregator->num_of_ports, | 1582 | dprintk("best ports %p slave %p %s\n", |
1535 | aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key, | 1583 | best->lag_ports, best->slave, |
1536 | aggregator->is_individual, aggregator->is_active); | 1584 | best->slave ? best->slave->dev->name : "NULL"); |
1585 | |||
1586 | for (agg = __get_first_agg(best->lag_ports); agg; | ||
1587 | agg = __get_next_agg(agg)) { | ||
1588 | |||
1589 | dprintk("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", | ||
1590 | agg->aggregator_identifier, agg->num_of_ports, | ||
1591 | agg->actor_oper_aggregator_key, | ||
1592 | agg->partner_oper_aggregator_key, | ||
1593 | agg->is_individual, agg->is_active); | ||
1537 | } | 1594 | } |
1538 | 1595 | ||
1539 | // check if any partner replys | 1596 | // check if any partner replys |
1540 | if (best_aggregator->is_individual) { | 1597 | if (best->is_individual) { |
1541 | printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad response from " | 1598 | printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad" |
1542 | "the link partner for any adapters in the bond\n", | 1599 | " response from the link partner for any" |
1543 | best_aggregator->slave->dev->master->name); | 1600 | " adapters in the bond\n", |
1544 | } | 1601 | best->slave->dev->master->name); |
1545 | |||
1546 | // check if there are more than one aggregator | ||
1547 | if (num_of_aggs > 1) { | ||
1548 | dprintk("Warning: More than one Link Aggregation Group was " | ||
1549 | "found in the bond. Only one group will function in the bond\n"); | ||
1550 | } | 1602 | } |
1551 | 1603 | ||
1552 | best_aggregator->is_active = 1; | 1604 | best->is_active = 1; |
1553 | dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier); | 1605 | dprintk("LAG %d chosen as the active LAG\n", |
1554 | dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", | 1606 | best->aggregator_identifier); |
1555 | best_aggregator->aggregator_identifier, best_aggregator->num_of_ports, | 1607 | dprintk("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", |
1556 | best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key, | 1608 | best->aggregator_identifier, best->num_of_ports, |
1557 | best_aggregator->is_individual, best_aggregator->is_active); | 1609 | best->actor_oper_aggregator_key, |
1610 | best->partner_oper_aggregator_key, | ||
1611 | best->is_individual, best->is_active); | ||
1558 | 1612 | ||
1559 | // disable the ports that were related to the former active_aggregator | 1613 | // disable the ports that were related to the former active_aggregator |
1560 | if (last_active_aggregator) { | 1614 | if (active) { |
1561 | for (port=last_active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) { | 1615 | for (port = active->lag_ports; port; |
1616 | port = port->next_port_in_aggregator) { | ||
1562 | __disable_port(port); | 1617 | __disable_port(port); |
1563 | } | 1618 | } |
1564 | } | 1619 | } |
1565 | } | 1620 | } |
1566 | 1621 | ||
1567 | // if the selected aggregator is of join individuals(partner_system is NULL), enable their ports | 1622 | /* |
1568 | active_aggregator = __get_active_agg(origin_aggregator); | 1623 | * if the selected aggregator is of join individuals |
1624 | * (partner_system is NULL), enable their ports | ||
1625 | */ | ||
1626 | active = __get_active_agg(origin); | ||
1569 | 1627 | ||
1570 | if (active_aggregator) { | 1628 | if (active) { |
1571 | if (!MAC_ADDRESS_COMPARE(&(active_aggregator->partner_system), &(null_mac_addr))) { | 1629 | if (!__agg_has_partner(active)) { |
1572 | for (port=active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) { | 1630 | for (port = active->lag_ports; port; |
1631 | port = port->next_port_in_aggregator) { | ||
1573 | __enable_port(port); | 1632 | __enable_port(port); |
1574 | } | 1633 | } |
1575 | } | 1634 | } |
1576 | } | 1635 | } |
1636 | |||
1637 | if (origin->slave) { | ||
1638 | struct bonding *bond; | ||
1639 | |||
1640 | bond = bond_get_bond_by_slave(origin->slave); | ||
1641 | if (bond) | ||
1642 | bond_3ad_set_carrier(bond); | ||
1643 | } | ||
1577 | } | 1644 | } |
1578 | 1645 | ||
1579 | /** | 1646 | /** |
@@ -1830,6 +1897,19 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu) | |||
1830 | // Check aggregators status in team every T seconds | 1897 | // Check aggregators status in team every T seconds |
1831 | #define AD_AGGREGATOR_SELECTION_TIMER 8 | 1898 | #define AD_AGGREGATOR_SELECTION_TIMER 8 |
1832 | 1899 | ||
1900 | /* | ||
1901 | * bond_3ad_initiate_agg_selection(struct bonding *bond) | ||
1902 | * | ||
1903 | * Set the aggregation selection timer, to initiate an agg selection in | ||
1904 | * the very near future. Called during first initialization, and during | ||
1905 | * any down to up transitions of the bond. | ||
1906 | */ | ||
1907 | void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout) | ||
1908 | { | ||
1909 | BOND_AD_INFO(bond).agg_select_timer = timeout; | ||
1910 | BOND_AD_INFO(bond).agg_select_mode = bond->params.ad_select; | ||
1911 | } | ||
1912 | |||
1833 | static u16 aggregator_identifier; | 1913 | static u16 aggregator_identifier; |
1834 | 1914 | ||
1835 | /** | 1915 | /** |
@@ -1854,9 +1934,9 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fas | |||
1854 | // initialize how many times this module is called in one second(should be about every 100ms) | 1934 | // initialize how many times this module is called in one second(should be about every 100ms) |
1855 | ad_ticks_per_sec = tick_resolution; | 1935 | ad_ticks_per_sec = tick_resolution; |
1856 | 1936 | ||
1857 | // initialize the aggregator selection timer(to activate an aggregation selection after initialize) | 1937 | bond_3ad_initiate_agg_selection(bond, |
1858 | BOND_AD_INFO(bond).agg_select_timer = (AD_AGGREGATOR_SELECTION_TIMER * ad_ticks_per_sec); | 1938 | AD_AGGREGATOR_SELECTION_TIMER * |
1859 | BOND_AD_INFO(bond).agg_select_mode = AD_BANDWIDTH; | 1939 | ad_ticks_per_sec); |
1860 | } | 1940 | } |
1861 | } | 1941 | } |
1862 | 1942 | ||
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index b5ee45f6d55a..a803fe05f63e 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h | |||
@@ -42,10 +42,11 @@ typedef struct mac_addr { | |||
42 | u8 mac_addr_value[ETH_ALEN]; | 42 | u8 mac_addr_value[ETH_ALEN]; |
43 | } mac_addr_t; | 43 | } mac_addr_t; |
44 | 44 | ||
45 | typedef enum { | 45 | enum { |
46 | AD_BANDWIDTH = 0, | 46 | BOND_AD_STABLE = 0, |
47 | AD_COUNT | 47 | BOND_AD_BANDWIDTH = 1, |
48 | } agg_selection_t; | 48 | BOND_AD_COUNT = 2, |
49 | }; | ||
49 | 50 | ||
50 | // rx machine states(43.4.11 in the 802.3ad standard) | 51 | // rx machine states(43.4.11 in the 802.3ad standard) |
51 | typedef enum { | 52 | typedef enum { |
@@ -277,6 +278,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fas | |||
277 | int bond_3ad_bind_slave(struct slave *slave); | 278 | int bond_3ad_bind_slave(struct slave *slave); |
278 | void bond_3ad_unbind_slave(struct slave *slave); | 279 | void bond_3ad_unbind_slave(struct slave *slave); |
279 | void bond_3ad_state_machine_handler(struct work_struct *); | 280 | void bond_3ad_state_machine_handler(struct work_struct *); |
281 | void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout); | ||
280 | void bond_3ad_adapter_speed_changed(struct slave *slave); | 282 | void bond_3ad_adapter_speed_changed(struct slave *slave); |
281 | void bond_3ad_adapter_duplex_changed(struct slave *slave); | 283 | void bond_3ad_adapter_duplex_changed(struct slave *slave); |
282 | void bond_3ad_handle_link_change(struct slave *slave, char link); | 284 | void bond_3ad_handle_link_change(struct slave *slave, char link); |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 798d98ce2d97..02de3e031237 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -97,6 +97,7 @@ static int use_carrier = 1; | |||
97 | static char *mode = NULL; | 97 | static char *mode = NULL; |
98 | static char *primary = NULL; | 98 | static char *primary = NULL; |
99 | static char *lacp_rate = NULL; | 99 | static char *lacp_rate = NULL; |
100 | static char *ad_select = NULL; | ||
100 | static char *xmit_hash_policy = NULL; | 101 | static char *xmit_hash_policy = NULL; |
101 | static int arp_interval = BOND_LINK_ARP_INTERV; | 102 | static int arp_interval = BOND_LINK_ARP_INTERV; |
102 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; | 103 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; |
@@ -130,6 +131,8 @@ MODULE_PARM_DESC(primary, "Primary network device to use"); | |||
130 | module_param(lacp_rate, charp, 0); | 131 | module_param(lacp_rate, charp, 0); |
131 | MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner " | 132 | MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner " |
132 | "(slow/fast)"); | 133 | "(slow/fast)"); |
134 | module_param(ad_select, charp, 0); | ||
135 | MODULE_PARM_DESC(ad_select, "803.ad aggregation selection logic: stable (0, default), bandwidth (1), count (2)"); | ||
133 | module_param(xmit_hash_policy, charp, 0); | 136 | module_param(xmit_hash_policy, charp, 0); |
134 | MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)" | 137 | MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)" |
135 | ", 1 for layer 3+4"); | 138 | ", 1 for layer 3+4"); |
@@ -200,6 +203,13 @@ struct bond_parm_tbl fail_over_mac_tbl[] = { | |||
200 | { NULL, -1}, | 203 | { NULL, -1}, |
201 | }; | 204 | }; |
202 | 205 | ||
206 | struct bond_parm_tbl ad_select_tbl[] = { | ||
207 | { "stable", BOND_AD_STABLE}, | ||
208 | { "bandwidth", BOND_AD_BANDWIDTH}, | ||
209 | { "count", BOND_AD_COUNT}, | ||
210 | { NULL, -1}, | ||
211 | }; | ||
212 | |||
203 | /*-------------------------- Forward declarations ---------------------------*/ | 213 | /*-------------------------- Forward declarations ---------------------------*/ |
204 | 214 | ||
205 | static void bond_send_gratuitous_arp(struct bonding *bond); | 215 | static void bond_send_gratuitous_arp(struct bonding *bond); |
@@ -3318,6 +3328,8 @@ static void bond_info_show_master(struct seq_file *seq) | |||
3318 | seq_puts(seq, "\n802.3ad info\n"); | 3328 | seq_puts(seq, "\n802.3ad info\n"); |
3319 | seq_printf(seq, "LACP rate: %s\n", | 3329 | seq_printf(seq, "LACP rate: %s\n", |
3320 | (bond->params.lacp_fast) ? "fast" : "slow"); | 3330 | (bond->params.lacp_fast) ? "fast" : "slow"); |
3331 | seq_printf(seq, "Aggregator selection policy (ad_select): %s\n", | ||
3332 | ad_select_tbl[bond->params.ad_select].modename); | ||
3321 | 3333 | ||
3322 | if (bond_3ad_get_active_agg_info(bond, &ad_info)) { | 3334 | if (bond_3ad_get_active_agg_info(bond, &ad_info)) { |
3323 | seq_printf(seq, "bond %s has no active aggregator\n", | 3335 | seq_printf(seq, "bond %s has no active aggregator\n", |
@@ -3824,6 +3836,7 @@ static int bond_open(struct net_device *bond_dev) | |||
3824 | queue_delayed_work(bond->wq, &bond->ad_work, 0); | 3836 | queue_delayed_work(bond->wq, &bond->ad_work, 0); |
3825 | /* register to receive LACPDUs */ | 3837 | /* register to receive LACPDUs */ |
3826 | bond_register_lacpdu(bond); | 3838 | bond_register_lacpdu(bond); |
3839 | bond_3ad_initiate_agg_selection(bond, 1); | ||
3827 | } | 3840 | } |
3828 | 3841 | ||
3829 | return 0; | 3842 | return 0; |
@@ -4763,6 +4776,23 @@ static int bond_check_params(struct bond_params *params) | |||
4763 | } | 4776 | } |
4764 | } | 4777 | } |
4765 | 4778 | ||
4779 | if (ad_select) { | ||
4780 | params->ad_select = bond_parse_parm(ad_select, ad_select_tbl); | ||
4781 | if (params->ad_select == -1) { | ||
4782 | printk(KERN_ERR DRV_NAME | ||
4783 | ": Error: Invalid ad_select \"%s\"\n", | ||
4784 | ad_select == NULL ? "NULL" : ad_select); | ||
4785 | return -EINVAL; | ||
4786 | } | ||
4787 | |||
4788 | if (bond_mode != BOND_MODE_8023AD) { | ||
4789 | printk(KERN_WARNING DRV_NAME | ||
4790 | ": ad_select param only affects 802.3ad mode\n"); | ||
4791 | } | ||
4792 | } else { | ||
4793 | params->ad_select = BOND_AD_STABLE; | ||
4794 | } | ||
4795 | |||
4766 | if (max_bonds < 0 || max_bonds > INT_MAX) { | 4796 | if (max_bonds < 0 || max_bonds > INT_MAX) { |
4767 | printk(KERN_WARNING DRV_NAME | 4797 | printk(KERN_WARNING DRV_NAME |
4768 | ": Warning: max_bonds (%d) not in range %d-%d, so it " | 4798 | ": Warning: max_bonds (%d) not in range %d-%d, so it " |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 8788e3e33852..aaf2927b5c38 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -48,6 +48,7 @@ extern struct list_head bond_dev_list; | |||
48 | extern struct bond_params bonding_defaults; | 48 | extern struct bond_params bonding_defaults; |
49 | extern struct bond_parm_tbl bond_mode_tbl[]; | 49 | extern struct bond_parm_tbl bond_mode_tbl[]; |
50 | extern struct bond_parm_tbl bond_lacp_tbl[]; | 50 | extern struct bond_parm_tbl bond_lacp_tbl[]; |
51 | extern struct bond_parm_tbl ad_select_tbl[]; | ||
51 | extern struct bond_parm_tbl xmit_hashtype_tbl[]; | 52 | extern struct bond_parm_tbl xmit_hashtype_tbl[]; |
52 | extern struct bond_parm_tbl arp_validate_tbl[]; | 53 | extern struct bond_parm_tbl arp_validate_tbl[]; |
53 | extern struct bond_parm_tbl fail_over_mac_tbl[]; | 54 | extern struct bond_parm_tbl fail_over_mac_tbl[]; |
@@ -944,6 +945,53 @@ out: | |||
944 | } | 945 | } |
945 | static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); | 946 | static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); |
946 | 947 | ||
948 | static ssize_t bonding_show_ad_select(struct device *d, | ||
949 | struct device_attribute *attr, | ||
950 | char *buf) | ||
951 | { | ||
952 | struct bonding *bond = to_bond(d); | ||
953 | |||
954 | return sprintf(buf, "%s %d\n", | ||
955 | ad_select_tbl[bond->params.ad_select].modename, | ||
956 | bond->params.ad_select); | ||
957 | } | ||
958 | |||
959 | |||
960 | static ssize_t bonding_store_ad_select(struct device *d, | ||
961 | struct device_attribute *attr, | ||
962 | const char *buf, size_t count) | ||
963 | { | ||
964 | int new_value, ret = count; | ||
965 | struct bonding *bond = to_bond(d); | ||
966 | |||
967 | if (bond->dev->flags & IFF_UP) { | ||
968 | printk(KERN_ERR DRV_NAME | ||
969 | ": %s: Unable to update ad_select because interface " | ||
970 | "is up.\n", bond->dev->name); | ||
971 | ret = -EPERM; | ||
972 | goto out; | ||
973 | } | ||
974 | |||
975 | new_value = bond_parse_parm(buf, ad_select_tbl); | ||
976 | |||
977 | if (new_value != -1) { | ||
978 | bond->params.ad_select = new_value; | ||
979 | printk(KERN_INFO DRV_NAME | ||
980 | ": %s: Setting ad_select to %s (%d).\n", | ||
981 | bond->dev->name, ad_select_tbl[new_value].modename, | ||
982 | new_value); | ||
983 | } else { | ||
984 | printk(KERN_ERR DRV_NAME | ||
985 | ": %s: Ignoring invalid ad_select value %.*s.\n", | ||
986 | bond->dev->name, (int)strlen(buf) - 1, buf); | ||
987 | ret = -EINVAL; | ||
988 | } | ||
989 | out: | ||
990 | return ret; | ||
991 | } | ||
992 | |||
993 | static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); | ||
994 | |||
947 | /* | 995 | /* |
948 | * Show and set the number of grat ARP to send after a failover event. | 996 | * Show and set the number of grat ARP to send after a failover event. |
949 | */ | 997 | */ |
@@ -1459,6 +1507,7 @@ static struct attribute *per_bond_attrs[] = { | |||
1459 | &dev_attr_downdelay.attr, | 1507 | &dev_attr_downdelay.attr, |
1460 | &dev_attr_updelay.attr, | 1508 | &dev_attr_updelay.attr, |
1461 | &dev_attr_lacp_rate.attr, | 1509 | &dev_attr_lacp_rate.attr, |
1510 | &dev_attr_ad_select.attr, | ||
1462 | &dev_attr_xmit_hash_policy.attr, | 1511 | &dev_attr_xmit_hash_policy.attr, |
1463 | &dev_attr_num_grat_arp.attr, | 1512 | &dev_attr_num_grat_arp.attr, |
1464 | &dev_attr_num_unsol_na.attr, | 1513 | &dev_attr_num_unsol_na.attr, |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0491c7c2645b..b5eb8e65b309 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.4.0" | 26 | #define DRV_VERSION "3.5.0" |
27 | #define DRV_RELDATE "October 7, 2008" | 27 | #define DRV_RELDATE "November 4, 2008" |
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 | ||
@@ -137,6 +137,7 @@ struct bond_params { | |||
137 | int updelay; | 137 | int updelay; |
138 | int downdelay; | 138 | int downdelay; |
139 | int lacp_fast; | 139 | int lacp_fast; |
140 | int ad_select; | ||
140 | char primary[IFNAMSIZ]; | 141 | char primary[IFNAMSIZ]; |
141 | __be32 arp_targets[BOND_MAX_ARP_TARGETS]; | 142 | __be32 arp_targets[BOND_MAX_ARP_TARGETS]; |
142 | }; | 143 | }; |