patch-2.4.20 linux-2.4.20/drivers/net/bonding.c
Next file: linux-2.4.20/drivers/net/cs89x0.h
Previous file: linux-2.4.20/drivers/net/au1000_eth.h
Back to the patch index
Back to the overall index
- Lines: 337
- Date:
Thu Nov 28 15:53:13 2002
- Orig file:
linux-2.4.19/drivers/net/bonding.c
- Orig date:
Fri Aug 2 17:39:44 2002
diff -urN linux-2.4.19/drivers/net/bonding.c linux-2.4.20/drivers/net/bonding.c
@@ -176,6 +176,21 @@
* Steve Mead <steve.mead at comdev dot cc>
* - Port Gleb Natapov's multicast support patchs from 2.4.12
* to 2.4.18 adding support for multicast.
+ *
+ * 2002/06/17 - Tony Cureington <tony.cureington * hp_com>
+ * - corrected uninitialized pointer (ifr.ifr_data) in bond_check_dev_link;
+ * actually changed function to use ETHTOOL, then MIIPHY, and finally
+ * MIIREG to determine the link status
+ * - fixed bad ifr_data pointer assignments in bond_ioctl
+ * - corrected mode 1 being reported as active-backup in bond_get_info;
+ * also added text to distinguish type of load balancing (rr or xor)
+ * - change arp_ip_target module param from "1-12s" (array of 12 ptrs)
+ * to "s" (a single ptr)
+ *
+ * 2002/09/18 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - Fixed up bond_check_dev_link() (and callers): removed some magic
+ * numbers, banished local MII_ defines, wrapped ioctl calls to
+ * prevent EFAULT errors
*/
#include <linux/config.h>
@@ -210,21 +225,15 @@
#include <linux/smp.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+
/* monitor all links that often (in milliseconds). <=0 disables monitoring */
#ifndef BOND_LINK_MON_INTERV
#define BOND_LINK_MON_INTERV 0
#endif
-#undef MII_LINK_UP
-#define MII_LINK_UP 0x04
-
-#undef MII_ENDOF_NWAY
-#define MII_ENDOF_NWAY 0x20
-
-#undef MII_LINK_READY
-#define MII_LINK_READY (MII_LINK_UP)
-
#ifndef BOND_LINK_ARP_INTERV
#define BOND_LINK_ARP_INTERV 0
#endif
@@ -253,7 +262,7 @@
MODULE_PARM(mode, "i");
MODULE_PARM(arp_interval, "i");
MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
-MODULE_PARM(arp_ip_target, "1-12s");
+MODULE_PARM(arp_ip_target, "s");
MODULE_PARM_DESC(arp_ip_target, "arp target in n.n.n.n form");
MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
MODULE_PARM(updelay, "i");
@@ -374,33 +383,75 @@
return slave;
}
+/*
+ * Less bad way to call ioctl from within the kernel; this needs to be
+ * done some other way to get the call out of interrupt context.
+ * Needs "ioctl" variable to be supplied by calling context.
+ */
+#define IOCTL(dev, arg, cmd) ({ \
+ int ret; \
+ mm_segment_t fs = get_fs(); \
+ set_fs(get_ds()); \
+ ret = ioctl(dev, arg, cmd); \
+ set_fs(fs); \
+ ret; })
+
/*
- * if <dev> supports MII link status reporting, check its link
- * and report it as a bit field in a short int :
- * - 0x04 means link is up,
- * - 0x20 means end of autonegociation
- * If the device doesn't support MII, then we only report 0x24,
- * meaning that the link is up and running since we can't check it.
+ * if <dev> supports MII link status reporting, check its link status.
+ *
+ * Return either BMSR_LSTATUS, meaning that the link is up (or we
+ * can't tell and just pretend it is), or 0, meaning that the link is
+ * down.
*/
static u16 bond_check_dev_link(struct net_device *dev)
{
static int (* ioctl)(struct net_device *, struct ifreq *, int);
struct ifreq ifr;
- u16 *data = (u16 *)&ifr.ifr_data;
-
- /* data[0] automagically filled by the ioctl */
- data[1] = 1; /* MII location 1 reports Link Status */
+ struct mii_ioctl_data *mii;
+ struct ethtool_value etool;
+
+ ioctl = dev->do_ioctl;
+ if (ioctl) {
+ /* TODO: set pointer to correct ioctl on a per team member */
+ /* bases to make this more efficient. that is, once */
+ /* we determine the correct ioctl, we will always */
+ /* call it and not the others for that team */
+ /* member. */
+
+ /* try SOICETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
+ /* for a period of time; we need to encourage link status */
+ /* be reported by network drivers in real time; if the */
+ /* value is cached, the mmimon module parm may have no */
+ /* effect... */
+ etool.cmd = ETHTOOL_GLINK;
+ ifr.ifr_data = (char*)&etool;
+ if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) {
+ if (etool.data == 1) {
+ return BMSR_LSTATUS;
+ }
+ else {
+ return(0);
+ }
+ }
+
+ /*
+ * We cannot assume that SIOCGMIIPHY will also read a
+ * register; not all network drivers support that.
+ */
+
+ /* Yes, the mii is overlaid on the ifreq.ifr_ifru */
+ mii = (struct mii_ioctl_data *)&ifr.ifr_data;
+ if (IOCTL(dev, &ifr, SIOCGMIIPHY) != 0) {
+ return BMSR_LSTATUS; /* can't tell */
+ }
+
+ mii->reg_num = MII_BMSR;
+ if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) {
+ return mii->val_out & BMSR_LSTATUS;
+ }
- if (((ioctl = dev->do_ioctl) != NULL) && /* ioctl to access MII */
- (ioctl(dev, &ifr, SIOCGMIIPHY) == 0)) {
- /* now, data[3] contains info about link status :
- - data[3] & 0x04 means link up
- - data[3] & 0x20 means end of auto-negociation
- */
- return data[3];
- } else {
- return MII_LINK_READY; /* spoof link up ( we can't check it) */
}
+ return BMSR_LSTATUS; /* spoof link up ( we can't check it) */
}
static u16 bond_check_mii_link(bonding_t *bond)
@@ -414,7 +465,7 @@
read_unlock(&bond->ptrlock);
read_unlock_irqrestore(&bond->lock, flags);
- return (has_active_interface ? MII_LINK_READY : 0);
+ return (has_active_interface ? BMSR_LSTATUS : 0);
}
static int bond_open(struct net_device *dev)
@@ -598,12 +649,6 @@
*/
write_lock_irqsave(&bond->lock, flags);
- /*
- * Lock the master device so that noone trys to transmit
- * while we're changing things
- */
- spin_lock_bh(&master->xmit_lock);
-
/* set promiscuity flag to slaves */
if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) )
bond_set_promiscuity(bond, 1);
@@ -637,7 +682,6 @@
bond_mc_list_destroy (bond);
bond_mc_list_copy (master->mc_list, bond, GFP_KERNEL);
- spin_unlock_bh(&master->xmit_lock);
write_unlock_irqrestore(&bond->lock, flags);
}
@@ -759,8 +803,8 @@
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)) {
+ if ((miimon <= 0) ||
+ (bond_check_dev_link(slave_dev) == BMSR_LSTATUS)) {
#ifdef BONDING_DEBUG
printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n");
#endif
@@ -1182,7 +1226,7 @@
switch (slave->link) {
case BOND_LINK_UP: /* the link was up */
- if ((link_state & MII_LINK_UP) == MII_LINK_UP) {
+ if (link_state == BMSR_LSTATUS) {
/* link stays up, tell that this one
is immediately available */
if (IS_UP(dev) && (mindelay > -2)) {
@@ -1218,7 +1262,7 @@
ensure proper action to be taken
*/
case BOND_LINK_FAIL: /* the link has just gone down */
- if ((link_state & MII_LINK_UP) == 0) {
+ if (link_state != BMSR_LSTATUS) {
/* link stays down */
if (slave->delay <= 0) {
/* link down for too long time */
@@ -1247,7 +1291,7 @@
} else {
slave->delay--;
}
- } else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
+ } else {
/* link up again */
slave->link = BOND_LINK_UP;
printk(KERN_INFO
@@ -1266,7 +1310,7 @@
}
break;
case BOND_LINK_DOWN: /* the link was down */
- if ((link_state & MII_LINK_READY) != MII_LINK_READY) {
+ if (link_state != BMSR_LSTATUS) {
/* the link stays down, nothing more to do */
break;
} else { /* link going up */
@@ -1288,7 +1332,7 @@
case there's something to do.
*/
case BOND_LINK_BACK: /* the link has just come back */
- if ((link_state & MII_LINK_UP) == 0) {
+ if (link_state != BMSR_LSTATUS) {
/* link down again */
slave->link = BOND_LINK_DOWN;
printk(KERN_INFO
@@ -1297,8 +1341,7 @@
master->name,
(updelay - slave->delay) * miimon,
dev->name);
- }
- else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
+ } else {
/* link stays up */
if (slave->delay == 0) {
/* now the link has been up for long time enough */
@@ -1707,7 +1750,7 @@
switch (cmd) {
case SIOCGMIIPHY:
- data = (u16 *)&ifr->ifr_data;
+ data = (u16 *)ifr->ifr_data;
if (data == NULL) {
return -EINVAL;
}
@@ -1718,7 +1761,7 @@
* We do this again just in case we were called by SIOCGMIIREG
* instead of SIOCGMIIPHY.
*/
- data = (u16 *)&ifr->ifr_data;
+ data = (u16 *)ifr->ifr_data;
if (data == NULL) {
return -EINVAL;
}
@@ -2035,7 +2078,28 @@
link = bond_check_mii_link(bond);
len += sprintf(buf + len, "Bonding Mode: ");
- len += sprintf(buf + len, "%s\n", mode ? "active-backup" : "load balancing");
+
+ switch (mode) {
+ case BOND_MODE_ACTIVEBACKUP:
+ len += sprintf(buf + len, "%s\n",
+ "active-backup");
+ break;
+
+ case BOND_MODE_ROUNDROBIN:
+ len += sprintf(buf + len, "%s\n",
+ "load balancing (round-robin)");
+ break;
+
+ case BOND_MODE_XOR:
+ len += sprintf(buf + len, "%s\n",
+ "load balancing (xor)");
+ break;
+
+ default:
+ len += sprintf(buf + len, "%s\n",
+ "unknown");
+ break;
+ }
if (mode == BOND_MODE_ACTIVEBACKUP) {
read_lock_irqsave(&bond->lock, flags);
@@ -2051,7 +2115,7 @@
len += sprintf(buf + len, "MII Status: ");
len += sprintf(buf + len,
- link == MII_LINK_READY ? "up\n" : "down\n");
+ link == BMSR_LSTATUS ? "up\n" : "down\n");
len += sprintf(buf + len, "MII Polling Interval (ms): %d\n",
miimon);
len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay);
@@ -2282,7 +2346,32 @@
}
memset(dev_bonds, 0, max_bonds*sizeof(struct net_device));
+ if (updelay < 0) {
+ printk(KERN_WARNING
+ "bonding_init(): updelay module parameter (%d), "
+ "not in range 0-%d, so it was reset to 0\n",
+ updelay, INT_MAX);
+ updelay = 0;
+ }
+
+ if (downdelay < 0) {
+ printk(KERN_WARNING
+ "bonding_init(): downdelay module parameter (%d), "
+ "not in range 0-%d, so it was reset to 0\n",
+ downdelay, INT_MAX);
+ downdelay = 0;
+ }
+
+ if (arp_interval < 0) {
+ printk(KERN_WARNING
+ "bonding_init(): arp_interval module parameter (%d), "
+ "not in range 0-%d, so it was reset to %d\n",
+ arp_interval, INT_MAX, BOND_LINK_ARP_INTERV);
+ arp_interval = BOND_LINK_ARP_INTERV;
+ }
+
if (arp_ip_target) {
+ /* TODO: check and log bad ip address */
if (my_inet_aton(arp_ip_target, &arp_target) == 0) {
arp_interval = 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)