📄 bonding.c
字号:
/* * queue to the end of the slaves list, make the first element its * successor, the last one its predecessor, and make it the bond's * predecessor. */ new_slave->prev = bond->prev; new_slave->prev->next = new_slave; bond->prev = new_slave; new_slave->next = bond->next; new_slave->delay = 0; new_slave->link_failure_count = 0; /* check for initial state */ if ((miimon <= 0) || ((bond_check_dev_link(slave_dev) & MII_LINK_READY) == MII_LINK_READY)) {#ifdef BONDING_DEBUG printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n");#endif new_slave->link = BOND_LINK_UP; } else {#ifdef BONDING_DEBUG printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_DOWN\n");#endif new_slave->link = BOND_LINK_DOWN; } /* if we're in active-backup mode, we need one and only one active * interface. The backup interfaces will have their NOARP flag set * because we need them to be completely deaf and not to respond to * any ARP request on the network to avoid fooling a switch. Thus, * since we guarantee that current_slave always point to the last * usable interface, we just have to verify this interface's flag. */ if (mode == BOND_MODE_ACTIVEBACKUP) { if (((bond->current_slave == NULL) || (bond->current_slave->dev->flags & IFF_NOARP)) && (new_slave->link == BOND_LINK_UP)) {#ifdef BONDING_DEBUG printk(KERN_CRIT "This is the first active slave\n");#endif /* first slave or no active slave yet, and this link is OK, so make this interface the active one */ bond->current_slave = new_slave; bond_set_slave_active_flags(new_slave); } else {#ifdef BONDING_DEBUG printk(KERN_CRIT "This is just a backup slave\n");#endif bond_set_slave_inactive_flags(new_slave); } } else {#ifdef BONDING_DEBUG printk(KERN_CRIT "This slave is always active in trunk mode\n");#endif /* always active in trunk mode */ new_slave->state = BOND_STATE_ACTIVE; if (bond->current_slave == NULL) { bond->current_slave = new_slave; } } update_slave_cnt(bond); write_unlock_irqrestore(&bond->lock, flags); /* * !!! This is to support old versions of ifenslave. We can remove * this in 2.5 because our ifenslave takes care of this for us. * We check to see if the master has a mac address yet. If not, * we'll give it the mac address of our slave device. */ for (ndx = 0; ndx < slave_dev->addr_len; ndx++) {#ifdef BONDING_DEBUG printk(KERN_CRIT "Checking ndx=%d of master_dev->dev_addr\n", ndx);#endif if (master_dev->dev_addr[ndx] != 0) {#ifdef BONDING_DEBUG printk(KERN_CRIT "Found non-zero byte at ndx=%d\n", ndx);#endif break; } } if (ndx == slave_dev->addr_len) { /* * We got all the way through the address and it was * all 0's. */#ifdef BONDING_DEBUG printk(KERN_CRIT "%s doesn't have a MAC address yet. ", master_dev->name); printk(KERN_CRIT "Going to give assign it from %s.\n", slave_dev->name);#endif bond_sethwaddr(master_dev, slave_dev); } printk (KERN_INFO "%s: enslaving %s as a%s interface with a%s link.\n", master_dev->name, slave_dev->name, new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", new_slave->link == BOND_LINK_UP ? "n up" : " down"); return 0;}/* * This function changes the active slave to slave <slave_dev>. * It returns -EINVAL in the following cases. * - <slave_dev> is not found in the list. * - There is not active slave now. * - <slave_dev> is already active. * - The link state of <slave_dev> is not BOND_LINK_UP. * - <slave_dev> is not running. * In these cases, this fuction does nothing. * In the other cases, currnt_slave pointer is changed and 0 is returned. */static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev){ bonding_t *bond; slave_t *slave; slave_t *oldactive = NULL; slave_t *newactive = NULL; unsigned long flags; int ret = 0; if (master_dev == NULL || slave_dev == NULL) { return -ENODEV; } bond = (struct bonding *) master_dev->priv; write_lock_irqsave(&bond->lock, flags); slave = (slave_t *)bond; oldactive = bond->current_slave; while ((slave = slave->prev) != (slave_t *)bond) { if(slave_dev == slave->dev) { newactive = slave; break; } } if ((newactive != NULL)&& (oldactive != NULL)&& (newactive != oldactive)&& (newactive->link == BOND_LINK_UP)&& IS_UP(newactive->dev)) { bond_set_slave_inactive_flags(oldactive); bond_set_slave_active_flags(newactive); bond->current_slave = newactive; printk("%s : activate %s(old : %s)\n", master_dev->name, newactive->dev->name, oldactive->dev->name); } else { ret = -EINVAL; } write_unlock_irqrestore(&bond->lock, flags); return ret;}/* Choose a new valid interface from the pool, set it active * and make it the current slave. If no valid interface is * found, the oldest slave in BACK state is choosen and * 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: must put locks around the call to this function if needed. */slave_t *change_active_interface(bonding_t *bond){ slave_t *newslave, *oldslave; slave_t *bestslave = NULL; int mintime; read_lock(&bond->ptrlock); newslave = oldslave = bond->current_slave; read_unlock(&bond->ptrlock); if (newslave == NULL) { /* there were no active slaves left */ if (bond->next != (slave_t *)bond) { /* found one slave */ write_lock(&bond->ptrlock); newslave = bond->current_slave = bond->next; write_unlock(&bond->ptrlock); } else { printk (" but could not find any %s interface.\n", (mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); write_lock(&bond->ptrlock); bond->current_slave = (slave_t *)NULL; write_unlock(&bond->ptrlock); return NULL; /* still no slave, return NULL */ } } mintime = updelay; do { if (IS_UP(newslave->dev)) { if (newslave->link == BOND_LINK_UP) { /* this one is immediately usable */ if (mode == BOND_MODE_ACTIVEBACKUP) { bond_set_slave_active_flags(newslave); printk (" and making interface %s the active one.\n", newslave->dev->name); } else { printk (" and setting pointer to interface %s.\n", newslave->dev->name); } write_lock(&bond->ptrlock); bond->current_slave = newslave; write_unlock(&bond->ptrlock); return newslave; } else if (newslave->link == BOND_LINK_BACK) { /* link up, but waiting for stabilization */ if (newslave->delay < mintime) { mintime = newslave->delay; bestslave = newslave; } } } } while ((newslave = newslave->next) != oldslave); /* no usable backup found, we'll see if we at least got a link that was coming back for a long time, and could possibly already be usable. */ if (bestslave != NULL) { /* early take-over. */ printk (" and making interface %s the active one %d ms earlier.\n", bestslave->dev->name, (updelay - bestslave->delay)*miimon); bestslave->delay = 0; bestslave->link = BOND_LINK_UP; bond_set_slave_active_flags(bestslave); write_lock(&bond->ptrlock); bond->current_slave = bestslave; write_unlock(&bond->ptrlock); return bestslave; } printk (" but could not find any %s interface.\n", (mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); /* absolutely nothing found. let's return NULL */ write_lock(&bond->ptrlock); bond->current_slave = (slave_t *)NULL; write_unlock(&bond->ptrlock); return NULL;}/* * Try to release the slave device <slave> from the bond device <master> * It is legal to access current_slave without a lock because all the function * is write-locked. * * The rules for slave state should be: * for Active/Backup: * Active stays on all backups go down * for Bonded connections: * The first up interface should be left on and all others downed. */static int bond_release(struct net_device *master, struct net_device *slave){ bonding_t *bond; slave_t *our_slave, *old_current; unsigned long flags; if (master == NULL || slave == NULL) { return -ENODEV; } bond = (struct bonding *) master->priv; write_lock_irqsave(&bond->lock, flags); /* master already enslaved, or slave not enslaved, or no slave for this master */ if ((master->flags & IFF_SLAVE) || !(slave->flags & IFF_SLAVE)) { printk (KERN_DEBUG "%s: cannot release %s.\n", master->name, slave->name); write_unlock_irqrestore(&bond->lock, flags); return -EINVAL; } our_slave = (slave_t *)bond; old_current = bond->current_slave; while ((our_slave = our_slave->prev) != (slave_t *)bond) { if (our_slave->dev == slave) { bond_detach_slave(bond, our_slave); printk (KERN_INFO "%s: releasing %s interface %s", master->name, (our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup", slave->name); if (our_slave == old_current) { /* find a new interface and be verbose */ change_active_interface(bond); } else { printk(".\n"); } kfree(our_slave); /* release the slave from its bond */ netdev_set_master(slave, NULL); /* only restore its RUNNING flag if monitoring set it down */ if (slave->flags & IFF_UP) { slave->flags |= IFF_RUNNING; } if (slave->flags & IFF_NOARP || bond->current_slave != NULL) { dev_close(slave); } if (bond->current_slave == NULL) { printk(KERN_INFO "%s: now running without any active interface !\n", master->name); } update_slave_cnt(bond); write_unlock_irqrestore(&bond->lock, flags); return 0; /* deletion OK */ } } /* if we get here, it's because the device was not found */ write_unlock_irqrestore(&bond->lock, flags); printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name); return -EINVAL;}/* * This function releases all slaves. * Warning: must put write-locks around the call to this function. */static int bond_release_all(struct net_device *master){ bonding_t *bond; slave_t *our_slave; struct net_device *slave_dev; if (master == NULL) { return -ENODEV; } if (master->flags & IFF_SLAVE) { return -EINVAL; } bond = (struct bonding *) master->priv; bond->current_slave = NULL; while ((our_slave = bond->prev) != (slave_t *)bond) { slave_dev = our_slave->dev; bond->prev = our_slave->prev; kfree(our_slave); netdev_set_master(slave_dev, NULL); /* only restore its RUNNING flag if monitoring set it down */ if (slave_dev->flags & IFF_UP) slave_dev->flags |= IFF_RUNNING; if (slave_dev->flags & IFF_NOARP) dev_close(slave_dev); } bond->next = (slave_t *)bond; bond->slave_cnt = 0; printk (KERN_INFO "%s: releases all slaves\n", master->name); return 0;}/* this function is called regularly to monitor each slave's link. */static void bond_mii_monitor(struct net_device *master){ bonding_t *bond = (struct bonding *) master->priv; slave_t *slave, *bestslave, *oldcurrent; unsigned long flags; int slave_died = 0; read_lock_irqsave(&bond->lock, flags); /* we will try to read the link status of each of our slaves, and * set their IFF_RUNNING flag appropriately. For each slave not * supporting MII status, we won't do anything so that a user-space * program could monitor the link itself if needed. */ bestslave = NULL; slave = (slave_t *)bond; read_lock(&bond->ptrlock); oldcurrent = bond->current_slave; read_unlock(&bond->ptrlock); while ((slave = slave->prev) != (slave_t *)bond) { /* use updelay+1 to match an UP slave even when updelay is 0 */ int mindelay = updelay + 1; struct net_device *dev = slave->dev; u16 link_state; link_state = bond_check_dev_link(dev); switch (slave->link) { case BOND_LINK_UP: /* the link was up */ if ((link_state & MII_LINK_UP) == MII_LINK_UP) { /* link stays up, tell that this one is immediately available */ if (IS_UP(dev) && (mindelay > -2)) { /* -2 is the best case : this slave was already up */ mindelay = -2; bestslave = slave; } break; } else { /* link going down */ slave->link = BOND_LINK_FAIL; slave->delay = downdelay; if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } if (downdelay > 0) { printk (KERN_INFO "%s: link status down for %sinterface " "%s, disabling it in %d ms.\n", master->name, IS_UP(dev) ? ((mode == BOND_MODE_ACTIVEBACKUP) ? ((slave == oldcurrent) ? "active " : "backup ") : "") : "idle ", dev->name, downdelay * miimon); } } /* no break ! fall through the BOND_LINK_FAIL test to ensure proper action to be taken */ case BOND_LINK_FAIL: /* the link has just gone down */ if ((link_state & MII_LINK_UP) == 0) { /* link stays down */ if (slave->delay <= 0) { /* link down for too long time */ slave->link = BOND_LINK_DOWN; /* in active/backup mode, we must completely disable this interface */ if (mode == BOND_MODE_ACTIVEBACKUP) { bond_set_slave_inactive_flags(slave); } printk(KERN_INFO "%s: link status definitely down " "for interface %s, disabling it", master->name, dev->name); read_lock(&bond->ptrlock); if (slave == bond->current_slave) { read_unlock(&bond->ptrlock); /* find a new interface and be verbose */ change_active_interface(bond); } else { read_unlock(&bond->ptrlock); printk(".\n"); } slave_died = 1; } else { slave->delay--; } } else if ((link_state & MII_LINK_READY) == MII_LINK_READY) { /* link up again */ slave->link = BOND_LINK_UP; printk(KERN_INFO "%s: link status up again after %d ms " "for interface %s.\n", master->name, (downdelay - slave->delay) * miimon, dev->name); if (IS_UP(dev) && (mindelay > -1)) { /* -1 is a good case : this slave went down only for a short time */ mindelay = -1; bestslave = slave; } } break; case BOND_LINK_DOWN: /* the link was down */ if ((link_state & MII_LINK_READY) != MII_LINK_READY) { /* the link stays down, nothing more to do */ break; } else { /* link going up */ slave->link = BOND_LINK_BACK; slave->delay = updelay; if (updelay > 0) { /* if updelay == 0, no need to advertise about a 0 ms delay */ printk (KERN_INFO "%s: link status up for interface" " %s, enabling it in %d ms.\n", master->name, dev->name, updelay * miimon); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -