Commit 3d91647a authored by Shmulik Hen's avatar Shmulik Hen Committed by Jeff Garzik

[PATCH] bonding cleanup 2.6 - Fix slave list iteration

bond is no longer part of the list. Added cyclic list iteration macros.
parent de631a00
...@@ -198,13 +198,11 @@ static inline struct bonding *__get_bond_by_port(struct port *port) ...@@ -198,13 +198,11 @@ static inline struct bonding *__get_bond_by_port(struct port *port)
*/ */
static inline struct port *__get_first_port(struct bonding *bond) static inline struct port *__get_first_port(struct bonding *bond)
{ {
struct slave *slave = bond->next; if (bond->slave_cnt == 0) {
if (slave == (struct slave *)bond) {
return NULL; return NULL;
} }
return &(SLAVE_AD_INFO(slave).port); return &(SLAVE_AD_INFO(bond->first_slave).port);
} }
/** /**
...@@ -220,7 +218,7 @@ static inline struct port *__get_next_port(struct port *port) ...@@ -220,7 +218,7 @@ static inline struct port *__get_next_port(struct port *port)
struct slave *slave = port->slave; struct slave *slave = port->slave;
// If there's no bond for this port, or this is the last slave // If there's no bond for this port, or this is the last slave
if ((bond == NULL) || (slave->next == bond->next)) { if ((bond == NULL) || (slave->next == bond->first_slave)) {
return NULL; return NULL;
} }
...@@ -238,12 +236,12 @@ static inline struct aggregator *__get_first_agg(struct port *port) ...@@ -238,12 +236,12 @@ static inline struct aggregator *__get_first_agg(struct port *port)
{ {
struct bonding *bond = __get_bond_by_port(port); struct bonding *bond = __get_bond_by_port(port);
// If there's no bond for this port, or this is the last slave // If there's no bond for this port, or bond has no slaves
if ((bond == NULL) || (bond->next == (struct slave *)bond)) { if ((bond == NULL) || (bond->slave_cnt == 0)) {
return NULL; return NULL;
} }
return &(SLAVE_AD_INFO(bond->next).aggregator); return &(SLAVE_AD_INFO(bond->first_slave).aggregator);
} }
/** /**
...@@ -259,7 +257,7 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator) ...@@ -259,7 +257,7 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator)
struct bonding *bond = bond_get_bond_by_slave(slave); struct bonding *bond = bond_get_bond_by_slave(slave);
// If there's no bond for this aggregator, or this is the last slave // If there's no bond for this aggregator, or this is the last slave
if ((bond == NULL) || (slave->next == bond->next)) { if ((bond == NULL) || (slave->next == bond->first_slave)) {
return NULL; return NULL;
} }
...@@ -2131,7 +2129,7 @@ void bond_3ad_state_machine_handler(struct bonding *bond) ...@@ -2131,7 +2129,7 @@ void bond_3ad_state_machine_handler(struct bonding *bond)
} }
//check if there are any slaves //check if there are any slaves
if (bond->next == (struct slave *)bond) { if (bond->slave_cnt == 0) {
goto re_arm; goto re_arm;
} }
...@@ -2359,6 +2357,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2359,6 +2357,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
int slave_agg_no; int slave_agg_no;
int slaves_in_agg; int slaves_in_agg;
int agg_id; int agg_id;
int i;
struct ad_info ad_info; struct ad_info ad_info;
if (!IS_UP(dev)) { /* bond down */ if (!IS_UP(dev)) { /* bond down */
...@@ -2373,10 +2372,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2373,10 +2372,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
} }
read_lock(&bond->lock); read_lock(&bond->lock);
slave = bond->prev;
/* check if bond is empty */ /* check if bond is empty */
if ((slave == (struct slave *)bond) || (bond->slave_cnt == 0)) { if (bond->slave_cnt == 0) {
printk(KERN_DEBUG DRV_NAME ": Error: bond is empty\n"); printk(KERN_DEBUG DRV_NAME ": Error: bond is empty\n");
dev_kfree_skb(skb); dev_kfree_skb(skb);
read_unlock(&bond->lock); read_unlock(&bond->lock);
...@@ -2401,16 +2399,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2401,16 +2399,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
/* we're at the root, get the first slave */ slave_agg_no = (data->h_dest[5]^bond->device->dev_addr[5]) % slaves_in_agg;
if ((slave == NULL) || (slave->dev == NULL)) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
read_unlock(&bond->lock);
return 0;
}
slave_agg_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % slaves_in_agg; bond_for_each_slave(bond, slave, i) {
while (slave != (struct slave *)bond) {
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
if (agg && (agg->aggregator_identifier == agg_id)) { if (agg && (agg->aggregator_identifier == agg_id)) {
...@@ -2419,17 +2410,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2419,17 +2410,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
break; break;
} }
} }
slave = slave->prev;
if (slave == NULL) {
printk(KERN_ERR DRV_NAME ": Error: slave is NULL\n");
dev_kfree_skb(skb);
read_unlock(&bond->lock);
return 0;
}
} }
if (slave == (struct slave *)bond) { if (slave_agg_no >= 0) {
printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id);
dev_kfree_skb(skb); dev_kfree_skb(skb);
read_unlock(&bond->lock); read_unlock(&bond->lock);
...@@ -2438,18 +2421,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2438,18 +2421,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
start_at = slave; start_at = slave;
do { bond_for_each_slave_from(bond, slave, i, start_at) {
int slave_agg_id = 0; int slave_agg_id = 0;
struct aggregator *agg; struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
if (slave == NULL) {
printk(KERN_ERR DRV_NAME ": Error: slave is NULL\n");
dev_kfree_skb(skb);
read_unlock(&bond->lock);
return 0;
}
agg = SLAVE_AD_INFO(slave).port.aggregator;
if (agg) { if (agg) {
slave_agg_id = agg->aggregator_identifier; slave_agg_id = agg->aggregator_identifier;
...@@ -2463,7 +2437,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2463,7 +2437,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
read_unlock(&bond->lock); read_unlock(&bond->lock);
return 0; return 0;
} }
} while ((slave = slave->next) != start_at); }
/* no suitable interface, frame not sent */ /* no suitable interface, frame not sent */
dev_kfree_skb(skb); dev_kfree_skb(skb);
......
...@@ -232,17 +232,17 @@ tlb_get_least_loaded_slave(struct bonding *bond) ...@@ -232,17 +232,17 @@ tlb_get_least_loaded_slave(struct bonding *bond)
struct slave *slave; struct slave *slave;
struct slave *least_loaded; struct slave *least_loaded;
s64 curr_gap, max_gap; s64 curr_gap, max_gap;
int i, found = 0;
/* Find the first enabled slave */ /* Find the first enabled slave */
slave = bond_get_first_slave(bond); bond_for_each_slave(bond, slave, i) {
while (slave) {
if (SLAVE_IS_OK(slave)) { if (SLAVE_IS_OK(slave)) {
found = 1;
break; break;
} }
slave = bond_get_next_slave(bond, slave);
} }
if (!slave) { if (!found) {
return NULL; return NULL;
} }
...@@ -251,8 +251,7 @@ tlb_get_least_loaded_slave(struct bonding *bond) ...@@ -251,8 +251,7 @@ tlb_get_least_loaded_slave(struct bonding *bond)
(s64)(SLAVE_TLB_INFO(slave).load * 8); (s64)(SLAVE_TLB_INFO(slave).load * 8);
/* Find the slave with the largest gap */ /* Find the slave with the largest gap */
slave = bond_get_next_slave(bond, slave); bond_for_each_slave_from(bond, slave, i, least_loaded) {
while (slave) {
if (SLAVE_IS_OK(slave)) { if (SLAVE_IS_OK(slave)) {
curr_gap = (s64)(slave->speed * 1000000) - curr_gap = (s64)(slave->speed * 1000000) -
(s64)(SLAVE_TLB_INFO(slave).load * 8); (s64)(SLAVE_TLB_INFO(slave).load * 8);
...@@ -261,7 +260,6 @@ tlb_get_least_loaded_slave(struct bonding *bond) ...@@ -261,7 +260,6 @@ tlb_get_least_loaded_slave(struct bonding *bond)
max_gap = curr_gap; max_gap = curr_gap;
} }
} }
slave = bond_get_next_slave(bond, slave);
} }
return least_loaded; return least_loaded;
...@@ -398,14 +396,10 @@ rlb_next_rx_slave(struct bonding *bond) ...@@ -398,14 +396,10 @@ rlb_next_rx_slave(struct bonding *bond)
slave = bond_info->next_rx_slave; slave = bond_info->next_rx_slave;
if (slave == NULL) { if (slave == NULL) {
slave = bond->next; slave = bond->first_slave;
} }
/* this loop uses the circular linked list property of the bond_for_each_slave(bond, slave, i) {
* slave's list to go through all slaves
*/
for (i = 0; i < bond->slave_cnt; i++, slave = slave->next) {
if (SLAVE_IS_OK(slave)) { if (SLAVE_IS_OK(slave)) {
if (!rx_slave) { if (!rx_slave) {
rx_slave = slave; rx_slave = slave;
...@@ -971,6 +965,7 @@ alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) ...@@ -971,6 +965,7 @@ alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave)
struct slave *tmp_slave; struct slave *tmp_slave;
int perm_curr_diff; int perm_curr_diff;
int perm_bond_diff; int perm_bond_diff;
int i, found = 0;
perm_curr_diff = memcmp(slave->perm_hwaddr, perm_curr_diff = memcmp(slave->perm_hwaddr,
slave->dev->dev_addr, slave->dev->dev_addr,
...@@ -979,17 +974,16 @@ alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) ...@@ -979,17 +974,16 @@ alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave)
bond->device->dev_addr, bond->device->dev_addr,
ETH_ALEN); ETH_ALEN);
if (perm_curr_diff && perm_bond_diff) { if (perm_curr_diff && perm_bond_diff) {
tmp_slave = bond_get_first_slave(bond); bond_for_each_slave(bond, tmp_slave, i) {
while (tmp_slave) {
if (!memcmp(slave->perm_hwaddr, if (!memcmp(slave->perm_hwaddr,
tmp_slave->dev->dev_addr, tmp_slave->dev->dev_addr,
ETH_ALEN)) { ETH_ALEN)) {
found = 1;
break; break;
} }
tmp_slave = bond_get_next_slave(bond, tmp_slave);
} }
if (tmp_slave) { if (found) {
alb_swap_mac_addr(bond, slave, tmp_slave); alb_swap_mac_addr(bond, slave, tmp_slave);
} }
} }
...@@ -1023,7 +1017,8 @@ alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) ...@@ -1023,7 +1017,8 @@ alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave)
static int static int
alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
{ {
struct slave *tmp_slave1, *tmp_slave2; struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave;
int i, j, found = 0;
if (bond->slave_cnt == 0) { if (bond->slave_cnt == 0) {
/* this is the first slave */ /* this is the first slave */
...@@ -1035,14 +1030,14 @@ alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) ...@@ -1035,14 +1030,14 @@ alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
* slaves in the bond. * slaves in the bond.
*/ */
if (memcmp(slave->perm_hwaddr, bond->device->dev_addr, ETH_ALEN)) { if (memcmp(slave->perm_hwaddr, bond->device->dev_addr, ETH_ALEN)) {
tmp_slave1 = bond_get_first_slave(bond); bond_for_each_slave(bond, tmp_slave1, i) {
for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) {
if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr, if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr,
ETH_ALEN)) { ETH_ALEN)) {
found = 1;
break; break;
} }
} }
if (tmp_slave1) { if (found) {
/* a slave was found that is using the mac address /* a slave was found that is using the mac address
* of the new slave * of the new slave
*/ */
...@@ -1058,36 +1053,36 @@ alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) ...@@ -1058,36 +1053,36 @@ alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
/* the slave's address is equal to the address of the bond /* the slave's address is equal to the address of the bond
* search for a spare address in the bond for this slave. * search for a spare address in the bond for this slave.
*/ */
tmp_slave1 = bond_get_first_slave(bond); free_mac_slave = NULL;
for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) {
tmp_slave2 = bond_get_first_slave(bond);
for (; tmp_slave2; tmp_slave2 = bond_get_next_slave(bond, tmp_slave2)) {
bond_for_each_slave(bond, tmp_slave1, i) {
found = 0;
bond_for_each_slave(bond, tmp_slave2, j) {
if (!memcmp(tmp_slave1->perm_hwaddr, if (!memcmp(tmp_slave1->perm_hwaddr,
tmp_slave2->dev->dev_addr, tmp_slave2->dev->dev_addr,
ETH_ALEN)) { ETH_ALEN)) {
found = 1;
break; break;
} }
} }
if (!tmp_slave2) { if (!found) {
/* no slave has tmp_slave1's perm addr /* no slave has tmp_slave1's perm addr
* as its curr addr * as its curr addr
*/ */
free_mac_slave = tmp_slave1;
break; break;
} }
} }
if (tmp_slave1) { if (free_mac_slave) {
alb_set_slave_mac_addr(slave, tmp_slave1->perm_hwaddr, alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr,
bond->alb_info.rlb_enabled); bond->alb_info.rlb_enabled);
printk(KERN_WARNING DRV_NAME printk(KERN_WARNING DRV_NAME
": Warning: the hw address of slave %s is in use by " ": Warning: the hw address of slave %s is in use by "
"the bond; giving it the hw address of %s\n", "the bond; giving it the hw address of %s\n",
slave->dev->name, tmp_slave1->dev->name); slave->dev->name, free_mac_slave->dev->name);
} else { } else {
printk(KERN_ERR DRV_NAME printk(KERN_ERR DRV_NAME
": Error: the hw address of slave %s is in use by the " ": Error: the hw address of slave %s is in use by the "
...@@ -1118,16 +1113,16 @@ static inline int ...@@ -1118,16 +1113,16 @@ static inline int
alb_set_mac_address(struct bonding *bond, void *addr) alb_set_mac_address(struct bonding *bond, void *addr)
{ {
struct sockaddr sa; struct sockaddr sa;
struct slave *slave; struct slave *slave, *stop_at;
char tmp_addr[ETH_ALEN]; char tmp_addr[ETH_ALEN];
int error; int error;
int i;
if (bond->alb_info.rlb_enabled) { if (bond->alb_info.rlb_enabled) {
return 0; return 0;
} }
slave = bond_get_first_slave(bond); bond_for_each_slave(bond, slave, i) {
for (; slave; slave = bond_get_next_slave(bond, slave)) {
if (slave->dev->set_mac_address == NULL) { if (slave->dev->set_mac_address == NULL) {
error = -EOPNOTSUPP; error = -EOPNOTSUPP;
goto unwind; goto unwind;
...@@ -1151,8 +1146,10 @@ alb_set_mac_address(struct bonding *bond, void *addr) ...@@ -1151,8 +1146,10 @@ alb_set_mac_address(struct bonding *bond, void *addr)
unwind: unwind:
memcpy(sa.sa_data, bond->device->dev_addr, bond->device->addr_len); memcpy(sa.sa_data, bond->device->dev_addr, bond->device->addr_len);
sa.sa_family = bond->device->type; sa.sa_family = bond->device->type;
slave = bond_get_first_slave(bond);
for (; slave; slave = bond_get_next_slave(bond, slave)) { /* unwind from head to the slave that failed */
stop_at = slave;
bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
slave->dev->set_mac_address(slave->dev, &sa); slave->dev->set_mac_address(slave->dev, &sa);
memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
...@@ -1323,6 +1320,7 @@ bond_alb_monitor(struct bonding *bond) ...@@ -1323,6 +1320,7 @@ bond_alb_monitor(struct bonding *bond)
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *slave = NULL; struct slave *slave = NULL;
int delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; int delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC;
int i;
read_lock(&bond->lock); read_lock(&bond->lock);
...@@ -1347,10 +1345,8 @@ bond_alb_monitor(struct bonding *bond) ...@@ -1347,10 +1345,8 @@ bond_alb_monitor(struct bonding *bond)
* read. * read.
*/ */
read_lock(&bond->ptrlock); read_lock(&bond->ptrlock);
slave = bond_get_first_slave(bond); bond_for_each_slave(bond, slave, i) {
while (slave) {
alb_send_learning_packets(slave,slave->dev->dev_addr); alb_send_learning_packets(slave,slave->dev->dev_addr);
slave = bond_get_next_slave(bond, slave);
} }
read_unlock(&bond->ptrlock); read_unlock(&bond->ptrlock);
...@@ -1360,8 +1356,7 @@ bond_alb_monitor(struct bonding *bond) ...@@ -1360,8 +1356,7 @@ bond_alb_monitor(struct bonding *bond)
/* rebalance tx traffic */ /* rebalance tx traffic */
if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) { if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) {
read_lock(&bond->ptrlock); read_lock(&bond->ptrlock);
slave = bond_get_first_slave(bond); bond_for_each_slave(bond, slave, i) {
while (slave) {
tlb_clear_slave(bond, slave, 1); tlb_clear_slave(bond, slave, 1);
if (slave == bond->current_slave) { if (slave == bond->current_slave) {
SLAVE_TLB_INFO(slave).load = SLAVE_TLB_INFO(slave).load =
...@@ -1369,7 +1364,6 @@ bond_alb_monitor(struct bonding *bond) ...@@ -1369,7 +1364,6 @@ bond_alb_monitor(struct bonding *bond)
BOND_TLB_REBALANCE_INTERVAL; BOND_TLB_REBALANCE_INTERVAL;
bond_info->unbalanced_load = 0; bond_info->unbalanced_load = 0;
} }
slave = bond_get_next_slave(bond, slave);
} }
read_unlock(&bond->ptrlock); read_unlock(&bond->ptrlock);
bond_info->tx_rebalance_counter = 0; bond_info->tx_rebalance_counter = 0;
...@@ -1519,6 +1513,7 @@ void ...@@ -1519,6 +1513,7 @@ void
bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave) bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave)
{ {
struct slave *swap_slave = bond->current_slave; struct slave *swap_slave = bond->current_slave;
int i, found = 0;
if (bond->current_slave == new_slave) { if (bond->current_slave == new_slave) {
return; return;
...@@ -1541,18 +1536,17 @@ bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave) ...@@ -1541,18 +1536,17 @@ bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave)
*/ */
if (!swap_slave) { if (!swap_slave) {
/* find slave that is holding the bond's mac address */ /* find slave that is holding the bond's mac address */
swap_slave = bond_get_first_slave(bond); bond_for_each_slave(bond, swap_slave, i) {
while (swap_slave) {
if (!memcmp(swap_slave->dev->dev_addr, if (!memcmp(swap_slave->dev->dev_addr,
bond->device->dev_addr, ETH_ALEN)) { bond->device->dev_addr, ETH_ALEN)) {
found = 1;
break; break;
} }
swap_slave = bond_get_next_slave(bond, swap_slave);
} }
} }
/* current_slave must be set before calling alb_swap_mac_addr */ /* current_slave must be set before calling alb_swap_mac_addr */
if (swap_slave) { if (found) {
/* swap mac address */ /* swap mac address */
alb_swap_mac_addr(bond, swap_slave, new_slave); alb_swap_mac_addr(bond, swap_slave, new_slave);
} else { } else {
...@@ -1571,6 +1565,7 @@ bond_alb_set_mac_address(struct net_device *dev, void *addr) ...@@ -1571,6 +1565,7 @@ bond_alb_set_mac_address(struct net_device *dev, void *addr)
struct sockaddr *sa = addr; struct sockaddr *sa = addr;
struct slave *swap_slave = NULL; struct slave *swap_slave = NULL;
int error = 0; int error = 0;
int i, found = 0;
if (!is_valid_ether_addr(sa->sa_data)) { if (!is_valid_ether_addr(sa->sa_data)) {
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
...@@ -1591,15 +1586,14 @@ bond_alb_set_mac_address(struct net_device *dev, void *addr) ...@@ -1591,15 +1586,14 @@ bond_alb_set_mac_address(struct net_device *dev, void *addr)
return 0; return 0;
} }
swap_slave = bond_get_first_slave(bond); bond_for_each_slave(bond, swap_slave, i) {
while (swap_slave) {
if (!memcmp(swap_slave->dev->dev_addr, dev->dev_addr, ETH_ALEN)) { if (!memcmp(swap_slave->dev->dev_addr, dev->dev_addr, ETH_ALEN)) {
found = 1;
break; break;
} }
swap_slave = bond_get_next_slave(bond, swap_slave);
} }
if (swap_slave) { if (found) {
alb_swap_mac_addr(bond, swap_slave, bond->current_slave); alb_swap_mac_addr(bond, swap_slave, bond->current_slave);
} else { } else {
alb_set_slave_mac_addr(bond->current_slave, dev->dev_addr, alb_set_slave_mac_addr(bond->current_slave, dev->dev_addr,
......
...@@ -644,99 +644,60 @@ void bond_set_slave_active_flags(struct slave *slave) ...@@ -644,99 +644,60 @@ void bond_set_slave_active_flags(struct slave *slave)
slave->dev->flags &= ~IFF_NOARP; slave->dev->flags &= ~IFF_NOARP;
} }
/*
* This function counts and verifies the the number of attached
* slaves, checking the count against the expected value (given that incr
* is either 1 or -1, for add or removal of a slave). Only
* bond_xmit_xor() uses the slave_cnt value, but this is still a good
* consistency check.
*/
static inline void
update_slave_cnt(struct bonding *bond, int incr)
{
struct slave *slave = NULL;
int expect = bond->slave_cnt + incr;
bond->slave_cnt = 0;
for (slave = bond->prev; slave != (struct slave *)bond;
slave = slave->prev) {
bond->slave_cnt++;
}
if (expect != bond->slave_cnt)
BUG();
}
/* /*
* This function detaches the slave <slave> from the list <bond>. * This function detaches the slave from the list.
* WARNING: no check is made to verify if the slave effectively * WARNING: no check is made to verify if the slave effectively
* belongs to <bond>. It returns <slave> in case it's needed. * belongs to <bond>.
* Nothing is freed on return, structures are just unchained. * Nothing is freed on return, structures are just unchained.
* If the bond->current_slave pointer was pointing to <slave>, * If any slave pointer in bond was pointing to <slave>,
* it should be changed by the calling function. * it should be changed by the calling function.
* *
* bond->lock held for writing by caller. * bond->lock held for writing by caller.
*/ */
static struct slave * static void
bond_detach_slave(struct bonding *bond, struct slave *slave) bond_detach_slave(struct bonding *bond, struct slave *slave)
{ {
if (bond->next == slave) { /* is the slave at the head ? */ if (slave->next) {
if (bond->prev == slave) { /* is the slave alone ? */ slave->next->prev = slave->prev;
bond->prev = bond->next = (struct slave *)bond; }
} else { /* not alone */
bond->next = slave->next; if (slave->prev) {
slave->next->prev = (struct slave *)bond;
bond->prev->next = slave->next;
}
} else {
slave->prev->next = slave->next; slave->prev->next = slave->next;
if (bond->prev == slave) { /* is this slave the last one ? */ }
bond->prev = slave->prev;
if (bond->first_slave == slave) { /* slave is the first slave */
if (bond->slave_cnt > 1) { /* there are more slave */
bond->first_slave = slave->next;
} else { } else {
slave->next->prev = slave->prev; bond->first_slave = NULL; /* slave was the last one */
} }
} }
update_slave_cnt(bond, -1); slave->next = NULL;
slave->prev = NULL;
return slave; bond->slave_cnt--;
} }
/* /*
* This function attaches the slave <slave> to the list <bond>. * This function attaches the slave to the end of list.
* *
* bond->lock held for writing by caller. * bond->lock held for writing by caller.
*/ */
static void static void
bond_attach_slave(struct bonding *bond, struct slave *new_slave) bond_attach_slave(struct bonding *bond, struct slave *new_slave)
{ {
/* if (bond->first_slave == NULL) { /* attaching the first slave */
* queue to the end of the slaves list, make the first element its new_slave->next = new_slave;
* successor, the last one its predecessor, and make it the bond's new_slave->prev = new_slave;
* predecessor. bond->first_slave = new_slave;
* } else {
* Just to clarify, so future bonding driver hackers don't go through new_slave->next = bond->first_slave;
* the same confusion stage I did trying to figure this out, the new_slave->prev = bond->first_slave->prev;
* slaves are stored in a double linked circular list, sortof. new_slave->next->prev = new_slave;
* In the ->next direction, the last slave points to the first slave, new_slave->prev->next = new_slave;
* bypassing bond; only the slaves are in the ->next direction. }
* In the ->prev direction, however, the first slave points to bond
* and bond points to the last slave.
*
* It looks like a circle with a little bubble hanging off one side
* in the ->prev direction only.
*
* When going through the list once, its best to start at bond->prev
* and go in the ->prev direction, testing for bond. Doing this
* in the ->next direction doesn't work. Trust me, I know this now.
* :) -mts 2002.03.14
*/
new_slave->prev = bond->prev;
new_slave->prev->next = new_slave;
bond->prev = new_slave;
new_slave->next = bond->next;
update_slave_cnt(bond, 1); bond->slave_cnt++;
} }
...@@ -1064,8 +1025,10 @@ static void bond_mc_add(struct bonding *bond, void *addr, int alen) ...@@ -1064,8 +1025,10 @@ static void bond_mc_add(struct bonding *bond, void *addr, int alen)
dev_mc_add(bond->current_slave->dev, addr, alen, 0); dev_mc_add(bond->current_slave->dev, addr, alen, 0);
} else { } else {
struct slave *slave; struct slave *slave;
for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) int i;
bond_for_each_slave(bond, slave, i) {
dev_mc_add(slave->dev, addr, alen, 0); dev_mc_add(slave->dev, addr, alen, 0);
}
} }
} }
...@@ -1081,8 +1044,10 @@ static void bond_mc_delete(struct bonding *bond, void *addr, int alen) ...@@ -1081,8 +1044,10 @@ static void bond_mc_delete(struct bonding *bond, void *addr, int alen)
dev_mc_delete(bond->current_slave->dev, addr, alen, 0); dev_mc_delete(bond->current_slave->dev, addr, alen, 0);
} else { } else {
struct slave *slave; struct slave *slave;
for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) int i;
bond_for_each_slave(bond, slave, i) {
dev_mc_delete(slave->dev, addr, alen, 0); dev_mc_delete(slave->dev, addr, alen, 0);
}
} }
} }
...@@ -1133,9 +1098,9 @@ static void bond_set_promiscuity(struct bonding *bond, int inc) ...@@ -1133,9 +1098,9 @@ static void bond_set_promiscuity(struct bonding *bond, int inc)
} }
} else { } else {
struct slave *slave; struct slave *slave;
for (slave = bond->prev; slave != (struct slave *)bond; int i;
slave = slave->prev) { bond_for_each_slave(bond, slave, i) {
dev_set_promiscuity(slave->dev, inc); dev_set_promiscuity(slave->dev, inc);
} }
} }
...@@ -1151,9 +1116,11 @@ static void bond_set_allmulti(struct bonding *bond, int inc) ...@@ -1151,9 +1116,11 @@ static void bond_set_allmulti(struct bonding *bond, int inc)
if (bond->current_slave != NULL) if (bond->current_slave != NULL)
dev_set_allmulti(bond->current_slave->dev, inc); dev_set_allmulti(bond->current_slave->dev, inc);
} else { } else {
struct slave *slave; struct slave *slave;
for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) int i;
bond_for_each_slave(bond, slave, i) {
dev_set_allmulti(slave->dev, inc); dev_set_allmulti(slave->dev, inc);
}
} }
} }
...@@ -1531,7 +1498,7 @@ static int bond_enslave(struct net_device *master_dev, ...@@ -1531,7 +1498,7 @@ static int bond_enslave(struct net_device *master_dev,
*/ */
bond_set_slave_inactive_flags(new_slave); bond_set_slave_inactive_flags(new_slave);
/* if this is the first slave */ /* if this is the first slave */
if (new_slave == bond->next) { if (bond->slave_cnt == 1) {
SLAVE_AD_INFO(new_slave).id = 1; SLAVE_AD_INFO(new_slave).id = 1;
/* Initialize AD with the number of times that the AD timer is called in 1 second /* Initialize AD with the number of times that the AD timer is called in 1 second
* can be called only after the mac address of the bond is set * can be called only after the mac address of the bond is set
...@@ -1644,7 +1611,6 @@ static int bond_enslave(struct net_device *master_dev, ...@@ -1644,7 +1611,6 @@ static int bond_enslave(struct net_device *master_dev,
static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev) static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev)
{ {
struct bonding *bond; struct bonding *bond;
struct slave *slave;
struct slave *oldactive = NULL; struct slave *oldactive = NULL;
struct slave *newactive = NULL; struct slave *newactive = NULL;
int ret = 0; int ret = 0;
...@@ -1658,15 +1624,9 @@ static int bond_change_active(struct net_device *master_dev, struct net_device * ...@@ -1658,15 +1624,9 @@ static int bond_change_active(struct net_device *master_dev, struct net_device *
bond = (struct bonding *)master_dev->priv; bond = (struct bonding *)master_dev->priv;
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
slave = (struct slave *)bond;
oldactive = bond->current_slave;
while ((slave = slave->prev) != (struct slave *)bond) { oldactive = bond->current_slave;
if(slave_dev == slave->dev) { newactive = bond_get_slave_by_dev(bond, slave_dev);
newactive = slave;
break;
}
}
/* /*
* Changing to the current active: do nothing; return success. * Changing to the current active: do nothing; return success.
...@@ -1699,12 +1659,13 @@ static struct slave *find_best_interface(struct bonding *bond) ...@@ -1699,12 +1659,13 @@ static struct slave *find_best_interface(struct bonding *bond)
struct slave *newslave, *oldslave; struct slave *newslave, *oldslave;
struct slave *bestslave = NULL; struct slave *bestslave = NULL;
int mintime; int mintime;
int i;
newslave = oldslave = bond->current_slave; newslave = oldslave = bond->current_slave;
if (newslave == NULL) { /* there were no active slaves left */ if (newslave == NULL) { /* there were no active slaves left */
if (bond->next != (struct slave *)bond) { /* found one slave */ if (bond->slave_cnt > 0) { /* found one slave */
newslave = bond->next; newslave = bond->first_slave;
} else { } else {
return NULL; /* still no slave, return NULL */ return NULL; /* still no slave, return NULL */
} }
...@@ -1725,7 +1686,7 @@ static struct slave *find_best_interface(struct bonding *bond) ...@@ -1725,7 +1686,7 @@ static struct slave *find_best_interface(struct bonding *bond)
/* remember where to stop iterating over the slaves */ /* remember where to stop iterating over the slaves */
oldslave = newslave; oldslave = newslave;
do { bond_for_each_slave_from(bond, newslave, i, oldslave) {
if (IS_UP(newslave->dev)) { if (IS_UP(newslave->dev)) {
if (newslave->link == BOND_LINK_UP) { if (newslave->link == BOND_LINK_UP) {
return newslave; return newslave;
...@@ -1738,7 +1699,7 @@ static struct slave *find_best_interface(struct bonding *bond) ...@@ -1738,7 +1699,7 @@ static struct slave *find_best_interface(struct bonding *bond)
} }
} }
} }
} while ((newslave = newslave->next) != oldslave); }
return bestslave; return bestslave;
} }
...@@ -1858,9 +1819,8 @@ static int bond_release(struct net_device *master, struct net_device *slave) ...@@ -1858,9 +1819,8 @@ static int bond_release(struct net_device *master, struct net_device *slave)
struct bonding *bond; struct bonding *bond;
struct slave *our_slave; struct slave *our_slave;
struct sockaddr addr; struct sockaddr addr;
int mac_addr_differ;
bond = (struct bonding *)master->priv;
/* slave is not a slave or master is not master of this slave */ /* slave is not a slave or master is not master of this slave */
if (!(slave->flags & IFF_SLAVE) || if (!(slave->flags & IFF_SLAVE) ||
(slave->master != master)) { (slave->master != master)) {
...@@ -1870,89 +1830,87 @@ static int bond_release(struct net_device *master, struct net_device *slave) ...@@ -1870,89 +1830,87 @@ static int bond_release(struct net_device *master, struct net_device *slave)
return -EINVAL; return -EINVAL;
} }
bond = (struct bonding *)master->priv;
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
bond->current_arp_slave = NULL;
our_slave = (struct slave *)bond;
while ((our_slave = our_slave->prev) != (struct slave *)bond) {
if (our_slave->dev == slave) {
int mac_addr_differ = memcmp(bond->device->dev_addr,
our_slave->perm_hwaddr,
ETH_ALEN);
if (!mac_addr_differ && (bond->slave_cnt > 1)) {
printk(KERN_WARNING DRV_NAME
": Warning: the permanent HWaddr of %s "
"- %02X:%02X:%02X:%02X:%02X:%02X - is "
"still in use by %s. Set the HWaddr of "
"%s to a different address to avoid "
"conflicts.\n",
slave->name,
our_slave->perm_hwaddr[0],
our_slave->perm_hwaddr[1],
our_slave->perm_hwaddr[2],
our_slave->perm_hwaddr[3],
our_slave->perm_hwaddr[4],
our_slave->perm_hwaddr[5],
bond->device->name,
slave->name);
}
/* Inform AD package of unbinding of slave. */ our_slave = bond_get_slave_by_dev(bond, slave);
if (bond_mode == BOND_MODE_8023AD) { if (our_slave == NULL) {
/* must be called before the slave is /* not a slave of this bond */
* detached from the list printk(KERN_INFO DRV_NAME
*/ ": %s: %s not enslaved\n",
bond_3ad_unbind_slave(our_slave); master->name, slave->name);
} return -EINVAL;
}
printk(KERN_INFO DRV_NAME mac_addr_differ = memcmp(bond->device->dev_addr,
": %s: releasing %s interface %s\n", our_slave->perm_hwaddr,
master->name, ETH_ALEN);
(our_slave->state == BOND_STATE_ACTIVE) if (!mac_addr_differ && (bond->slave_cnt > 1)) {
? "active" : "backup", printk(KERN_WARNING DRV_NAME
slave->name); ": Warning: the permanent HWaddr of %s "
"- %02X:%02X:%02X:%02X:%02X:%02X - is "
"still in use by %s. Set the HWaddr of "
"%s to a different address to avoid "
"conflicts.\n",
slave->name,
our_slave->perm_hwaddr[0],
our_slave->perm_hwaddr[1],
our_slave->perm_hwaddr[2],
our_slave->perm_hwaddr[3],
our_slave->perm_hwaddr[4],
our_slave->perm_hwaddr[5],
bond->device->name,
slave->name);
}
/* Inform AD package of unbinding of slave. */
if (bond_mode == BOND_MODE_8023AD) {
/* must be called before the slave is
* detached from the list
*/
bond_3ad_unbind_slave(our_slave);
}
/* release the slave from its bond */ printk(KERN_INFO DRV_NAME
bond_detach_slave(bond, our_slave); ": %s: releasing %s interface %s\n",
master->name,
(our_slave->state == BOND_STATE_ACTIVE)
? "active" : "backup",
slave->name);
if (bond->primary_slave == our_slave) { bond->current_arp_slave = NULL;
bond->primary_slave = NULL;
}
if (bond->current_slave == our_slave) { /* release the slave from its bond */
change_active_interface(bond, NULL); bond_detach_slave(bond, our_slave);
reselect_active_interface(bond);
}
if (bond->current_slave == NULL) { if (bond->primary_slave == our_slave) {
printk(KERN_INFO DRV_NAME bond->primary_slave = NULL;
": %s: now running without any active " }
"interface !\n",
master->name);
}
if ((bond_mode == BOND_MODE_TLB) || if (bond->current_slave == our_slave) {
(bond_mode == BOND_MODE_ALB)) { change_active_interface(bond, NULL);
/* must be called only after the slave has been reselect_active_interface(bond);
* detached from the list and the current_slave }
* has been replaced (if our_slave == old_current)
*/
bond_alb_deinit_slave(bond, our_slave);
}
break; if (bond->current_slave == NULL) {
} printk(KERN_INFO DRV_NAME
": %s: now running without any active "
"interface !\n",
master->name);
}
if ((bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
/* must be called only after the slave has been
* detached from the list and the current_slave
* has been replaced (if our_slave == old_current)
*/
bond_alb_deinit_slave(bond, our_slave);
} }
write_unlock_bh(&bond->lock); write_unlock_bh(&bond->lock);
if (our_slave == (struct slave *)bond) {
/* if we get here, it's because the device was not found */
printk(KERN_INFO DRV_NAME
": %s: %s not enslaved\n",
master->name, slave->name);
return -EINVAL;
}
/* If the mode USES_PRIMARY, then we should only remove its /* If the mode USES_PRIMARY, then we should only remove its
* promisc and mc settings if it was the current_slave, but that was * promisc and mc settings if it was the current_slave, but that was
* already taken care of above when we detached the slave * already taken care of above when we detached the slave
...@@ -1996,7 +1954,7 @@ static int bond_release(struct net_device *master, struct net_device *slave) ...@@ -1996,7 +1954,7 @@ static int bond_release(struct net_device *master, struct net_device *slave)
* of the master so it will be set by the application * of the master so it will be set by the application
* to the mac address of the first slave * to the mac address of the first slave
*/ */
if (bond->next == (struct slave *)bond) { if (bond->slave_cnt == 0) {
memset(master->dev_addr, 0, master->addr_len); memset(master->dev_addr, 0, master->addr_len);
} }
...@@ -2017,7 +1975,8 @@ static int bond_release_all(struct net_device *master) ...@@ -2017,7 +1975,8 @@ static int bond_release_all(struct net_device *master)
bond = (struct bonding *)master->priv; bond = (struct bonding *)master->priv;
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
if (bond->next == (struct slave *) bond) {
if (bond->slave_cnt == 0) {
goto out; goto out;
} }
...@@ -2025,7 +1984,7 @@ static int bond_release_all(struct net_device *master) ...@@ -2025,7 +1984,7 @@ static int bond_release_all(struct net_device *master)
bond->primary_slave = NULL; bond->primary_slave = NULL;
change_active_interface(bond, NULL); change_active_interface(bond, NULL);
while ((our_slave = bond->prev) != (struct slave *)bond) { while ((our_slave = bond->first_slave) != NULL) {
/* Inform AD package of unbinding of slave /* Inform AD package of unbinding of slave
* before slave is detached from the list. * before slave is detached from the list.
*/ */
...@@ -2116,6 +2075,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -2116,6 +2075,7 @@ static void bond_mii_monitor(struct net_device *master)
int slave_died = 0; int slave_died = 0;
int do_failover = 0; int do_failover = 0;
int delta_in_ticks = miimon * HZ / 1000; int delta_in_ticks = miimon * HZ / 1000;
int i;
read_lock(&bond->lock); read_lock(&bond->lock);
...@@ -2133,13 +2093,11 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -2133,13 +2093,11 @@ static void bond_mii_monitor(struct net_device *master)
* program could monitor the link itself if needed. * program could monitor the link itself if needed.
*/ */
slave = (struct slave *)bond;
read_lock(&bond->ptrlock); read_lock(&bond->ptrlock);
oldcurrent = bond->current_slave; oldcurrent = bond->current_slave;
read_unlock(&bond->ptrlock); read_unlock(&bond->ptrlock);
while ((slave = slave->prev) != (struct slave *)bond) { bond_for_each_slave(bond, slave, i) {
struct net_device *dev = slave->dev; struct net_device *dev = slave->dev;
int link_state; int link_state;
u16 old_speed = slave->speed; u16 old_speed = slave->speed;
...@@ -2319,7 +2277,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -2319,7 +2277,7 @@ static void bond_mii_monitor(struct net_device *master)
} }
} }
} /* end of while */ } /* end of for */
if (do_failover) { if (do_failover) {
write_lock(&bond->ptrlock); write_lock(&bond->ptrlock);
...@@ -2354,6 +2312,7 @@ static void loadbalance_arp_monitor(struct net_device *master) ...@@ -2354,6 +2312,7 @@ static void loadbalance_arp_monitor(struct net_device *master)
struct slave *slave, *oldcurrent; struct slave *slave, *oldcurrent;
int do_failover = 0; int do_failover = 0;
int the_delta_in_ticks = arp_interval * HZ / 1000; int the_delta_in_ticks = arp_interval * HZ / 1000;
int i;
read_lock(&bond->lock); read_lock(&bond->lock);
...@@ -2377,8 +2336,7 @@ static void loadbalance_arp_monitor(struct net_device *master) ...@@ -2377,8 +2336,7 @@ static void loadbalance_arp_monitor(struct net_device *master)
* TODO: what about up/down delay in arp mode? it wasn't here before * TODO: what about up/down delay in arp mode? it wasn't here before
* so it can wait * so it can wait
*/ */
slave = (struct slave *)bond; bond_for_each_slave(bond, slave, i) {
while ((slave = slave->prev) != (struct slave *)bond) {
if (slave->link != BOND_LINK_UP) { if (slave->link != BOND_LINK_UP) {
...@@ -2488,6 +2446,7 @@ static void activebackup_arp_monitor(struct net_device *master) ...@@ -2488,6 +2446,7 @@ static void activebackup_arp_monitor(struct net_device *master)
struct bonding *bond = (struct bonding *)master->priv; struct bonding *bond = (struct bonding *)master->priv;
struct slave *slave; struct slave *slave;
int the_delta_in_ticks = arp_interval * HZ / 1000; int the_delta_in_ticks = arp_interval * HZ / 1000;
int i;
read_lock(&bond->lock); read_lock(&bond->lock);
...@@ -2504,8 +2463,7 @@ static void activebackup_arp_monitor(struct net_device *master) ...@@ -2504,8 +2463,7 @@ static void activebackup_arp_monitor(struct net_device *master)
* TODO: what about up/down delay in arp mode? it wasn't here before * TODO: what about up/down delay in arp mode? it wasn't here before
* so it can wait * so it can wait
*/ */
slave = (struct slave *)bond; bond_for_each_slave(bond, slave, i) {
while ((slave = slave->prev) != (struct slave *)bond) {
if (slave->link != BOND_LINK_UP) { if (slave->link != BOND_LINK_UP) {
if ((jiffies - slave->dev->last_rx) <= if ((jiffies - slave->dev->last_rx) <=
...@@ -2650,17 +2608,15 @@ static void activebackup_arp_monitor(struct net_device *master) ...@@ -2650,17 +2608,15 @@ static void activebackup_arp_monitor(struct net_device *master)
*/ */
if (slave == NULL) { if (slave == NULL) {
if ((bond->current_arp_slave == NULL) || if (bond->current_arp_slave == NULL) {
(bond->current_arp_slave == (struct slave *)bond)) { bond->current_arp_slave = bond->first_slave;
bond->current_arp_slave = bond->prev;
} }
if (bond->current_arp_slave != (struct slave *)bond) { if (bond->current_arp_slave) {
bond_set_slave_inactive_flags(bond->current_arp_slave); bond_set_slave_inactive_flags(bond->current_arp_slave);
slave = bond->current_arp_slave->next;
/* search for next candidate */ /* search for next candidate */
do { bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) {
if (IS_UP(slave->dev)) { if (IS_UP(slave->dev)) {
slave->link = BOND_LINK_BACK; slave->link = BOND_LINK_BACK;
bond_set_slave_active_flags(slave); bond_set_slave_active_flags(slave);
...@@ -2691,8 +2647,7 @@ static void activebackup_arp_monitor(struct net_device *master) ...@@ -2691,8 +2647,7 @@ static void activebackup_arp_monitor(struct net_device *master)
master->name, master->name,
slave->dev->name); slave->dev->name);
} }
} while ((slave = slave->next) != }
bond->current_arp_slave->next);
} }
} }
...@@ -2714,16 +2669,12 @@ static int bond_sethwaddr(struct net_device *master, struct net_device *slave) ...@@ -2714,16 +2669,12 @@ static int bond_sethwaddr(struct net_device *master, struct net_device *slave)
static int bond_info_query(struct net_device *master, struct ifbond *info) static int bond_info_query(struct net_device *master, struct ifbond *info)
{ {
struct bonding *bond = (struct bonding *)master->priv; struct bonding *bond = (struct bonding *)master->priv;
struct slave *slave;
info->bond_mode = bond_mode; info->bond_mode = bond_mode;
info->num_slaves = 0;
info->miimon = miimon; info->miimon = miimon;
read_lock_bh(&bond->lock); read_lock_bh(&bond->lock);
for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) { info->num_slaves = bond->slave_cnt;
info->num_slaves++;
}
read_unlock_bh(&bond->lock); read_unlock_bh(&bond->lock);
return 0; return 0;
...@@ -2734,21 +2685,22 @@ static int bond_slave_info_query(struct net_device *master, ...@@ -2734,21 +2685,22 @@ static int bond_slave_info_query(struct net_device *master,
{ {
struct bonding *bond = (struct bonding *)master->priv; struct bonding *bond = (struct bonding *)master->priv;
struct slave *slave; struct slave *slave;
int cur_ndx = 0; int i, found = 0;
if (info->slave_id < 0) { if (info->slave_id < 0) {
return -ENODEV; return -ENODEV;
} }
read_lock_bh(&bond->lock); read_lock_bh(&bond->lock);
for (slave = bond->prev; bond_for_each_slave(bond, slave, i) {
slave != (struct slave *)bond && cur_ndx < info->slave_id; if (i == (int)info->slave_id) {
slave = slave->prev) { found = 1;
cur_ndx++; break;
}
} }
read_unlock_bh(&bond->lock); read_unlock_bh(&bond->lock);
if (slave != (struct slave *)bond) { if (found) {
strcpy(info->slave_name, slave->dev->name); strcpy(info->slave_name, slave->dev->name);
info->link = slave->link; info->link = slave->link;
info->state = slave->state; info->state = slave->state;
...@@ -2965,7 +2917,8 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev) ...@@ -2965,7 +2917,8 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev)
{ {
struct slave *slave, *start_at; struct slave *slave, *start_at;
struct bonding *bond = (struct bonding *)dev->priv; struct bonding *bond = (struct bonding *)dev->priv;
struct net_device *device_we_should_send_to = 0; struct net_device *device_we_should_send_to = NULL;
int i;
if (!IS_UP(dev)) { /* bond down */ if (!IS_UP(dev)) { /* bond down */
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -2975,17 +2928,17 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev) ...@@ -2975,17 +2928,17 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev)
read_lock(&bond->lock); read_lock(&bond->lock);
read_lock(&bond->ptrlock); read_lock(&bond->ptrlock);
slave = start_at = bond->current_slave; start_at = bond->current_slave;
read_unlock(&bond->ptrlock); read_unlock(&bond->ptrlock);
if (slave == NULL) { /* we're at the root, get the first slave */ if (start_at == NULL) { /* we're at the root, get the first slave */
/* no suitable interface, frame not sent */ /* no suitable interface, frame not sent */
read_unlock(&bond->lock); read_unlock(&bond->lock);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
} }
do { bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) if (IS_UP(slave->dev)
&& (slave->link == BOND_LINK_UP) && (slave->link == BOND_LINK_UP)
&& (slave->state == BOND_STATE_ACTIVE)) { && (slave->state == BOND_STATE_ACTIVE)) {
...@@ -3004,7 +2957,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev) ...@@ -3004,7 +2957,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev)
} }
device_we_should_send_to = slave->dev; device_we_should_send_to = slave->dev;
} }
} while ((slave = slave->next) != start_at); }
if (device_we_should_send_to) { if (device_we_should_send_to) {
skb->dev = device_we_should_send_to; skb->dev = device_we_should_send_to;
...@@ -3022,6 +2975,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev) ...@@ -3022,6 +2975,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev)
{ {
struct slave *slave, *start_at; struct slave *slave, *start_at;
struct bonding *bond = (struct bonding *)dev->priv; struct bonding *bond = (struct bonding *)dev->priv;
int i;
if (!IS_UP(dev)) { /* bond down */ if (!IS_UP(dev)) { /* bond down */
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -3041,7 +2995,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev) ...@@ -3041,7 +2995,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
do { bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) if (IS_UP(slave->dev)
&& (slave->link == BOND_LINK_UP) && (slave->link == BOND_LINK_UP)
&& (slave->state == BOND_STATE_ACTIVE)) { && (slave->state == BOND_STATE_ACTIVE)) {
...@@ -3057,7 +3011,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev) ...@@ -3057,7 +3011,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev)
read_unlock(&bond->lock); read_unlock(&bond->lock);
return 0; return 0;
} }
} while ((slave = slave->next) != start_at); }
/* no suitable interface, frame not sent */ /* no suitable interface, frame not sent */
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -3076,6 +3030,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -3076,6 +3030,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev)
struct bonding *bond = (struct bonding *)dev->priv; struct bonding *bond = (struct bonding *)dev->priv;
struct ethhdr *data = (struct ethhdr *)skb->data; struct ethhdr *data = (struct ethhdr *)skb->data;
int slave_no; int slave_no;
int i;
if (!IS_UP(dev)) { /* bond down */ if (!IS_UP(dev)) { /* bond down */
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -3083,9 +3038,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -3083,9 +3038,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev)
} }
read_lock(&bond->lock); read_lock(&bond->lock);
slave = bond->prev;
/* we're at the root, get the first slave */
if (bond->slave_cnt == 0) { if (bond->slave_cnt == 0) {
/* no suitable interface, frame not sent */ /* no suitable interface, frame not sent */
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -3093,15 +3046,18 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -3093,15 +3046,18 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; slave_no = (data->h_dest[5]^bond->device->dev_addr[5]) % bond->slave_cnt;
while ( (slave_no > 0) && (slave != (struct slave *)bond) ) { bond_for_each_slave(bond, slave, i) {
slave = slave->prev;
slave_no--; slave_no--;
} if (slave_no < 0) {
break;
}
}
start_at = slave; start_at = slave;
do { bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) if (IS_UP(slave->dev)
&& (slave->link == BOND_LINK_UP) && (slave->link == BOND_LINK_UP)
&& (slave->state == BOND_STATE_ACTIVE)) { && (slave->state == BOND_STATE_ACTIVE)) {
...@@ -3113,7 +3069,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -3113,7 +3069,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev)
read_unlock(&bond->lock); read_unlock(&bond->lock);
return 0; return 0;
} }
} while ((slave = slave->next) != start_at); }
/* no suitable interface, frame not sent */ /* no suitable interface, frame not sent */
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -3173,12 +3129,13 @@ static struct net_device_stats *bond_get_stats(struct net_device *dev) ...@@ -3173,12 +3129,13 @@ static struct net_device_stats *bond_get_stats(struct net_device *dev)
struct bonding *bond = (struct bonding *)dev->priv; struct bonding *bond = (struct bonding *)dev->priv;
struct net_device_stats *stats = &(bond->stats), *sstats; struct net_device_stats *stats = &(bond->stats), *sstats;
struct slave *slave; struct slave *slave;
int i;
memset(stats, 0, sizeof(struct net_device_stats)); memset(stats, 0, sizeof(struct net_device_stats));
read_lock_bh(&bond->lock); read_lock_bh(&bond->lock);
for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) { bond_for_each_slave(bond, slave, i) {
sstats = slave->dev->get_stats(slave->dev); sstats = slave->dev->get_stats(slave->dev);
stats->rx_packets += sstats->rx_packets; stats->rx_packets += sstats->rx_packets;
...@@ -3222,6 +3179,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) ...@@ -3222,6 +3179,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
struct bonding *bond = seq->private; struct bonding *bond = seq->private;
loff_t off = 0; loff_t off = 0;
struct slave *slave; struct slave *slave;
int i;
/* make sure the bond won't be taken away */ /* make sure the bond won't be taken away */
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
...@@ -3231,9 +3189,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) ...@@ -3231,9 +3189,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
return SEQ_START_TOKEN; return SEQ_START_TOKEN;
} }
for (slave = bond->prev; slave != (struct slave *)bond; bond_for_each_slave(bond, slave, i) {
slave = slave->prev) {
if (++off == *pos) { if (++off == *pos) {
return slave; return slave;
} }
...@@ -3249,12 +3205,12 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) ...@@ -3249,12 +3205,12 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++*pos; ++*pos;
if (v == SEQ_START_TOKEN) { if (v == SEQ_START_TOKEN) {
slave = bond->prev; return bond->first_slave;
} else {
slave = slave->prev;
} }
return (slave == (struct slave *) bond) ? NULL : slave; slave = slave->next;
return (slave == bond->first_slave) ? NULL : slave;
} }
static void bond_info_seq_stop(struct seq_file *seq, void *v) static void bond_info_seq_stop(struct seq_file *seq, void *v)
...@@ -3494,8 +3450,9 @@ bond_set_mac_address(struct net_device *dev, void *addr) ...@@ -3494,8 +3450,9 @@ bond_set_mac_address(struct net_device *dev, void *addr)
{ {
struct bonding *bond = (struct bonding *)dev->priv; struct bonding *bond = (struct bonding *)dev->priv;
struct sockaddr *sa = addr, tmp_sa; struct sockaddr *sa = addr, tmp_sa;
struct slave *slave; struct slave *slave, *stop_at;
int error; int error;
int i;
dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
...@@ -3503,8 +3460,22 @@ bond_set_mac_address(struct net_device *dev, void *addr) ...@@ -3503,8 +3460,22 @@ bond_set_mac_address(struct net_device *dev, void *addr)
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
} }
for (slave = bond->prev; slave != (struct slave *)bond; /* Can't hold bond->lock with bh disabled here since
slave = slave->prev) { * some base drivers panic. On the other hand we can't
* hold bond->lock without bh disabled because we'll
* deadlock. The only solution is to rely on the fact
* that we're under rtnl_lock here, and the slaves
* list won't change. This doesn't solve the problem
* of setting the slave's hw address while it is
* transmitting, but the assumption is that the base
* driver can handle that.
*
* TODO: figure out a way to safely iterate the slaves
* list, but without holding a lock around the actual
* call to the base driver.
*/
bond_for_each_slave(bond, slave, i) {
dprintk("slave %p %s\n", slave, slave->dev->name); dprintk("slave %p %s\n", slave, slave->dev->name);
if (slave->dev->set_mac_address == NULL) { if (slave->dev->set_mac_address == NULL) {
error = -EOPNOTSUPP; error = -EOPNOTSUPP;
...@@ -3533,8 +3504,9 @@ bond_set_mac_address(struct net_device *dev, void *addr) ...@@ -3533,8 +3504,9 @@ bond_set_mac_address(struct net_device *dev, void *addr)
memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len); memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len);
tmp_sa.sa_family = dev->type; tmp_sa.sa_family = dev->type;
for (slave = slave->next; slave != bond->next; /* unwind from the first slave that failed to head */
slave = slave->next) { stop_at = slave;
bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
int tmp_error; int tmp_error;
tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa); tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa);
...@@ -3554,14 +3526,29 @@ static inline int ...@@ -3554,14 +3526,29 @@ static inline int
bond_change_mtu(struct net_device *dev, int newmtu) bond_change_mtu(struct net_device *dev, int newmtu)
{ {
struct bonding *bond = (struct bonding *)dev->priv; struct bonding *bond = (struct bonding *)dev->priv;
struct slave *slave; struct slave *slave, *stop_at;
int error; int error;
int i;
dprintk("bond=%p, name=%s, new_mtu=%d\n", bond, dprintk("bond=%p, name=%s, new_mtu=%d\n", bond,
(bond_dev ? bond_dev->name : "None"), new_mtu); (bond_dev ? bond_dev->name : "None"), new_mtu);
for (slave = bond->prev; slave != (struct slave *)bond; /* Can't hold bond->lock with bh disabled here since
slave = slave->prev) { * some base drivers panic. On the other hand we can't
* hold bond->lock without bh disabled because we'll
* deadlock. The only solution is to rely on the fact
* that we're under rtnl_lock here, and the slaves
* list won't change. This doesn't solve the problem
* of setting the slave's MTU while it is
* transmitting, but the assumption is that the base
* driver can handle that.
*
* TODO: figure out a way to safely iterate the slaves
* list, but without holding a lock around the actual
* call to the base driver.
*/
bond_for_each_slave(bond, slave, i) {
dprintk("s %p s->p %p c_m %p\n", slave, dprintk("s %p s->p %p c_m %p\n", slave,
slave->prev, slave->dev->change_mtu); slave->prev, slave->dev->change_mtu);
if (slave->dev->change_mtu) { if (slave->dev->change_mtu) {
...@@ -3590,9 +3577,9 @@ bond_change_mtu(struct net_device *dev, int newmtu) ...@@ -3590,9 +3577,9 @@ bond_change_mtu(struct net_device *dev, int newmtu)
unwind: unwind:
for (slave = slave->next; slave != bond->next; /* unwind from the first slave that failed to head */
slave = slave->next) { stop_at = slave;
bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
if (slave->dev->change_mtu) { if (slave->dev->change_mtu) {
slave->dev->change_mtu(slave->dev, dev->mtu); slave->dev->change_mtu(slave->dev, dev->mtu);
} else { } else {
...@@ -3767,7 +3754,7 @@ static int __init bond_init(struct net_device *dev) ...@@ -3767,7 +3754,7 @@ static int __init bond_init(struct net_device *dev)
rwlock_init(&bond->ptrlock); rwlock_init(&bond->ptrlock);
/* Initialize pointers */ /* Initialize pointers */
bond->next = bond->prev = (struct slave *)bond; bond->first_slave = NULL;
bond->current_slave = NULL; bond->current_slave = NULL;
bond->current_arp_slave = NULL; bond->current_arp_slave = NULL;
bond->primary_slave = NULL; bond->primary_slave = NULL;
......
...@@ -88,12 +88,11 @@ struct slave { ...@@ -88,12 +88,11 @@ struct slave {
* beforehand. * beforehand.
*/ */
struct bonding { struct bonding {
struct slave *next; struct slave *first_slave;
struct slave *prev;
struct slave *current_slave; struct slave *current_slave;
struct slave *primary_slave; struct slave *primary_slave;
struct slave *current_arp_slave; struct slave *current_arp_slave;
__s32 slave_cnt; int slave_cnt; /* never change this value outside the attach/detach wrappers */
rwlock_t lock; rwlock_t lock;
rwlock_t ptrlock; rwlock_t ptrlock;
struct timer_list mii_timer; struct timer_list mii_timer;
...@@ -112,37 +111,45 @@ struct bonding { ...@@ -112,37 +111,45 @@ struct bonding {
struct alb_bond_info alb_info; struct alb_bond_info alb_info;
}; };
/* Forward declarations */ /**
void bond_set_slave_active_flags(struct slave *slave); * bond_for_each_slave_from - iterate the slaves list from a starting point
void bond_set_slave_inactive_flags(struct slave *slave); * @bond: the bond holding this list.
* @pos: current slave.
* @cnt: counter for max number of moves
* @start: starting point.
*
* Caller must hold bond->lock
*/
#define bond_for_each_slave_from(bond, pos, cnt, start) \
for (cnt = 0, pos = start; \
cnt < (bond)->slave_cnt; \
cnt++, pos = (pos)->next)
/** /**
* These functions can be used for iterating the slave list * bond_for_each_slave_from_to - iterate the slaves list from start point to stop point
* (which is circular) * @bond: the bond holding this list.
* Caller must hold bond lock for read * @pos: current slave.
* @cnt: counter for number max of moves
* @start: start point.
* @stop: stop point.
*
* Caller must hold bond->lock
*/ */
extern inline struct slave * #define bond_for_each_slave_from_to(bond, pos, cnt, start, stop) \
bond_get_first_slave(struct bonding *bond) for (cnt = 0, pos = start; \
{ ((cnt < (bond)->slave_cnt) && (pos != (stop)->next)); \
/* if there are no slaves return NULL */ cnt++, pos = (pos)->next)
if (bond->next == (struct slave *)bond) {
return NULL;
}
return bond->next;
}
/** /**
* Caller must hold bond lock for read * bond_for_each_slave - iterate the slaves list from head
* @bond: the bond holding this list.
* @pos: current slave.
* @cnt: counter for max number of moves
*
* Caller must hold bond->lock
*/ */
extern inline struct slave * #define bond_for_each_slave(bond, pos, cnt) \
bond_get_next_slave(struct bonding *bond, struct slave *slave) bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave)
{
/* If we have reached the last slave return NULL */
if (slave->next == bond->next) {
return NULL;
}
return slave->next;
}
/** /**
* Returns NULL if the net_device does not belong to any of the bond's slaves * Returns NULL if the net_device does not belong to any of the bond's slaves
...@@ -152,19 +159,16 @@ bond_get_next_slave(struct bonding *bond, struct slave *slave) ...@@ -152,19 +159,16 @@ bond_get_next_slave(struct bonding *bond, struct slave *slave)
extern inline struct slave * extern inline struct slave *
bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev)
{ {
struct slave *our_slave = bond->next; struct slave *slave = NULL;
int i;
/* check if the list of slaves is empty */ bond_for_each_slave(bond, slave, i) {
if (our_slave == (struct slave *)bond) { if (slave->dev == slave_dev) {
return NULL;
}
for (; our_slave; our_slave = bond_get_next_slave(bond, our_slave)) {
if (our_slave->dev == slave_dev) {
break; break;
} }
} }
return our_slave;
return slave;
} }
extern inline struct bonding * extern inline struct bonding *
...@@ -177,5 +181,9 @@ bond_get_bond_by_slave(struct slave *slave) ...@@ -177,5 +181,9 @@ bond_get_bond_by_slave(struct slave *slave)
return (struct bonding *)slave->dev->master->priv; return (struct bonding *)slave->dev->master->priv;
} }
/* Forward declarations */
void bond_set_slave_active_flags(struct slave *slave);
void bond_set_slave_inactive_flags(struct slave *slave);
#endif /* _LINUX_BONDING_H */ #endif /* _LINUX_BONDING_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment