Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2499

kernel-2.6.18-238.el5.src.rpm

From: Andy Gospodarek <gospo@redhat.com>
Subject: [RHEL5.1 PATCH] bonding: update to driver version 3.1.2
Date: Mon, 4 Jun 2007 16:18:00 -0400
Bugzilla: 210577
Message-Id: <20070604201758.GK5927@gospo.rdu.redhat.com>
Changelog: [net] bonding: update to driver version 3.1.2



Another driver update...this time we are moving the bonding driver
forward to 3.1.2.  This includes several important fixes and gets us
ready for BZ 210577 (hope to be finalized by Wed).

This patch resolves at least BZ 225473 and BZ 223163 and includes at
least one patch already included in RHEL4, so we need that in RHEL5. It
also adds support for bonding 10G interfaces (several customers have
asked about that in various IT/BZs).

I've tested these as have quite a few customers via my test kernels.

---

 drivers/net/bonding/bond_3ad.c   |   70 +++---
 drivers/net/bonding/bond_alb.c   |    8 
 drivers/net/bonding/bond_main.c  |  396 +++++++++++++++++++++++++++------------
 drivers/net/bonding/bond_sysfs.c |   71 ++++++
 drivers/net/bonding/bonding.h    |   38 +++
 include/linux/if.h               |    2 
 include/linux/igmp.h             |    2 
 net/ipv4/igmp.c                  |   23 ++
 8 files changed, 449 insertions(+), 161 deletions(-)

--- linux-2.6.18.x86_64/drivers/net/bonding/bond_3ad.c.gospo	2007-05-22 13:28:54.581424000 -0400
+++ linux-2.6.18.x86_64/drivers/net/bonding/bond_3ad.c	2007-05-22 13:29:13.183807000 -0400
@@ -85,6 +85,7 @@
 #define     AD_LINK_SPEED_BITMASK_10MBPS      0x2
 #define     AD_LINK_SPEED_BITMASK_100MBPS     0x4
 #define     AD_LINK_SPEED_BITMASK_1000MBPS    0x8
+#define     AD_LINK_SPEED_BITMASK_10000MBPS   0x10
 //endalloun
 
 // compare MAC addresses
@@ -99,7 +100,7 @@ static u16 __get_link_speed(struct port 
 static u8 __get_duplex(struct port *port);
 static inline void __initialize_port_locks(struct port *port);
 //conversions
-static void __ntohs_lacpdu(struct lacpdu *lacpdu);
+static void __htons_lacpdu(struct lacpdu *lacpdu);
 static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
 
 
@@ -330,7 +331,8 @@ static inline void __release_rx_machine_
  *     0,
  *     %AD_LINK_SPEED_BITMASK_10MBPS,
  *     %AD_LINK_SPEED_BITMASK_100MBPS,
- *     %AD_LINK_SPEED_BITMASK_1000MBPS
+ *     %AD_LINK_SPEED_BITMASK_1000MBPS,
+ *     %AD_LINK_SPEED_BITMASK_10000MBPS
  */
 static u16 __get_link_speed(struct port *port)
 {
@@ -357,6 +359,10 @@ static u16 __get_link_speed(struct port 
 			speed = AD_LINK_SPEED_BITMASK_1000MBPS;
 			break;
 
+		case SPEED_10000:
+			speed = AD_LINK_SPEED_BITMASK_10000MBPS;
+			break;
+
 		default:
 			speed = 0; // unknown speed value from ethtool. shouldn't happen
 			break;
@@ -414,23 +420,23 @@ static inline void __initialize_port_loc
 
 //conversions
 /**
- * __ntohs_lacpdu - convert the contents of a LACPDU to host byte order
+ * __htons_lacpdu - convert the contents of a LACPDU to network byte order
  * @lacpdu: the speicifed lacpdu
  *
  * For each multi-byte field in the lacpdu, convert its content
  */
-static void __ntohs_lacpdu(struct lacpdu *lacpdu)
+static void __htons_lacpdu(struct lacpdu *lacpdu)
 {
 	if (lacpdu) {
-		lacpdu->actor_system_priority =   ntohs(lacpdu->actor_system_priority);
-		lacpdu->actor_key =               ntohs(lacpdu->actor_key);
-		lacpdu->actor_port_priority =     ntohs(lacpdu->actor_port_priority);
-		lacpdu->actor_port =              ntohs(lacpdu->actor_port);
-		lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority);
-		lacpdu->partner_key =             ntohs(lacpdu->partner_key);
-		lacpdu->partner_port_priority =   ntohs(lacpdu->partner_port_priority);
-		lacpdu->partner_port =            ntohs(lacpdu->partner_port);
-		lacpdu->collector_max_delay =     ntohs(lacpdu->collector_max_delay);
+		lacpdu->actor_system_priority =   htons(lacpdu->actor_system_priority);
+		lacpdu->actor_key =               htons(lacpdu->actor_key);
+		lacpdu->actor_port_priority =     htons(lacpdu->actor_port_priority);
+		lacpdu->actor_port =              htons(lacpdu->actor_port);
+		lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
+		lacpdu->partner_key =             htons(lacpdu->partner_key);
+		lacpdu->partner_port_priority =   htons(lacpdu->partner_port_priority);
+		lacpdu->partner_port =            htons(lacpdu->partner_port);
+		lacpdu->collector_max_delay =     htons(lacpdu->collector_max_delay);
 	}
 }
 
@@ -490,11 +496,11 @@ static void __record_pdu(struct lacpdu *
 	// validate lacpdu and port
 	if (lacpdu && port) {
 		// record the new parameter values for the partner operational
-		port->partner_oper_port_number = lacpdu->actor_port;
-		port->partner_oper_port_priority = lacpdu->actor_port_priority;
+		port->partner_oper_port_number = ntohs(lacpdu->actor_port);
+		port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority);
 		port->partner_oper_system = lacpdu->actor_system;
-		port->partner_oper_system_priority = lacpdu->actor_system_priority;
-		port->partner_oper_key = lacpdu->actor_key;
+		port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority);
+		port->partner_oper_key = ntohs(lacpdu->actor_key);
 		// zero partener's lase states
 		port->partner_oper_port_state = 0;
 		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY);
@@ -561,11 +567,11 @@ static void __update_selected(struct lac
 	// validate lacpdu and port
 	if (lacpdu && port) {
 		// check if any parameter is different
-		if ((lacpdu->actor_port != port->partner_oper_port_number) ||
-		    (lacpdu->actor_port_priority != port->partner_oper_port_priority) ||
+		if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) ||
+		    (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) ||
 		    MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) ||
-		    (lacpdu->actor_system_priority != port->partner_oper_system_priority) ||
-		    (lacpdu->actor_key != port->partner_oper_key) ||
+		    (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) ||
+		    (ntohs(lacpdu->actor_key) != port->partner_oper_key) ||
 		    ((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
 		   ) {
 			// update the state machine Selected variable
@@ -628,11 +634,11 @@ static void __choose_matched(struct lacp
 	// validate lacpdu and port
 	if (lacpdu && port) {
 		// check if all parameters are alike
-		if (((lacpdu->partner_port == port->actor_port_number) &&
-		     (lacpdu->partner_port_priority == port->actor_port_priority) &&
+		if (((ntohs(lacpdu->partner_port) == port->actor_port_number) &&
+		     (ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) &&
 		     !MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) &&
-		     (lacpdu->partner_system_priority == port->actor_system_priority) &&
-		     (lacpdu->partner_key == port->actor_oper_port_key) &&
+		     (ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) &&
+		     (ntohs(lacpdu->partner_key) == port->actor_oper_port_key) &&
 		     ((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) ||
 		    // or this is individual link(aggregation == FALSE)
 		    ((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0)
@@ -662,11 +668,11 @@ static void __update_ntt(struct lacpdu *
 	// validate lacpdu and port
 	if (lacpdu && port) {
 		// check if any parameter is different
-		if ((lacpdu->partner_port != port->actor_port_number) ||
-		    (lacpdu->partner_port_priority != port->actor_port_priority) ||
+		if ((ntohs(lacpdu->partner_port) != port->actor_port_number) ||
+		    (ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) ||
 		    MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) ||
-		    (lacpdu->partner_system_priority != port->actor_system_priority) ||
-		    (lacpdu->partner_key != port->actor_oper_port_key) ||
+		    (ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) ||
+		    (ntohs(lacpdu->partner_key) != port->actor_oper_port_key) ||
 		    ((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) ||
 		    ((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) ||
 		    ((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) ||
@@ -775,6 +781,9 @@ static u32 __get_agg_bandwidth(struct ag
 		case AD_LINK_SPEED_BITMASK_1000MBPS:
 			bandwidth = aggregator->num_of_ports * 1000;
 			break;
+		case AD_LINK_SPEED_BITMASK_10000MBPS:
+			bandwidth = aggregator->num_of_ports * 10000;
+			break;
 		default:
 			bandwidth=0; // to silent the compilor ....
 		}
@@ -847,7 +856,7 @@ static inline void __update_lacpdu_from_
 	 */
 
 	/* Convert all non u8 parameters to Big Endian for transmit */
-	__ntohs_lacpdu(lacpdu);
+	__htons_lacpdu(lacpdu);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -2171,7 +2180,6 @@ static void bond_3ad_rx_indication(struc
 
 		switch (lacpdu->subtype) {
 		case AD_TYPE_LACPDU:
-			__ntohs_lacpdu(lacpdu);
 			dprintk("Received LACPDU on port %d\n", port->actor_port_number);
 			ad_rx_machine(lacpdu, port);
 			break;
--- linux-2.6.18.x86_64/drivers/net/bonding/bond_alb.c.gospo	2007-05-22 13:28:54.589416000 -0400
+++ linux-2.6.18.x86_64/drivers/net/bonding/bond_alb.c	2007-05-22 13:41:21.045216000 -0400
@@ -184,7 +184,7 @@ static int tlb_initialize(struct bonding
 
 	spin_lock_init(&(bond_info->tx_hashtbl_lock));
 
-	new_hashtbl = kmalloc(size, GFP_KERNEL);
+	new_hashtbl = kzalloc(size, GFP_KERNEL);
 	if (!new_hashtbl) {
 		printk(KERN_ERR DRV_NAME
 		       ": %s: Error: Failed to allocate TLB hash table\n",
@@ -195,8 +195,6 @@ static int tlb_initialize(struct bonding
 
 	bond_info->tx_hashtbl = new_hashtbl;
 
-	memset(bond_info->tx_hashtbl, 0, size);
-
 	for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
 		tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1);
 	}
@@ -1433,7 +1431,7 @@ void bond_alb_monitor(struct bonding *bo
 		 * write lock to protect from other code that also
 		 * sets the promiscuity.
 		 */
-		write_lock(&bond->curr_slave_lock);
+		write_lock_bh(&bond->curr_slave_lock);
 
 		if (bond_info->primary_is_promisc &&
 		    (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) {
@@ -1448,7 +1446,7 @@ void bond_alb_monitor(struct bonding *bo
 			bond_info->primary_is_promisc = 0;
 		}
 
-		write_unlock(&bond->curr_slave_lock);
+		write_unlock_bh(&bond->curr_slave_lock);
 
 		if (bond_info->rlb_rebalance) {
 			bond_info->rlb_rebalance = 0;
--- linux-2.6.18.x86_64/drivers/net/bonding/bond_main.c.gospo	2007-05-22 13:28:54.604403000 -0400
+++ linux-2.6.18.x86_64/drivers/net/bonding/bond_main.c	2007-05-22 13:45:40.380620000 -0400
@@ -61,6 +61,7 @@
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/inetdevice.h>
+#include <linux/igmp.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -96,6 +97,7 @@ static char *lacp_rate	= NULL;
 static char *xmit_hash_policy = NULL;
 static int arp_interval = BOND_LINK_ARP_INTERV;
 static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
+static char *arp_validate = NULL;
 struct bond_params bonding_defaults;
 
 module_param(max_bonds, int, 0);
@@ -127,6 +129,8 @@ module_param(arp_interval, int, 0);
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
 module_param_array(arp_ip_target, charp, NULL, 0);
 MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
+module_param(arp_validate, charp, 0);
+MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
 
 /*----------------------------- Global variables ----------------------------*/
 
@@ -170,6 +174,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[]
 {	NULL,			-1},
 };
 
+struct bond_parm_tbl arp_validate_tbl[] = {
+{	"none",			BOND_ARP_VALIDATE_NONE},
+{	"active",		BOND_ARP_VALIDATE_ACTIVE},
+{	"backup",		BOND_ARP_VALIDATE_BACKUP},
+{	"all",			BOND_ARP_VALIDATE_ALL},
+{	NULL,			-1},
+};
+
 /*-------------------------- Forward declarations ---------------------------*/
 
 static void bond_send_gratuitous_arp(struct bonding *bond);
@@ -638,6 +650,7 @@ verify:
 	case SPEED_10:
 	case SPEED_100:
 	case SPEED_1000:
+	case SPEED_10000:
 		break;
 	default:
 		return -1;
@@ -850,6 +863,28 @@ static void bond_mc_delete(struct bondin
 	}
 }
 
+
+/*
+ * Retrieve the list of registered multicast addresses for the bonding
+ * device and retransmit an IGMP JOIN request to the current active
+ * slave.
+ */
+static void bond_resend_igmp_join_requests(struct bonding *bond)
+{
+	struct in_device *in_dev;
+	struct ip_mc_list *im;
+
+	rcu_read_lock();
+	in_dev = __in_dev_get_rcu(bond->dev);
+	if (in_dev) {
+		for (im = in_dev->mc_list; im; im = im->next) {
+			ip_mc_rejoin_group(im);
+		}
+	}
+
+	rcu_read_unlock();
+}
+
 /*
  * Totally destroys the mc_list in bond
  */
@@ -863,6 +898,7 @@ static void bond_mc_list_destroy(struct 
 		kfree(dmi);
 		dmi = bond->mc_list;
 	}
+        bond->mc_list = NULL;
 }
 
 /*
@@ -956,6 +992,7 @@ static void bond_mc_swap(struct bonding 
 		for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) {
 			dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
 		}
+		bond_resend_igmp_join_requests(bond);
 	}
 }
 
@@ -1210,10 +1247,14 @@ static int bond_compute_features(struct 
 	unsigned long features = BOND_INTERSECT_FEATURES;
 	struct slave *slave;
 	struct net_device *bond_dev = bond->dev;
+	unsigned short max_hard_header_len = ETH_HLEN;
 	int i;
 
-	bond_for_each_slave(bond, slave, i)
+	bond_for_each_slave(bond, slave, i) {
 		features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
+		if (slave->dev->hard_header_len > max_hard_header_len)
+			max_hard_header_len = slave->dev->hard_header_len;
+	}
 
 	if ((features & NETIF_F_SG) && 
 	    !(features & NETIF_F_ALL_CSUM))
@@ -1231,6 +1272,7 @@ static int bond_compute_features(struct 
 
 	features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
 	bond_dev->features = features;
+	bond_dev->hard_header_len = max_hard_header_len;
 
 	return 0;
 }
@@ -1319,14 +1361,19 @@ int bond_enslave(struct net_device *bond
 		goto err_undo_flags;
 	}
 
-	new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL);
+	if (slave_dev->get_stats == NULL) {
+		printk(KERN_NOTICE DRV_NAME
+			": %s: the driver for slave device %s does not provide "
+			"get_stats function, network statistics will be "
+			"inaccurate.\n", bond_dev->name, slave_dev->name);
+	}
+
+	new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
 	if (!new_slave) {
 		res = -ENOMEM;
 		goto err_undo_flags;
 	}
 
-	memset(new_slave, 0, sizeof(struct slave));
-
 	/* save slave's original flags before calling
 	 * netdev_set_master and dev_open
 	 */
@@ -1365,6 +1412,7 @@ int bond_enslave(struct net_device *bond
 	}
 
 	new_slave->dev = slave_dev;
+	slave_dev->priv_flags |= IFF_BONDING;
 
 	if ((bond->params.mode == BOND_MODE_TLB) ||
 	    (bond->params.mode == BOND_MODE_ALB)) {
@@ -1417,6 +1465,8 @@ int bond_enslave(struct net_device *bond
 
 	bond_compute_features(bond);
 
+	new_slave->last_arp_rx = jiffies;
+
 	if (bond->params.miimon && !bond->params.use_carrier) {
 		link_reporting = bond_check_dev_link(bond, slave_dev, 1);
 
@@ -1493,29 +1543,8 @@ int bond_enslave(struct net_device *bond
 
 	switch (bond->params.mode) {
 	case BOND_MODE_ACTIVEBACKUP:
-		/* if we're in active-backup mode, we need one and
-		 * only one active interface. The backup interfaces
-		 * will have their SLAVE_INACTIVE flag set because we
-		 * need them to be drop all packets. Thus, since we
-		 * guarantee that curr_active_slave always point to
-		 * the last usable interface, we just have to verify
-		 * this interface's flag.
-		 */
-		if (((!bond->curr_active_slave) ||
-		     (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
-		    (new_slave->link != BOND_LINK_DOWN)) {
-			/* first slave or no active slave yet, and this link
-			   is OK, so make this interface the active one */
-			bond_change_active_slave(bond, new_slave);
-			printk(KERN_INFO DRV_NAME
-			       ": %s: first active interface up!\n",
-			       bond->dev->name);
-			netif_carrier_on(bond->dev);
-
-		} else {
-			dprintk("This is just a backup slave\n");
-			bond_set_slave_inactive_flags(new_slave);
-		}
+		bond_set_slave_inactive_flags(new_slave);
+		bond_select_active_slave(bond);
 		break;
 	case BOND_MODE_8023AD:
 		/* in 802.3ad mode, the internal mechanism
@@ -1778,7 +1807,8 @@ int bond_release(struct net_device *bond
 	dev_set_mac_address(slave_dev, &addr);
 
 	slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
-				   IFF_SLAVE_INACTIVE);
+				   IFF_SLAVE_INACTIVE | IFF_BONDING |
+				   IFF_SLAVE_NEEDARP);
 
 	kfree(slave);
 
@@ -2252,7 +2282,7 @@ static u32 bond_glean_dev_ip(struct net_
 {
 	struct in_device *idev;
 	struct in_ifaddr *ifa;
-	u32 addr = 0;
+	__be32 addr = 0;
 
 	if (!dev)
 		return 0;
@@ -2291,6 +2321,25 @@ static int bond_has_ip(struct bonding *b
 	return 0;
 }
 
+static int bond_has_this_ip(struct bonding *bond, u32 ip)
+{
+	struct vlan_entry *vlan, *vlan_next;
+
+	if (ip == bond->master_ip)
+		return 1;
+
+	if (list_empty(&bond->vlan_list))
+		return 0;
+
+	list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+				 vlan_list) {
+		if (ip == vlan->vlan_ip)
+			return 1;
+	}
+
+	return 0;
+}
+
 /*
  * We go to the (large) trouble of VLAN tagging ARP frames because
  * switches in VLAN mode (especially if ports are configured as
@@ -2429,6 +2478,93 @@ static void bond_send_gratuitous_arp(str
 	}
 }
 
+static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
+{
+	int i;
+	u32 *targets = bond->params.arp_targets;
+
+	targets = bond->params.arp_targets;
+	for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
+		dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] "
+			"%u.%u.%u.%u bhti(tip) %d\n",
+		       NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]),
+		       bond_has_this_ip(bond, tip));
+		if (sip == targets[i]) {
+			if (bond_has_this_ip(bond, tip))
+				slave->last_arp_rx = jiffies;
+			return;
+		}
+	}
+}
+
+static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct arphdr *arp;
+	struct slave *slave;
+	struct bonding *bond;
+	unsigned char *arp_ptr;
+	u32 sip, tip;
+
+	if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
+		goto out;
+
+	bond = dev->priv;
+	read_lock(&bond->lock);
+
+	dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
+		bond->dev->name, skb->dev ? skb->dev->name : "NULL",
+		orig_dev ? orig_dev->name : "NULL");
+
+	slave = bond_get_slave_by_dev(bond, orig_dev);
+	if (!slave || !slave_do_arp_validate(bond, slave))
+		goto out_unlock;
+
+	/* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
+	if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
+				 (2 * dev->addr_len) +
+				 (2 * sizeof(u32)))))
+		goto out_unlock;
+
+	arp = skb->nh.arph;
+	if (arp->ar_hln != dev->addr_len ||
+	    skb->pkt_type == PACKET_OTHERHOST ||
+	    skb->pkt_type == PACKET_LOOPBACK ||
+	    arp->ar_hrd != htons(ARPHRD_ETHER) ||
+	    arp->ar_pro != htons(ETH_P_IP) ||
+	    arp->ar_pln != 4)
+		goto out_unlock;
+
+	arp_ptr = (unsigned char *)(arp + 1);
+	arp_ptr += dev->addr_len;
+	memcpy(&sip, arp_ptr, 4);
+	arp_ptr += 4 + dev->addr_len;
+	memcpy(&tip, arp_ptr, 4);
+
+	dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u"
+		" tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name,
+		slave->state, bond->params.arp_validate,
+		slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip));
+
+	/*
+	 * Backup slaves won't see the ARP reply, but do come through
+	 * here for each ARP probe (so we swap the sip/tip to validate
+	 * the probe).  In a "redundant switch, common router" type of
+	 * configuration, the ARP probe will (hopefully) travel from
+	 * the active, through one switch, the router, then the other
+	 * switch before reaching the backup.
+	 */
+	if (slave->state == BOND_STATE_ACTIVE)
+		bond_validate_arp(bond, slave, sip, tip);
+	else
+		bond_validate_arp(bond, slave, tip, sip);
+
+out_unlock:
+	read_unlock(&bond->lock);
+out:
+	dev_kfree_skb(skb);
+	return NET_RX_SUCCESS;
+}
+
 /*
  * this function is called regularly to monitor each slave's link
  * ensuring that traffic is being sent and received when arp monitoring
@@ -2593,7 +2729,8 @@ void bond_activebackup_arp_mon(struct ne
 	 */
 	bond_for_each_slave(bond, slave, i) {
 		if (slave->link != BOND_LINK_UP) {
-			if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) {
+			if ((jiffies - slave_last_rx(bond, slave)) <=
+			     delta_in_ticks) {
 
 				slave->link = BOND_LINK_UP;
 
@@ -2638,7 +2775,7 @@ void bond_activebackup_arp_mon(struct ne
 
 			if ((slave != bond->curr_active_slave) &&
 			    (!bond->current_arp_slave) &&
-			    (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) &&
+			    (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) &&
 			     bond_has_ip(bond))) {
 				/* a backup slave has gone down; three times
 				 * the delta allows the current slave to be
@@ -2685,7 +2822,7 @@ void bond_activebackup_arp_mon(struct ne
 		 * if it is up and needs to take over as the curr_active_slave
 		 */
 		if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
-	    (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
+	    (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) &&
 	     bond_has_ip(bond))) &&
 		    ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {
 
@@ -2950,7 +3087,7 @@ static void bond_info_show_slave(struct 
 	seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
 	seq_printf(seq, "MII Status: %s\n",
 		   (slave->link == BOND_LINK_UP) ?  "up" : "down");
-	seq_printf(seq, "Link Failure Count: %d\n",
+	seq_printf(seq, "Link Failure Count: %u\n",
 		   slave->link_failure_count);
 
 	seq_printf(seq,
@@ -3210,6 +3347,9 @@ static int bond_netdev_event(struct noti
 		(event_dev ? event_dev->name : "None"),
 		event);
 
+	if (!(event_dev->priv_flags & IFF_BONDING))
+		return NOTIFY_DONE;
+
 	if (event_dev->flags & IFF_MASTER) {
 		dprintk("IFF_MASTER\n");
 		return bond_master_netdev_event(event, event_dev);
@@ -3305,6 +3445,27 @@ static void bond_unregister_lacpdu(struc
 	dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
 }
 
+void bond_register_arp(struct bonding *bond)
+{
+	struct packet_type *pt = &bond->arp_mon_pt;
+
+	if (pt->type)
+		return;
+
+	pt->type = htons(ETH_P_ARP);
+	pt->dev = bond->dev;
+	pt->func = bond_arp_rcv;
+	dev_add_pack(pt);
+}
+
+void bond_unregister_arp(struct bonding *bond)
+{
+	struct packet_type *pt = &bond->arp_mon_pt;
+
+	dev_remove_pack(pt);
+	pt->type = 0;
+}
+
 /*---------------------------- Hashing Policies -----------------------------*/
 
 /*
@@ -3391,6 +3552,9 @@ static int bond_open(struct net_device *
 		} else {
 			arp_timer->function = (void *)&bond_loadbalance_arp_mon;
 		}
+		if (bond->params.arp_validate)
+			bond_register_arp(bond);
+
 		add_timer(arp_timer);
 	}
 
@@ -3418,6 +3582,9 @@ static int bond_close(struct net_device 
 		bond_unregister_lacpdu(bond);
 	}
 
+	if (bond->params.arp_validate)
+		bond_unregister_arp(bond);
+
 	write_lock_bh(&bond->lock);
 
 
@@ -3474,33 +3641,35 @@ static struct net_device_stats *bond_get
 	read_lock_bh(&bond->lock);
 
 	bond_for_each_slave(bond, slave, i) {
-		sstats = slave->dev->get_stats(slave->dev);
+		if (slave->dev->get_stats) {
+			sstats = slave->dev->get_stats(slave->dev);
 
-		stats->rx_packets += sstats->rx_packets;
-		stats->rx_bytes += sstats->rx_bytes;
-		stats->rx_errors += sstats->rx_errors;
-		stats->rx_dropped += sstats->rx_dropped;
-
-		stats->tx_packets += sstats->tx_packets;
-		stats->tx_bytes += sstats->tx_bytes;
-		stats->tx_errors += sstats->tx_errors;
-		stats->tx_dropped += sstats->tx_dropped;
-
-		stats->multicast += sstats->multicast;
-		stats->collisions += sstats->collisions;
-
-		stats->rx_length_errors += sstats->rx_length_errors;
-		stats->rx_over_errors += sstats->rx_over_errors;
-		stats->rx_crc_errors += sstats->rx_crc_errors;
-		stats->rx_frame_errors += sstats->rx_frame_errors;
-		stats->rx_fifo_errors += sstats->rx_fifo_errors;
-		stats->rx_missed_errors += sstats->rx_missed_errors;
-
-		stats->tx_aborted_errors += sstats->tx_aborted_errors;
-		stats->tx_carrier_errors += sstats->tx_carrier_errors;
-		stats->tx_fifo_errors += sstats->tx_fifo_errors;
-		stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
-		stats->tx_window_errors += sstats->tx_window_errors;
+			stats->rx_packets += sstats->rx_packets;
+			stats->rx_bytes += sstats->rx_bytes;
+			stats->rx_errors += sstats->rx_errors;
+			stats->rx_dropped += sstats->rx_dropped;
+
+			stats->tx_packets += sstats->tx_packets;
+			stats->tx_bytes += sstats->tx_bytes;
+			stats->tx_errors += sstats->tx_errors;
+			stats->tx_dropped += sstats->tx_dropped;
+
+			stats->multicast += sstats->multicast;
+			stats->collisions += sstats->collisions;
+
+			stats->rx_length_errors += sstats->rx_length_errors;
+			stats->rx_over_errors += sstats->rx_over_errors;
+			stats->rx_crc_errors += sstats->rx_crc_errors;
+			stats->rx_frame_errors += sstats->rx_frame_errors;
+			stats->rx_fifo_errors += sstats->rx_fifo_errors;
+			stats->rx_missed_errors += sstats->rx_missed_errors;
+
+			stats->tx_aborted_errors += sstats->tx_aborted_errors;
+			stats->tx_carrier_errors += sstats->tx_carrier_errors;
+			stats->tx_fifo_errors += sstats->tx_fifo_errors;
+			stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+			stats->tx_window_errors += sstats->tx_window_errors;
+		}
 	}
 
 	read_unlock_bh(&bond->lock);
@@ -3544,7 +3713,7 @@ static int bond_do_ioctl(struct net_devi
 			mii->val_out = 0;
 			read_lock_bh(&bond->lock);
 			read_lock(&bond->curr_slave_lock);
-			if (bond->curr_active_slave) {
+			if (netif_carrier_ok(bond->dev)) {
 				mii->val_out = BMSR_LSTATUS;
 			}
 			read_unlock(&bond->curr_slave_lock);
@@ -3874,42 +4043,6 @@ out:
 	return 0;
 }
 
-static void bond_activebackup_xmit_copy(struct sk_buff *skb,
-                                        struct bonding *bond,
-                                        struct slave *slave)
-{
-	struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
-	struct ethhdr *eth_data;
-	u8 *hwaddr;
-	int res;
-
-	if (!skb2) {
-		printk(KERN_ERR DRV_NAME ": Error: "
-		       "bond_activebackup_xmit_copy(): skb_copy() failed\n");
-		return;
-	}
-
-	skb2->mac.raw = (unsigned char *)skb2->data;
-	eth_data = eth_hdr(skb2);
-
-	/* Pick an appropriate source MAC address
-	 *	-- use slave's perm MAC addr, unless used by bond
-	 *	-- otherwise, borrow active slave's perm MAC addr
-	 *	   since that will not be used
-	 */
-	hwaddr = slave->perm_hwaddr;
-	if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN))
-		hwaddr = bond->curr_active_slave->perm_hwaddr;
-
-	/* Set source MAC address appropriately */
-	memcpy(eth_data->h_source, hwaddr, ETH_ALEN);
-
-	res = bond_dev_queue_xmit(bond, skb2, slave->dev);
-	if (res)
-		dev_kfree_skb(skb2);
-
-	return;
-}
 
 /*
  * in active-backup mode, we know that bond->curr_active_slave is always valid if
@@ -3930,21 +4063,6 @@ static int bond_xmit_activebackup(struct
 	if (!bond->curr_active_slave)
 		goto out;
 
-	/* Xmit IGMP frames on all slaves to ensure rapid fail-over
-	   for multicast traffic on snooping switches */
-	if (skb->protocol == __constant_htons(ETH_P_IP) &&
-	    skb->nh.iph->protocol == IPPROTO_IGMP) {
-		struct slave *slave, *active_slave;
-		int i;
-
-		active_slave = bond->curr_active_slave;
-		bond_for_each_slave_from_to(bond, slave, i, active_slave->next,
-		                            active_slave->prev)
-			if (IS_UP(slave->dev) &&
-			    (slave->link == BOND_LINK_UP))
-				bond_activebackup_xmit_copy(skb, bond, slave);
-	}
-
 	res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
 
 out:
@@ -4176,6 +4294,7 @@ static int bond_init(struct net_device *
 	/* Initialize the device options */
 	bond_dev->tx_queue_len = 0;
 	bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
+	bond_dev->priv_flags |= IFF_BONDING;
 
 	/* At first, we block adding VLANs. That's the only way to
 	 * prevent problems that occur when adding VLANs over an
@@ -4270,6 +4389,8 @@ int bond_parse_parm(char *mode_arg, stru
 
 static int bond_check_params(struct bond_params *params)
 {
+	int arp_validate_value;
+
 	/*
 	 * Convert string parameters.
 	 */
@@ -4473,6 +4594,29 @@ static int bond_check_params(struct bond
 		arp_interval = 0;
 	}
 
+	if (arp_validate) {
+		if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
+			printk(KERN_ERR DRV_NAME
+	       ": arp_validate only supported in active-backup mode\n");
+			return -EINVAL;
+		}
+		if (!arp_interval) {
+			printk(KERN_ERR DRV_NAME
+			       ": arp_validate requires arp_interval\n");
+			return -EINVAL;
+		}
+
+		arp_validate_value = bond_parse_parm(arp_validate,
+						     arp_validate_tbl);
+		if (arp_validate_value == -1) {
+			printk(KERN_ERR DRV_NAME
+			       ": Error: invalid arp_validate \"%s\"\n",
+			       arp_validate == NULL ? "NULL" : arp_validate);
+			return -EINVAL;
+		}
+	} else
+		arp_validate_value = 0;
+
 	if (miimon) {
 		printk(KERN_INFO DRV_NAME
 		       ": MII link monitoring set to %d ms\n",
@@ -4481,8 +4625,10 @@ static int bond_check_params(struct bond
 		int i;
 
 		printk(KERN_INFO DRV_NAME
-		       ": ARP monitoring set to %d ms with %d target(s):",
-		       arp_interval, arp_ip_count);
+		       ": ARP monitoring set to %d ms, validate %s, with %d target(s):",
+		       arp_interval,
+		       arp_validate_tbl[arp_validate_value].modename,
+		       arp_ip_count);
 
 		for (i = 0; i < arp_ip_count; i++)
 			printk (" %s", arp_ip_target[i]);
@@ -4516,6 +4662,7 @@ static int bond_check_params(struct bond
 	params->xmit_policy = xmit_hashtype;
 	params->miimon = miimon;
 	params->arp_interval = arp_interval;
+	params->arp_validate = arp_validate_value;
 	params->updelay = updelay;
 	params->downdelay = downdelay;
 	params->use_carrier = use_carrier;
@@ -4535,6 +4682,7 @@ static int bond_check_params(struct bond
 static struct lock_class_key bonding_netdev_xmit_lock_key;
 
 /* Create a new bond based on the specified name and bonding parameters.
+ * If name is NULL, obtain a suitable "bond%d" name for us.
  * Caller must NOT hold rtnl_lock; we need to release it here before we
  * set up our sysfs entries.
  */
@@ -4544,7 +4692,8 @@ int bond_create(char *name, struct bond_
 	int res;
 
 	rtnl_lock();
-	bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup);
+	bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
+				ether_setup);
 	if (!bond_dev) {
 		printk(KERN_ERR DRV_NAME
 		       ": %s: eek! can't alloc netdev!\n",
@@ -4553,6 +4702,12 @@ int bond_create(char *name, struct bond_
 		goto out_rtnl;
 	}
 
+	if (!name) {
+		res = dev_alloc_name(bond_dev, "bond%d");
+		if (res < 0)
+			goto out_netdev;
+	}
+
 	/* bond_init() must be called after dev_alloc_name() (for the
 	 * /proc files), but before register_netdevice(), because we
 	 * need to set function pointers.
@@ -4579,14 +4734,19 @@ int bond_create(char *name, struct bond_
 
 	rtnl_unlock(); /* allows sysfs registration of net device */
 	res = bond_create_sysfs_entry(bond_dev->priv);
-	goto done;
+	if (res < 0) {
+		rtnl_lock();
+		goto out_bond;
+	}
+
+	return 0;
+
 out_bond:
 	bond_deinit(bond_dev);
 out_netdev:
 	free_netdev(bond_dev);
 out_rtnl:
 	rtnl_unlock();
-done:
 	return res;
 }
 
@@ -4594,7 +4754,6 @@ static int __init bonding_init(void)
 {
 	int i;
 	int res;
-	char new_bond_name[8];  /* Enough room for 999 bonds at init. */
 
 	printk(KERN_INFO "%s", version);
 
@@ -4607,8 +4766,7 @@ static int __init bonding_init(void)
 	bond_create_proc_dir();
 #endif
 	for (i = 0; i < max_bonds; i++) {
-		sprintf(new_bond_name, "bond%d",i);
-		res = bond_create(new_bond_name,&bonding_defaults, NULL);
+		res = bond_create(NULL, &bonding_defaults, NULL);
 		if (res)
 			goto err;
 	}
--- linux-2.6.18.x86_64/drivers/net/bonding/bond_sysfs.c.gospo	2007-05-22 13:28:54.612394000 -0400
+++ linux-2.6.18.x86_64/drivers/net/bonding/bond_sysfs.c	2007-05-22 13:41:17.030263000 -0400
@@ -51,6 +51,7 @@ extern struct bond_params bonding_defaul
 extern struct bond_parm_tbl bond_mode_tbl[];
 extern struct bond_parm_tbl bond_lacp_tbl[];
 extern struct bond_parm_tbl xmit_hashtype_tbl[];
+extern struct bond_parm_tbl arp_validate_tbl[];
 
 static int expected_refcount = -1;
 static struct class *netdev_class;
@@ -503,6 +504,53 @@ out:
 static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
 
 /*
+ * Show and set arp_validate.
+ */
+static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
+{
+	struct bonding *bond = to_bond(cd);
+
+	return sprintf(buf, "%s %d\n",
+		       arp_validate_tbl[bond->params.arp_validate].modename,
+		       bond->params.arp_validate) + 1;
+}
+
+static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
+{
+	int new_value;
+	struct bonding *bond = to_bond(cd);
+
+	new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
+	if (new_value < 0) {
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Ignoring invalid arp_validate value %s\n",
+		       bond->dev->name, buf);
+		return -EINVAL;
+	}
+	if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
+		printk(KERN_ERR DRV_NAME
+		       ": %s: arp_validate only supported in active-backup mode.\n",
+		       bond->dev->name);
+		return -EINVAL;
+	}
+	printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n",
+	       bond->dev->name, arp_validate_tbl[new_value].modename,
+	       new_value);
+
+	if (!bond->params.arp_validate && new_value) {
+		bond_register_arp(bond);
+	} else if (bond->params.arp_validate && !new_value) {
+		bond_unregister_arp(bond);
+	}
+
+	bond->params.arp_validate = new_value;
+
+	return count;
+}
+
+static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
+
+/*
  * Show and set the arp timer interval.  There are two tricky bits
  * here.  First, if ARP monitoring is activated, then we must disable
  * MII monitoring.  Second, if the ARP timer isn't running, we must
@@ -914,6 +962,11 @@ static ssize_t bonding_store_miimon(stru
 			       "ARP monitoring. Disabling ARP monitoring...\n",
 			       bond->dev->name);
 			bond->params.arp_interval = 0;
+			if (bond->params.arp_validate) {
+				bond_unregister_arp(bond);
+				bond->params.arp_validate =
+					BOND_ARP_VALIDATE_NONE;
+			}
 			/* Kill ARP timer, else it brings bond's link down */
 			if (bond->mii_timer.function) {
 				printk(KERN_INFO DRV_NAME
@@ -1093,7 +1146,7 @@ static ssize_t bonding_store_active_slav
 			     strlen(slave->dev->name)) == 0) {
         			old_active = bond->curr_active_slave;
         			new_active = slave;
-        			if (new_active && (new_active == old_active)) {
+        			if (new_active == old_active) {
 					/* do nothing */
 					printk(KERN_INFO DRV_NAME
 				       	       ": %s: %s is already the current active slave.\n",
@@ -1273,6 +1326,7 @@ static CLASS_DEVICE_ATTR(ad_partner_mac,
 static struct attribute *per_bond_attrs[] = {
 	&class_device_attr_slaves.attr,
 	&class_device_attr_mode.attr,
+	&class_device_attr_arp_validate.attr,
 	&class_device_attr_arp_interval.attr,
 	&class_device_attr_arp_ip_target.attr,
 	&class_device_attr_downdelay.attr,
@@ -1318,6 +1372,21 @@ int bond_create_sysfs(void)
 		return -ENODEV;
 
 	ret = class_create_file(netdev_class, &class_attr_bonding_masters);
+	/*
+	 * Permit multiple loads of the module by ignoring failures to
+	 * create the bonding_masters sysfs file.  Bonding devices
+	 * created by second or subsequent loads of the module will
+	 * not be listed in, or controllable by, bonding_masters, but
+	 * will have the usual "bonding" sysfs directory.
+	 *
+	 * This is done to preserve backwards compatibility for
+	 * initscripts/sysconfig, which load bonding multiple times to
+	 * configure multiple bonding devices.
+	 */
+	if (ret == -EEXIST) {
+		netdev_class = NULL;
+		return 0;
+	}
 
 	return ret;
 
--- linux-2.6.18.x86_64/drivers/net/bonding/bonding.h.gospo	2007-05-22 13:28:54.617393000 -0400
+++ linux-2.6.18.x86_64/drivers/net/bonding/bonding.h	2007-05-22 13:41:19.141122000 -0400
@@ -22,8 +22,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION	"3.0.3"
-#define DRV_RELDATE	"March 23, 2006"
+#define DRV_VERSION	"3.1.2"
+#define DRV_RELDATE	"January 20, 2007"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
@@ -126,6 +126,7 @@ struct bond_params {
 	int xmit_policy;
 	int miimon;
 	int arp_interval;
+	int arp_validate;
 	int use_carrier;
 	int updelay;
 	int downdelay;
@@ -149,8 +150,9 @@ struct slave {
 	struct net_device *dev; /* first - useful for panic debug */
 	struct slave *next;
 	struct slave *prev;
-	s16    delay;
-	u32    jiffies;
+	int    delay;
+	unsigned long jiffies;
+	unsigned long last_arp_rx;
 	s8     link;    /* one of BOND_LINK_XXXX */
 	s8     state;   /* one of BOND_STATE_XXXX */
 	u32    original_flags;
@@ -198,6 +200,7 @@ struct bonding {
 	struct   bond_params params;
 	struct   list_head vlan_list;
 	struct   vlan_group *vlgrp;
+	struct   packet_type arp_mon_pt;
 };
 
 /**
@@ -228,6 +231,27 @@ static inline struct bonding *bond_get_b
 	return (struct bonding *)slave->dev->master->priv;
 }
 
+#define BOND_ARP_VALIDATE_NONE		0
+#define BOND_ARP_VALIDATE_ACTIVE	(1 << BOND_STATE_ACTIVE)
+#define BOND_ARP_VALIDATE_BACKUP	(1 << BOND_STATE_BACKUP)
+#define BOND_ARP_VALIDATE_ALL		(BOND_ARP_VALIDATE_ACTIVE | \
+					 BOND_ARP_VALIDATE_BACKUP)
+
+static inline int slave_do_arp_validate(struct bonding *bond,
+					struct slave *slave)
+{
+	return bond->params.arp_validate & (1 << slave->state);
+}
+
+static inline unsigned long slave_last_rx(struct bonding *bond,
+					struct slave *slave)
+{
+	if (slave_do_arp_validate(bond, slave))
+		return slave->last_arp_rx;
+
+	return slave->dev->last_rx;
+}
+
 static inline void bond_set_slave_inactive_flags(struct slave *slave)
 {
 	struct bonding *bond = slave->dev->master->priv;
@@ -235,12 +259,14 @@ static inline void bond_set_slave_inacti
 	    bond->params.mode != BOND_MODE_ALB)
 		slave->state = BOND_STATE_BACKUP;
 	slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+	if (slave_do_arp_validate(bond, slave))
+		slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
 }
 
 static inline void bond_set_slave_active_flags(struct slave *slave)
 {
 	slave->state = BOND_STATE_ACTIVE;
-	slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
+	slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP);
 }
 
 static inline void bond_set_master_3ad_flags(struct bonding *bond)
@@ -284,6 +310,8 @@ int bond_parse_parm(char *mode_arg, stru
 const char *bond_mode_name(int mode);
 void bond_select_active_slave(struct bonding *bond);
 void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
+void bond_register_arp(struct bonding *);
+void bond_unregister_arp(struct bonding *);
 
 #endif /* _LINUX_BONDING_H */
 
--- linux-2.6.18.x86_64/include/linux/if.h.gospo	2007-05-22 13:28:54.622383000 -0400
+++ linux-2.6.18.x86_64/include/linux/if.h	2007-05-22 13:29:13.236749000 -0400
@@ -59,6 +59,8 @@
 #define IFF_SLAVE_INACTIVE	0x4	/* bonding slave not the curr. active */
 #define IFF_MASTER_8023AD	0x8	/* bonding master, 802.3ad. 	*/
 #define IFF_MASTER_ALB	0x10		/* bonding master, balance-alb.	*/
+#define IFF_BONDING	0x20		/* bonding master or slave	*/
+#define IFF_SLAVE_NEEDARP 0x40		/* need ARPs for validation	*/
 
 #define IF_GET_IFACE	0x0001		/* for querying only */
 #define IF_GET_PROTO	0x0002
--- linux-2.6.18.x86_64/include/linux/igmp.h.gospo	2007-05-22 13:45:36.994017000 -0400
+++ linux-2.6.18.x86_64/include/linux/igmp.h	2007-05-22 13:45:40.385616000 -0400
@@ -217,5 +217,7 @@ extern void ip_mc_up(struct in_device *)
 extern void ip_mc_down(struct in_device *);
 extern void ip_mc_dec_group(struct in_device *in_dev, u32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, u32 addr);
+extern void ip_mc_rejoin_group(struct ip_mc_list *im);
+
 #endif
 #endif
--- linux-2.6.18.x86_64/net/ipv4/igmp.c.gospo	2007-05-22 13:45:35.323681000 -0400
+++ linux-2.6.18.x86_64/net/ipv4/igmp.c	2007-05-22 13:45:40.397600000 -0400
@@ -1249,6 +1249,28 @@ out:
 }
 
 /*
+ *	Resend IGMP JOIN report; used for bonding.
+ */
+void ip_mc_rejoin_group(struct ip_mc_list *im)
+{
+	struct in_device *in_dev = im->interface;
+
+#ifdef CONFIG_IP_MULTICAST
+	if (im->multiaddr == IGMP_ALL_HOSTS)
+		return;
+
+	if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
+		igmp_mod_timer(im, IGMP_Initial_Report_Delay);
+		return;
+	}
+	/* else, v3 */
+	im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
+		IGMP_Unsolicited_Report_Count;
+	igmp_ifc_event(in_dev);
+#endif
+}
+
+/*
  *	A socket has left a multicast group on device dev
  */
 
@@ -2594,3 +2616,4 @@ int __init igmp_mc_proc_init(void)
 EXPORT_SYMBOL(ip_mc_dec_group);
 EXPORT_SYMBOL(ip_mc_inc_group);
 EXPORT_SYMBOL(ip_mc_join_group);
+EXPORT_SYMBOL(ip_mc_rejoin_group);