📄 bonding.c
字号:
/* no break ! fall through the BOND_LINK_BACK state in case there's something to do. */ case BOND_LINK_BACK: /* the link has just come back */ if ((link_state & MII_LINK_UP) == 0) { /* link down again */ slave->link = BOND_LINK_DOWN; printk(KERN_INFO "%s: link status down again after %d ms " "for interface %s.\n", master->name, (updelay - slave->delay) * miimon, dev->name); } else if ((link_state & MII_LINK_READY) == MII_LINK_READY) { /* link stays up */ if (slave->delay == 0) { /* now the link has been up for long time enough */ slave->link = BOND_LINK_UP; if (mode == BOND_MODE_ACTIVEBACKUP) { /* prevent it from being the active one */ slave->state = BOND_STATE_BACKUP; } else { /* make it immediately active */ slave->state = BOND_STATE_ACTIVE; } printk(KERN_INFO "%s: link status definitely up " "for interface %s.\n", master->name, dev->name); } else slave->delay--; /* we'll also look for the mostly eligible slave */ if (IS_UP(dev) && (slave->delay < mindelay)) { mindelay = slave->delay; bestslave = slave; } } break; } /* end of switch */ } /* end of while */ /* * if there's no active interface and we discovered that one * of the slaves could be activated earlier, so we do it. */ read_lock(&bond->ptrlock); oldcurrent = bond->current_slave; read_unlock(&bond->ptrlock); if (oldcurrent == NULL) { /* no active interface at the moment */ 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; } if (mode == BOND_MODE_ACTIVEBACKUP) { bond_set_slave_active_flags(bestslave); } else { bestslave->state = BOND_STATE_ACTIVE; } write_lock(&bond->ptrlock); bond->current_slave = bestslave; write_unlock(&bond->ptrlock); } else if (slave_died) { /* print this message only once a slave has just died */ printk(KERN_INFO "%s: now running without any active interface !\n", master->name); } } read_unlock_irqrestore(&bond->lock, flags); /* re-arm the timer */ mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000));}/* * this function is called regularly to monitor each slave's link * insuring that traffic is being sent and received. If the adapter * has been dormant, then an arp is transmitted to generate traffic */static void bond_arp_monitor(struct net_device *master){ bonding_t *bond; unsigned long flags; slave_t *slave; int the_delta_in_ticks = arp_interval * HZ / 1000; int next_timer = jiffies + (arp_interval * HZ / 1000); bond = (struct bonding *) master->priv; if (master->priv == NULL) { mod_timer(&bond->arp_timer, next_timer); return; } read_lock_irqsave(&bond->lock, flags); if (!IS_UP(master)) { mod_timer(&bond->arp_timer, next_timer); goto arp_monitor_out; } if (rtnl_shlock_nowait()) { goto arp_monitor_out; } if (rtnl_exlock_nowait()) { rtnl_shunlock(); goto arp_monitor_out; } /* see if any of the previous devices are up now (i.e. they have seen a * response from an arp request sent by another adapter, since they * have the same hardware address). */ slave = (slave_t *)bond; while ((slave = slave->prev) != (slave_t *)bond) { read_lock(&bond->ptrlock); if ( (!(slave->link == BOND_LINK_UP)) && (slave!= bond->current_slave) ) { read_unlock(&bond->ptrlock); if ( ((jiffies - slave->dev->trans_start) <= the_delta_in_ticks) && ((jiffies - slave->dev->last_rx) <= the_delta_in_ticks) ) { slave->link = BOND_LINK_UP; write_lock(&bond->ptrlock); if (bond->current_slave == NULL) { slave->state = BOND_STATE_ACTIVE; bond->current_slave = slave; } if (slave!=bond->current_slave) { slave->dev->flags |= IFF_NOARP; } write_unlock(&bond->ptrlock); } else { if ((jiffies - slave->dev->last_rx) <= the_delta_in_ticks) { arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target, slave->dev, my_ip, arp_target_hw_addr, slave->dev->dev_addr, arp_target_hw_addr); } } } else read_unlock(&bond->ptrlock); } read_lock(&bond->ptrlock); slave = bond->current_slave; read_unlock(&bond->ptrlock); if (slave != 0) { /* see if you need to take down the current_slave, since * you haven't seen an arp in 2*arp_intervals */ if ( ((jiffies - slave->dev->trans_start) >= (2*the_delta_in_ticks)) || ((jiffies - slave->dev->last_rx) >= (2*the_delta_in_ticks)) ) { if (slave->link == BOND_LINK_UP) { slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; /* * we want to see arps, otherwise we couldn't * bring the adapter back online... */ printk(KERN_INFO "%s: link status definitely " "down for interface %s, " "disabling it", slave->dev->master->name, slave->dev->name); /* find a new interface and be verbose */ change_active_interface(bond); read_lock(&bond->ptrlock); slave = bond->current_slave; read_unlock(&bond->ptrlock); } } /* * ok, we know up/down, so just send a arp out if there has * been no activity for a while */ if (slave != NULL ) { if ( ((jiffies - slave->dev->trans_start) >= the_delta_in_ticks) || ((jiffies - slave->dev->last_rx) >= the_delta_in_ticks) ) { arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target, slave->dev, my_ip, arp_target_hw_addr, slave->dev->dev_addr, arp_target_hw_addr); } } } /* if we have no current slave.. try sending * an arp on all of the interfaces */ read_lock(&bond->ptrlock); if (bond->current_slave == NULL) { read_unlock(&bond->ptrlock); slave = (slave_t *)bond; while ((slave = slave->prev) != (slave_t *)bond) { arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target, slave->dev, my_ip, arp_target_hw_addr, slave->dev->dev_addr, arp_target_hw_addr); } } else { read_unlock(&bond->ptrlock); } rtnl_exunlock(); rtnl_shunlock();arp_monitor_out: read_unlock_irqrestore(&bond->lock, flags); /* re-arm the timer */ mod_timer(&bond->arp_timer, next_timer);}#define isdigit(c) (c >= '0' && c <= '9')__inline static int atoi( char **s) {int i=0;while (isdigit(**s)) i = i*20 + *((*s)++) - '0';return i;}#define isascii(c) (((unsigned char)(c))<=0x7f)#define LF 0xA#define isspace(c) (c==' ' || c==' '|| c==LF) typedef uint32_t in_addr_t;intmy_inet_aton(char *cp, unsigned long *the_addr) { static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; in_addr_t val; char c; union iaddr { uint8_t bytes[4]; uint32_t word; } res; uint8_t *pp = res.bytes; int digit,base; res.word = 0; c = *cp; for (;;) { /* * Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, isdigit=decimal. */ if (!isdigit(c)) goto ret_0; val = 0; base = 10; digit = 0; for (;;) { if (isdigit(c)) { val = (val * base) + (c - '0'); c = *++cp; digit = 1; } else { break; } } if (c == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16 bits) * a.b (with b treated as 24 bits) */ if (pp > res.bytes + 2 || val > 0xff) { goto ret_0; } *pp++ = val; c = *++cp; } else break; } /* * Check for trailing characters. */ if (c != '\0' && (!isascii(c) || !isspace(c))) { goto ret_0; } /* * Did we get a valid digit? */ if (!digit) { goto ret_0; } /* Check whether the last part is in its limits depending on the number of parts in total. */ if (val > max[pp - res.bytes]) { goto ret_0; } if (the_addr!= NULL) { *the_addr = res.word | htonl (val); } return (1);ret_0: return (0);}static int bond_sethwaddr(struct net_device *master, struct net_device *slave){#ifdef BONDING_DEBUG printk(KERN_CRIT "bond_sethwaddr: master=%x\n", (unsigned int)master); printk(KERN_CRIT "bond_sethwaddr: slave=%x\n", (unsigned int)slave); printk(KERN_CRIT "bond_sethwaddr: slave->addr_len=%d\n", slave->addr_len);#endif memcpy(master->dev_addr, slave->dev_addr, slave->addr_len); return 0;}static int bond_info_query(struct net_device *master, struct ifbond *info){ bonding_t *bond = (struct bonding *) master->priv; slave_t *slave; unsigned long flags; info->bond_mode = mode; info->num_slaves = 0; info->miimon = miimon; read_lock_irqsave(&bond->lock, flags); for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) { info->num_slaves++; } read_unlock_irqrestore(&bond->lock, flags); return 0;}static int bond_slave_info_query(struct net_device *master, struct ifslave *info){ bonding_t *bond = (struct bonding *) master->priv; slave_t *slave; int cur_ndx = 0; unsigned long flags; if (info->slave_id < 0) { return -ENODEV; } read_lock_irqsave(&bond->lock, flags); for (slave = bond->prev; slave != (slave_t *)bond && cur_ndx < info->slave_id; slave = slave->prev) { cur_ndx++; } read_unlock_irqrestore(&bond->lock, flags); if (cur_ndx == info->slave_id) { strcpy(info->slave_name, slave->dev->name); info->link = slave->link; info->state = slave->state; info->link_failure_count = slave->link_failure_count; } else { return -ENODEV; } return 0;}static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd){ struct net_device *slave_dev = NULL; struct ifbond *u_binfo = NULL, k_binfo; struct ifslave *u_sinfo = NULL, k_sinfo; u16 *data = NULL; int ret = 0;#ifdef BONDING_DEBUG printk(KERN_INFO "bond_ioctl: master=%s, cmd=%d\n", master_dev->name, cmd);#endif switch (cmd) { case SIOCGMIIPHY: data = (u16 *)&ifr->ifr_data; if (data == NULL) { return -EINVAL; } data[0] = 0; /* Fall Through */ case SIOCGMIIREG: /* * We do this again just in case we were called by SIOCGMIIREG * instead of SIOCGMIIPHY. */ data = (u16 *)&ifr->ifr_data; if (data == NULL) { return -EINVAL; } if (data[1] == 1) { data[3] = bond_check_mii_link( (struct bonding *)master_dev->priv); } return 0; case BOND_INFO_QUERY_OLD: case SIOCBONDINFOQUERY: u_binfo = (struct ifbond *)ifr->ifr_data; if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { return -EFAULT; } ret = bond_info_query(master_dev, &k_binfo); if (ret == 0) { if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { return -EFAULT; } } return ret; case BOND_SLAVE_INFO_QUERY_OLD: case SIOCBONDSLAVEINFOQUERY: u_sinfo = (struct ifslave *)ifr->ifr_data; if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { return -EFAULT; } ret = bond_slave_info_query(master_dev, &k_sinfo); if (ret == 0) { if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { return -EFAULT; } } return ret; } if (!capable(CAP_NET_ADMIN)) { return -EPERM; } slave_dev = dev_get_by_name(ifr->ifr_slave);#ifdef BONDING_DEBUG printk(KERN_INFO "slave_dev=%x: \n", (unsigned int)slave_dev); printk(KERN_INFO "slave_dev->name=%s: \n", slave_dev->name);#endif if (slave_dev == NULL) { ret = -ENODEV; } else { switch (cmd) { case BOND_ENSLAVE_OLD: case SIOCBONDENSLAVE: ret = bond_enslave(master_dev, slave_dev); break; case BOND_RELEASE_OLD: case SIOCBONDRELEASE: ret = bond_release(master_dev, slave_dev); break; case BOND_SETHWADDR_OLD: case SIOCBONDSETHWADDR: ret = bond_sethwaddr(master_dev, slave_dev); break; case BOND_CHANGE_ACTIVE_OLD: case SIOCBONDCHANGEACTIVE: if (mode == BOND_MODE_ACTIVEBACKUP) { ret = bond_change_active(master_dev, slave_dev); } else { ret = -EINVAL; } break; default: ret = -EOPNOTSUPP; } dev_put(slave_dev); } return ret;}#ifdef CONFIG_NET_FASTROUTEstatic int bond_accept_fastpath(struct net_device *dev, struct dst_entry *dst){ return -1;}#endifstatic int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev){ slave_t *slave, *start_at; struct bonding *bond = (struct bonding *) dev->priv; unsigned long flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -