aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding/bond_3ad.c
diff options
context:
space:
mode:
authorJay Vosburgh <fubar@us.ibm.com>2008-11-04 20:51:16 -0500
committerJeff Garzik <jgarzik@redhat.com>2008-11-06 00:49:47 -0500
commitfd989c83325cb34795bc4d4aa6b13c06f90eac99 (patch)
treeba6a0589847a45cd558cf2273dae423a4ab78dcc /drivers/net/bonding/bond_3ad.c
parent6146b1a4da98377e4abddc91ba5856bef8f23f1e (diff)
bonding: alternate agg selection policies for 802.3ad
This patch implements alternative aggregator selection policies for 802.3ad. The existing policy, now termed "stable," selects the active aggregator by greatest bandwidth, and only reselects a new aggregator if the active aggregator is entirely disabled (no more ports or all ports down). This patch adds two new policies: bandwidth and count, selecting the active aggregator by total bandwidth (like the stable policy) or by the number of ports in the aggregator, respectively. These two policies also differ from the stable policy in that they will reselect the active aggregator when availability-related changes occur in the bond (e.g., link state change). This permits "gang failover" within 802.3ad, allowing redundant aggregators along parallel paths to always maintain the "best" aggregator as the active aggregator (rather than having to wait for the active to entirely fail). This patch also updates the driver version to 3.5.0. Signed-off-by: Jay Vosburgh <fubar@us.ibm.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/bonding/bond_3ad.c')
-rw-r--r--drivers/net/bonding/bond_3ad.c326
1 files changed, 203 insertions, 123 deletions
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 */
246static 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 */
279static inline u32 __get_agg_selection_mode(struct port *port) 291static 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 */
1437static 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 */
1435static void ad_agg_selection_logic(struct aggregator *aggregator) 1532static 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 */
1907void 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
1833static u16 aggregator_identifier; 1913static 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