Commit 7527f000 authored by Amir Noam's avatar Amir Noam Committed by Stephen Hemminger

[PATCH] [bonding 2.6] consolidate change_active operations

parent b6d4364c
...@@ -473,6 +473,11 @@ DRV_NAME ".c:v" DRV_VERSION " (" DRV_RELDATE ")\n"; ...@@ -473,6 +473,11 @@ DRV_NAME ".c:v" DRV_VERSION " (" DRV_RELDATE ")\n";
#define MAX_ARP_IP_TARGETS 16 #define MAX_ARP_IP_TARGETS 16
#endif #endif
#define USES_PRIMARY(mode) \
(((mode) == BOND_MODE_ACTIVEBACKUP) || \
((mode) == BOND_MODE_TLB) || \
((mode) == BOND_MODE_ALB))
struct bond_parm_tbl { struct bond_parm_tbl {
char *modename; char *modename;
int mode; int mode;
...@@ -581,6 +586,9 @@ static int bond_enslave(struct net_device *master, struct net_device *slave); ...@@ -581,6 +586,9 @@ static int bond_enslave(struct net_device *master, struct net_device *slave);
static int bond_release(struct net_device *master, struct net_device *slave); static int bond_release(struct net_device *master, struct net_device *slave);
static int bond_release_all(struct net_device *master); static int bond_release_all(struct net_device *master);
static int bond_sethwaddr(struct net_device *master, struct net_device *slave); static int bond_sethwaddr(struct net_device *master, struct net_device *slave);
static void change_active_interface(struct bonding *bond, struct slave *new);
static void reselect_active_interface(struct bonding *bond);
static struct slave *find_best_interface(struct bonding *bond);
/* Caller must hold bond->ptrlock for write */ /* Caller must hold bond->ptrlock for write */
static inline struct slave* static inline struct slave*
...@@ -691,7 +699,7 @@ update_slave_cnt(bonding_t *bond, int incr) ...@@ -691,7 +699,7 @@ update_slave_cnt(bonding_t *bond, int incr)
* belongs to <bond>. It returns <slave> in case it's needed. * belongs to <bond>. It returns <slave> in case it's needed.
* 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 the bond->current_slave pointer was pointing to <slave>,
* it's replaced with bond->next, or NULL if not applicable. * it should be changed by the calling function.
* *
* bond->lock held for writing by caller. * bond->lock held for writing by caller.
*/ */
...@@ -725,17 +733,6 @@ bond_detach_slave(bonding_t *bond, slave_t *slave) ...@@ -725,17 +733,6 @@ bond_detach_slave(bonding_t *bond, slave_t *slave)
update_slave_cnt(bond, -1); update_slave_cnt(bond, -1);
/* no need to hold ptrlock since bond lock is
* already held for writing
*/
if (slave == bond->current_slave) {
if ( bond->next != (slave_t *)bond) { /* found one slave */
bond_assign_current_slave(bond, bond->next);
} else {
bond_assign_current_slave(bond, NULL);
}
}
return slave; return slave;
} }
...@@ -1578,9 +1575,7 @@ static int bond_enslave(struct net_device *master_dev, ...@@ -1578,9 +1575,7 @@ static int bond_enslave(struct net_device *master_dev,
#endif #endif
/* first slave or no active slave yet, and this link /* first slave or no active slave yet, and this link
is OK, so make this interface the active one */ is OK, so make this interface the active one */
bond_assign_current_slave(bond, new_slave); change_active_interface(bond, new_slave);
bond_set_slave_active_flags(new_slave);
bond_mc_update(bond, new_slave, NULL);
} }
else { else {
#ifdef BONDING_DEBUG #ifdef BONDING_DEBUG
...@@ -1630,7 +1625,7 @@ static int bond_enslave(struct net_device *master_dev, ...@@ -1630,7 +1625,7 @@ static int bond_enslave(struct net_device *master_dev,
/* first slave or no active slave yet, and this link /* first slave or no active slave yet, and this link
* is OK, so make this interface the active one * is OK, so make this interface the active one
*/ */
bond_assign_current_slave(bond, new_slave); change_active_interface(bond, new_slave);
} }
/* if there is a primary slave, remember it */ /* if there is a primary slave, remember it */
...@@ -1737,6 +1732,13 @@ static int bond_change_active(struct net_device *master_dev, struct net_device * ...@@ -1737,6 +1732,13 @@ static int bond_change_active(struct net_device *master_dev, struct net_device *
return -ENODEV; return -ENODEV;
} }
/* Verify that master_dev is indeed the master of slave_dev */
if (!(slave_dev->flags & IFF_SLAVE) ||
(slave_dev->master != master_dev)) {
return -EINVAL;
}
bond = (struct bonding *) master_dev->priv; bond = (struct bonding *) master_dev->priv;
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
slave = (slave_t *)bond; slave = (slave_t *)bond;
...@@ -1761,16 +1763,7 @@ static int bond_change_active(struct net_device *master_dev, struct net_device * ...@@ -1761,16 +1763,7 @@ static int bond_change_active(struct net_device *master_dev, struct net_device *
(oldactive != NULL)&& (oldactive != NULL)&&
(newactive->link == BOND_LINK_UP)&& (newactive->link == BOND_LINK_UP)&&
IS_UP(newactive->dev)) { IS_UP(newactive->dev)) {
if (bond_mode == BOND_MODE_ACTIVEBACKUP) { change_active_interface(bond, newactive);
bond_set_slave_inactive_flags(oldactive);
bond_set_slave_active_flags(newactive);
}
bond_mc_update(bond, newactive, oldactive);
bond_assign_current_slave(bond, newactive);
printk("%s : activate %s(old : %s)\n",
master_dev->name, newactive->dev->name,
oldactive->dev->name);
} else { } else {
ret = -EINVAL; ret = -EINVAL;
} }
...@@ -1778,47 +1771,26 @@ static int bond_change_active(struct net_device *master_dev, struct net_device * ...@@ -1778,47 +1771,26 @@ static int bond_change_active(struct net_device *master_dev, struct net_device *
return ret; return ret;
} }
/* Choose a new valid interface from the pool, set it active /**
* and make it the current slave. If no valid interface is * find_best_interface - select the best available slave to be the active one
* found, the oldest slave in BACK state is choosen and * @bond: our bonding struct
* activated. If none is found, it's considered as no
* interfaces left so the current slave is set to NULL.
* The result is a pointer to the current slave.
*
* Since this function sends messages tails through printk, the caller
* must have started something like `printk(KERN_INFO "xxxx ");'.
* *
* Warning: Caller must hold ptrlock for writing. * Warning: Caller must hold ptrlock for writing.
*/ */
slave_t *change_active_interface(bonding_t *bond) static struct slave *find_best_interface(struct bonding *bond)
{ {
slave_t *newslave, *oldslave; struct slave *newslave, *oldslave;
slave_t *bestslave = NULL; struct slave *bestslave = NULL;
int mintime; int mintime;
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 != (slave_t *)bond) { /* found one slave */ if (bond->next != (slave_t *)bond) { /* found one slave */
newslave = bond_assign_current_slave(bond, bond->next); newslave = bond->next;
} else { } else {
printk (" but could not find any %s interface.\n",
(bond_mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
bond_assign_current_slave(bond, NULL);
return NULL; /* still no slave, return NULL */ return NULL; /* still no slave, return NULL */
} }
} else if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
/* make sure oldslave doesn't send arps - this could
* cause a ping-pong effect between interfaces since they
* would be able to tx arps - in active backup only one
* slave should be able to tx arps, and that should be
* the current_slave; the only exception is when all
* slaves have gone down, then only one non-current slave can
* send arps at a time; clearing oldslaves' mc list is handled
* later in this function.
*/
bond_set_slave_inactive_flags(oldslave);
} }
mintime = updelay; mintime = updelay;
...@@ -1833,22 +1805,12 @@ slave_t *change_active_interface(bonding_t *bond) ...@@ -1833,22 +1805,12 @@ slave_t *change_active_interface(bonding_t *bond)
newslave = bond->primary_slave; newslave = bond->primary_slave;
} }
/* remember where to stop iterating over the slaves */
oldslave = newslave;
do { do {
if (IS_UP(newslave->dev)) { if (IS_UP(newslave->dev)) {
if (newslave->link == BOND_LINK_UP) { if (newslave->link == BOND_LINK_UP) {
/* this one is immediately usable */
if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
bond_set_slave_active_flags(newslave);
bond_mc_update(bond, newslave, oldslave);
printk (" and making interface %s the active one.\n",
newslave->dev->name);
}
else {
printk (" and setting pointer to interface %s.\n",
newslave->dev->name);
}
bond_assign_current_slave(bond, newslave);
return newslave; return newslave;
} }
else if (newslave->link == BOND_LINK_BACK) { else if (newslave->link == BOND_LINK_BACK) {
...@@ -1861,46 +1823,100 @@ slave_t *change_active_interface(bonding_t *bond) ...@@ -1861,46 +1823,100 @@ slave_t *change_active_interface(bonding_t *bond)
} }
} while ((newslave = newslave->next) != oldslave); } while ((newslave = newslave->next) != oldslave);
/* no usable backup found, we'll see if we at least got a link that was return bestslave;
coming back for a long time, and could possibly already be usable. }
*/
/**
if (bestslave != NULL) { * change_active_interface - change the active slave into the specified one
/* early take-over. */ * @bond: our bonding struct
printk (" and making interface %s the active one %d ms earlier.\n", * @new: the new slave to make the active one
bestslave->dev->name, *
(updelay - bestslave->delay)*miimon); * Set the new slave to the bond's settings and unset them on the old
* current_slave.
bestslave->delay = 0; * Setting include flags, mc-list, promiscuity, allmulti, etc.
bestslave->link = BOND_LINK_UP; *
bestslave->jiffies = jiffies; * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP,
bond_set_slave_active_flags(bestslave); * because it is apparently the best available slave we have, even though its
bond_mc_update(bond, bestslave, oldslave); * updelay hasn't timed out yet.
bond_assign_current_slave(bond, bestslave); *
return bestslave; * Warning: Caller must hold ptrlock for writing.
} */
static void change_active_interface(struct bonding *bond, struct slave *new)
if ((bond_mode == BOND_MODE_ACTIVEBACKUP) && {
(multicast_mode == BOND_MULTICAST_ACTIVE) && struct slave *old = bond->current_slave;
(oldslave != NULL)) {
/* flush bonds (master's) mc_list from oldslave since it wasn't if (old == new) {
* updated (and deleted) above return;
*/ }
bond_mc_list_flush(oldslave->dev, bond->device);
if (bond->device->flags & IFF_PROMISC) { if (new) {
dev_set_promiscuity(oldslave->dev, -1); if (new->link == BOND_LINK_BACK) {
if (USES_PRIMARY(bond_mode)) {
printk (KERN_INFO
"%s: making interface %s the new "
"active one %d ms earlier.\n",
bond->device->name, new->dev->name,
(updelay - new->delay) * miimon);
}
new->delay = 0;
new->link = BOND_LINK_UP;
new->jiffies = jiffies;
if (bond_mode == BOND_MODE_8023AD) {
bond_3ad_handle_link_change(new, BOND_LINK_UP);
}
if ((bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
bond_alb_handle_link_change(bond, new, BOND_LINK_UP);
}
} else {
if (USES_PRIMARY(bond_mode)) {
printk (KERN_INFO
"%s: making interface %s the new active one.\n",
bond->device->name, new->dev->name);
}
} }
if (bond->device->flags & IFF_ALLMULTI) { }
dev_set_allmulti(oldslave->dev, -1);
if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
if (old) {
bond_set_slave_inactive_flags(old);
}
if (new) {
bond_set_slave_active_flags(new);
} }
} }
printk (" but could not find any %s interface.\n", if (USES_PRIMARY(bond_mode)) {
(bond_mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); bond_mc_update(bond, new, old);
}
/* absolutely nothing found. let's return NULL */
bond_assign_current_slave(bond, NULL); bond_assign_current_slave(bond, new);
return NULL; }
/**
* reselect_active_interface - select a new active slave, if needed
* @bond: our bonding struct
*
* This functions shoud be called when one of the following occurs:
* - The old current_slave has been released or lost its link.
* - The primary_slave has got its link back.
* - A slave has got its link back and there's no old current_slave.
*
* Warning: Caller must hold ptrlock for writing.
*/
static void reselect_active_interface(struct bonding *bond)
{
struct slave *best_slave;
best_slave = find_best_interface(bond);
if (best_slave != bond->current_slave) {
change_active_interface(bond, best_slave);
}
} }
/* /*
...@@ -1967,6 +1983,11 @@ static int bond_release(struct net_device *master, struct net_device *slave) ...@@ -1967,6 +1983,11 @@ static int bond_release(struct net_device *master, struct net_device *slave)
bond_3ad_unbind_slave(our_slave); bond_3ad_unbind_slave(our_slave);
} }
printk (KERN_INFO "%s: releasing %s interface %s\n",
master->name,
(our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup",
slave->name);
/* release the slave from its bond */ /* release the slave from its bond */
bond_detach_slave(bond, our_slave); bond_detach_slave(bond, our_slave);
...@@ -1974,18 +1995,11 @@ static int bond_release(struct net_device *master, struct net_device *slave) ...@@ -1974,18 +1995,11 @@ static int bond_release(struct net_device *master, struct net_device *slave)
bond->primary_slave = NULL; bond->primary_slave = NULL;
} }
printk (KERN_INFO "%s: releasing %s interface %s", if (bond->current_slave == our_slave) {
master->name, change_active_interface(bond, NULL);
(our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup", reselect_active_interface(bond);
slave->name);
if (our_slave == old_current) {
/* find a new interface and be verbose */
change_active_interface(bond);
} else {
printk(".\n");
} }
if (bond->current_slave == NULL) { if (bond->current_slave == NULL) {
printk(KERN_INFO printk(KERN_INFO
"%s: now running without any active interface !\n", "%s: now running without any active interface !\n",
...@@ -2274,9 +2288,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -2274,9 +2288,7 @@ static void bond_mii_monitor(struct net_device *master)
write_lock(&bond->ptrlock); write_lock(&bond->ptrlock);
if (slave == bond->current_slave) { if (slave == bond->current_slave) {
/* find a new interface and be verbose */ /* find a new interface and be verbose */
change_active_interface(bond); reselect_active_interface(bond);
} else {
printk(".\n");
} }
write_unlock(&bond->ptrlock); write_unlock(&bond->ptrlock);
slave_died = 1; slave_died = 1;
...@@ -2372,7 +2384,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -2372,7 +2384,7 @@ static void bond_mii_monitor(struct net_device *master)
write_lock(&bond->ptrlock); write_lock(&bond->ptrlock);
if ( (bond->primary_slave != NULL) if ( (bond->primary_slave != NULL)
&& (slave == bond->primary_slave) ) && (slave == bond->primary_slave) )
change_active_interface(bond); reselect_active_interface(bond);
write_unlock(&bond->ptrlock); write_unlock(&bond->ptrlock);
} }
else else
...@@ -2418,40 +2430,8 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -2418,40 +2430,8 @@ static void bond_mii_monitor(struct net_device *master)
/* no active interface at the moment or need to bring up the primary */ /* no active interface at the moment or need to bring up the primary */
if (oldcurrent == NULL) { /* no active interface at the moment */ if (oldcurrent == NULL) { /* no active interface at the moment */
if (bestslave != NULL) { /* last chance to find one ? */ if (bestslave != NULL) { /* last chance to find one ? */
if (bestslave->link == BOND_LINK_UP) {
printk (KERN_INFO
"%s: making interface %s the new active one.\n",
master->name, bestslave->dev->name);
} else {
printk (KERN_INFO
"%s: making interface %s the new "
"active one %d ms earlier.\n",
master->name, bestslave->dev->name,
(updelay - bestslave->delay) * miimon);
bestslave->delay = 0;
bestslave->link = BOND_LINK_UP;
bestslave->jiffies = jiffies;
/* notify ad that the link status has changed */
if (bond_mode == BOND_MODE_8023AD) {
bond_3ad_handle_link_change(bestslave, BOND_LINK_UP);
}
if ((bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
bond_alb_handle_link_change(bond, bestslave, BOND_LINK_UP);
}
}
if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
bond_set_slave_active_flags(bestslave);
bond_mc_update(bond, bestslave, NULL);
} else if (bond_mode != BOND_MODE_8023AD) {
bestslave->state = BOND_STATE_ACTIVE;
}
write_lock(&bond->ptrlock); write_lock(&bond->ptrlock);
bond_assign_current_slave(bond, bestslave); change_active_interface(bond, bestslave);
write_unlock(&bond->ptrlock); write_unlock(&bond->ptrlock);
} else if (slave_died) { } else if (slave_died) {
/* print this message only once a slave has just died */ /* print this message only once a slave has just died */
...@@ -2535,7 +2515,7 @@ static void loadbalance_arp_monitor(struct net_device *master) ...@@ -2535,7 +2515,7 @@ static void loadbalance_arp_monitor(struct net_device *master)
"for interface %s, ", "for interface %s, ",
master->name, master->name,
slave->dev->name); slave->dev->name);
change_active_interface(bond); reselect_active_interface(bond);
} else { } else {
printk(KERN_INFO printk(KERN_INFO
"%s: interface %s is now up\n", "%s: interface %s is now up\n",
...@@ -2567,7 +2547,7 @@ static void loadbalance_arp_monitor(struct net_device *master) ...@@ -2567,7 +2547,7 @@ static void loadbalance_arp_monitor(struct net_device *master)
write_lock(&bond->ptrlock); write_lock(&bond->ptrlock);
if (slave == bond->current_slave) { if (slave == bond->current_slave) {
change_active_interface(bond); reselect_active_interface(bond);
} }
write_unlock(&bond->ptrlock); write_unlock(&bond->ptrlock);
} }
...@@ -2645,9 +2625,7 @@ static void activebackup_arp_monitor(struct net_device *master) ...@@ -2645,9 +2625,7 @@ static void activebackup_arp_monitor(struct net_device *master)
if ((bond->current_slave == NULL) && if ((bond->current_slave == NULL) &&
((jiffies - slave->dev->trans_start) <= ((jiffies - slave->dev->trans_start) <=
the_delta_in_ticks)) { the_delta_in_ticks)) {
bond_assign_current_slave(bond, slave); change_active_interface(bond, slave);
bond_set_slave_active_flags(slave);
bond_mc_update(bond, slave, NULL);
bond->current_arp_slave = NULL; bond->current_arp_slave = NULL;
} else if (bond->current_slave != slave) { } else if (bond->current_slave != slave) {
/* this slave has just come up but we /* this slave has just come up but we
...@@ -2737,7 +2715,8 @@ static void activebackup_arp_monitor(struct net_device *master) ...@@ -2737,7 +2715,8 @@ static void activebackup_arp_monitor(struct net_device *master)
master->name, master->name,
slave->dev->name); slave->dev->name);
write_lock(&bond->ptrlock); write_lock(&bond->ptrlock);
slave = change_active_interface(bond); reselect_active_interface(bond);
slave = bond->current_slave;
write_unlock(&bond->ptrlock); write_unlock(&bond->ptrlock);
bond->current_arp_slave = slave; bond->current_arp_slave = slave;
if (slave != NULL) { if (slave != NULL) {
...@@ -2756,13 +2735,10 @@ static void activebackup_arp_monitor(struct net_device *master) ...@@ -2756,13 +2735,10 @@ static void activebackup_arp_monitor(struct net_device *master)
bond->primary_slave->dev->name); bond->primary_slave->dev->name);
/* primary is up so switch to it */ /* primary is up so switch to it */
bond_set_slave_inactive_flags(slave);
bond_mc_update(bond, bond->primary_slave, slave);
write_lock(&bond->ptrlock); write_lock(&bond->ptrlock);
bond_assign_current_slave(bond, bond->primary_slave); change_active_interface(bond, bond->primary_slave);
write_unlock(&bond->ptrlock); write_unlock(&bond->ptrlock);
slave = bond->primary_slave; slave = bond->primary_slave;
bond_set_slave_active_flags(slave);
slave->jiffies = jiffies; slave->jiffies = jiffies;
} else { } else {
bond->current_arp_slave = NULL; bond->current_arp_slave = NULL;
...@@ -2805,7 +2781,7 @@ static void activebackup_arp_monitor(struct net_device *master) ...@@ -2805,7 +2781,7 @@ static void activebackup_arp_monitor(struct net_device *master)
/* if the link state is up at this point, we /* if the link state is up at this point, we
* mark it down - this can happen if we have * mark it down - this can happen if we have
* simultaneous link failures and * simultaneous link failures and
* change_active_interface doesn't make this * reselect_active_interface doesn't make this
* one the current slave so it is still marked * one the current slave so it is still marked
* up when it is actually down * up when it is actually down
*/ */
...@@ -3056,9 +3032,7 @@ static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd) ...@@ -3056,9 +3032,7 @@ static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd)
break; break;
case BOND_CHANGE_ACTIVE_OLD: case BOND_CHANGE_ACTIVE_OLD:
case SIOCBONDCHANGEACTIVE: case SIOCBONDCHANGEACTIVE:
if ((bond_mode == BOND_MODE_ACTIVEBACKUP) || if (USES_PRIMARY(bond_mode)) {
(bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
ret = bond_change_active(master_dev, slave_dev); ret = bond_change_active(master_dev, slave_dev);
} }
else { else {
...@@ -3388,9 +3362,7 @@ static int bond_read_proc(char *buf, char **start, off_t off, int count, int *eo ...@@ -3388,9 +3362,7 @@ static int bond_read_proc(char *buf, char **start, off_t off, int count, int *eo
len += sprintf(buf + len, "Bonding Mode: %s\n", len += sprintf(buf + len, "Bonding Mode: %s\n",
bond_mode_name()); bond_mode_name());
if ((bond_mode == BOND_MODE_ACTIVEBACKUP) || if (USES_PRIMARY(bond_mode)) {
(bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
read_lock_bh(&bond->lock); read_lock_bh(&bond->lock);
read_lock(&bond->ptrlock); read_lock(&bond->ptrlock);
if (bond->current_slave != NULL) { if (bond->current_slave != NULL) {
...@@ -3905,9 +3877,7 @@ static int __init bonding_init(void) ...@@ -3905,9 +3877,7 @@ static int __init bonding_init(void)
"link failures! see bonding.txt for details.\n"); "link failures! see bonding.txt for details.\n");
} }
if ((primary != NULL) && (bond_mode != BOND_MODE_ACTIVEBACKUP) && if ((primary != NULL) && !USES_PRIMARY(bond_mode)) {
(bond_mode != BOND_MODE_TLB) &&
(bond_mode != BOND_MODE_ALB)){
/* currently, using a primary only makes sense /* currently, using a primary only makes sense
* in active backup, TLB or ALB modes * in active backup, TLB or ALB modes
*/ */
......
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