Index: oldkernel/linux/Documentation/networking/bonding.txt
diff -u /dev/null linux/Documentation/networking/bonding.txt:1.1
--- /dev/null	Mon Jul 31 21:13:34 2000
+++ linux/Documentation/networking/bonding.txt	Thu Jun  1 15:42:31 2000
@@ -0,0 +1,128 @@
+Installation:
+
+Apply patch.  (if your reading this in
+/usr/src/linux/Documentation/network/bonding.txt, then it's already
+applied.)
+
+Run make menuconfig/xconfig/config, and select 'bonding device' in
+network devices.
+
+Build the new kernel/modules.
+
+Get update ifenslave.c (included in tar file.) (location to be determined.)
+
+install ifenslave.c; do:
+	gcc -O2 -o ifenslave ifenslave.c
+	cp ifenslave /sbin/ifenslave
+
+Modify /etc/conf.modules by adding the line:
+	alias bond0 bonding
+
+If you running a RH5.0 or newer distribution, do:
+
+cd /etc/sysconfig/network-scripts
+cp ifcfg-eth0 ifcfg-bond0
+edit ifcfg-bond0, and make it look the following:
+
+DEVICE=bond0
+USERCTL=no
+ONBOOT=yes
+BOOTPROTO=none
+BROADCAST=XXX.XXX.XXX.255
+NETWORK=XXX.XXX.XXX.0
+NETMASK=255.255.255.0
+IPADDR=XXX.XXX.XXX.XXX
+
+(put the approiate values for you network in where the XXX's are at.)
+
+Then, edit ifcfg-eth0/ifcfg-eth1 (and all the other slave devices), and make them
+look like this:
+
+DEVICE=eth0
+USERCTL=no
+ONBOOT=yes
+MASTER=bond0
+SLAVE=yes
+BOOTPROTO=none
+
+Reboot, and the network should come up bonded together.
+
+For other distributions, you need to do something like:
+
+/sbin/ifconfig bond0 addresss netmask xxx.xxx.xxx.xxx broadcast xxx.xxx.xxx.xxx up
+/sbin/ifenslave bond0 eth0
+/sbin/ifenslave bond0 eth1
+
+When properly configured, it will look this:
+
+[root]# /sbin/ifconfig
+bond0     Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4  
+          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
+          UP BROADCAST RUNNING MASTER MULTICAST  MTU:1500  Metric:1
+          RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0
+          collisions:0 txqueuelen:0 
+
+eth0      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4  
+          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
+          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
+          RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0
+          collisions:0 txqueuelen:100 
+          Interrupt:10 Base address:0x1080 
+
+eth1      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4  
+          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
+          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
+          RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:100 
+          Interrupt:9 Base address:0x1400 
+
+Questions:
+
+1.  Is it SMP safe?
+
+	Yes.  The old 2.0.xx channel bonding patch wasn't SMP safe.
+This one was designed from the start to be SMP safe.
+
+2.  What type of cards can it work with it?
+
+	Any Ethernet type cards (ie, you can even mix cards - a tulip
+and a 3com 3c905, for example).  You can even bond together Gigabit
+Ethernet cards!
+
+3.  How many bond devices can I have?
+
+	Just one at this time.
+
+4.  How many slaves can a bond device have?
+
+	Limited by the number of cards you can place in your system.
+
+5.  What happens when a slave dies?
+
+	Currently, the ethernet drivers don't really handle this
+situation very well.  The tulip driver never stalls; it just starts to
+throw packets away!
+
+6.  If this was fixed, can bonding be used for High Availability?
+
+	Yes!
+
+7.  Which switches/systems does it work with?
+
+	Cisco 5500 series (look for EtherChannel support).
+	SunTrunking software.
+
+8.  Where does the bond0 device get it's mac address from?
+
+	It's taken from the first slave device.  If you remove that
+first slave device, the MAC address continues to be associated with
+it.  If you wish to remove that MAC address, you have to ifconfig
+bond0 down, and then modprobe -r bonding.  If you wish, you can also
+assign a MAC address when you ifconfig the bond0 device.
+
+9.  Which transmit policy is used?
+
+	Round robin, based on order of enslaving.
Index: oldkernel/linux/drivers/net/Config.in
diff -u linux/drivers/net/Config.in:1.3 linux/drivers/net/Config.in:1.4
--- linux/drivers/net/Config.in:1.3	Thu Jun  1 14:57:34 2000
+++ linux/drivers/net/Config.in	Thu Jun  1 15:42:31 2000
@@ -18,6 +18,7 @@
 endmenu
 
 tristate 'Dummy net driver support' CONFIG_DUMMY
+tristate 'Bonding driver support' CONFIG_BONDING
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   if [ "$CONFIG_NETLINK" = "y" ]; then
Index: oldkernel/linux/drivers/net/Makefile
diff -u linux/drivers/net/Makefile:1.3 linux/drivers/net/Makefile:1.4
--- linux/drivers/net/Makefile:1.3	Thu Jun  1 14:57:34 2000
+++ linux/drivers/net/Makefile	Thu Jun  1 15:42:31 2000
@@ -366,6 +366,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_BONDING),y)
+L_OBJS += bonding.o
+else
+  ifeq ($(CONFIG_BONDING),m)
+  M_OBJS += bonding.o
+  endif
+endif
+
 ifeq ($(CONFIG_DE600),y)
 L_OBJS += de600.o
 else
Index: oldkernel/linux/drivers/net/bonding.c
diff -u /dev/null linux/drivers/net/bonding.c:1.1
--- /dev/null	Mon Jul 31 21:13:34 2000
+++ linux/drivers/net/bonding.c	Thu Jun  1 15:42:31 2000
@@ -0,0 +1,353 @@
+/*
+ * originally based on the dummy device.
+ *
+ * Copyright 1999, Thomas Davis, tadavis@lbl.gov.  
+ * Licensed under the GPL. Based on dummy.c, and eql.c devices.
+ *
+ * bond.c: a bonding/etherchannel/sun trunking net driver
+ *
+ * This is useful to talk to a Cisco 5500, running Etherchannel, aka:
+ *	Linux Channel Bonding
+ *	Sun Trunking (Solaris)
+ *
+ * How it works:
+ *    ifconfig bond0 ipaddress netmask up
+ *      will setup a network device, with an ip address.  No mac address 
+ *	will be assigned at this time.  The hw mac address will come from 
+ *	the first slave bonded to the channel.  All slaves will then use 
+ *	this hw mac address.
+ *
+ *    ifconfig bond0 down
+ *         will release all slaves, marking them as down.
+ *
+ *    ifenslave bond0 eth0
+ *	will attache eth0 to bond0 as a slave.  eth0 hw mac address will either
+ *	a: be used as initial mac address
+ *	b: if a hw mac address already is there, eth0's hw mac address 
+ *	   will then  be set from bond0.
+ *
+ * v0.1 - first working version.
+ * v0.2 - changed stats to be calculated by summing slaves stats.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/if_bonding.h>
+
+static int bond_xmit(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *bond_get_stats(struct device *dev);
+
+static int bond_open(struct device *dev)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int bond_close(struct device *master)
+{
+	bonding_t *private = (struct bonding *) master->priv;
+	slave_queue_t *queue = (struct slave_queue *) private->queue;
+	slave_t *slave, *next;
+
+	for( slave=queue->head; slave != NULL; slave=next) {
+#ifdef BONDING_DEBUG
+		printk("freeing = %s\n", slave->dev->name);
+#endif
+		slave->dev->flags &= ~IFF_SLAVE;
+		slave->dev->slave = NULL;
+		next = slave->next;
+		kfree(slave);
+		queue->num_slaves++;
+	}
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/* fake multicast ability */
+static void set_multicast_list(struct device *dev)
+{
+}
+
+static int bond_enslave(struct device *master, struct device *slave)
+{
+	bonding_t *private = (struct bonding *) master->priv;
+	slave_queue_t *queue = (struct slave_queue *) private->queue;
+	slave_t *new_slave;
+	int flags;
+	
+	if (master == NULL || slave == NULL) 
+		return -ENODEV;
+
+#ifdef BONDING_DEBUG
+	printk (KERN_WARNING "%s: enslaving '%s'\n", master->name, slave->name);
+#endif
+
+	save_flags(flags);
+	cli();
+
+	/* not running. */
+	if ((slave->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+		restore_flags(flags);
+		return -EINVAL;
+	}
+
+	/* already enslaved */
+	if (master->flags & IFF_SLAVE || slave->flags & IFF_SLAVE) {
+		restore_flags(flags);
+		return -EBUSY;
+	}
+		   
+	slave->slave = master;     /* save the master in slave->slave */
+	slave->flags |= IFF_SLAVE;
+
+	if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+	memset(new_slave, 0, sizeof(slave_t));
+
+	new_slave->dev = slave;
+
+	if (queue->head == NULL) {
+		queue->head = new_slave;
+		queue->current_slave = queue->head;
+	} else {
+		queue->tail->next = new_slave;
+	}
+
+	queue->tail = new_slave;
+	queue->num_slaves++;
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+static int bond_release(struct device *master, struct device *slave)
+{
+	printk (KERN_DEBUG "%s: releasing `%s`\n", master->name, slave->name);
+
+	return -EINVAL;
+}
+
+static int bond_sethwaddr(struct device *master, struct device *slave)
+{
+	memcpy(master->dev_addr, slave->dev_addr, slave->addr_len);
+	return 0;
+}
+
+static int bond_ioctl(struct device *master, struct ifreq *ifr, int cmd)
+{
+	struct device *slave = dev_get(ifr->ifr_slave);
+
+#ifdef BONDING_DEBUG
+	printk("master=%s, slave=%s\n", master->name, slave->name);
+#endif
+
+	switch (cmd) {
+	case BOND_ENSLAVE:
+		return bond_enslave(master, slave);
+	case BOND_RELEASE:
+		return bond_release(master, slave);
+	case BOND_SETHWADDR:
+		return bond_sethwaddr(master, slave);
+	default:
+			return -EOPNOTSUPP;
+	}
+}
+
+#ifdef CONFIG_NET_FASTROUTE
+static int bond_accept_fastpath(struct device *dev, struct dst_entry *dst)
+{
+	return -1;
+}
+#endif
+
+__initfunc(int bond_init(struct device *dev))
+{
+	bonding_t *bond;
+
+	/* Initialize the device structure. */
+	dev->hard_start_xmit = bond_xmit;
+
+	dev->priv = kmalloc(sizeof(struct bonding), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+
+	memset(dev->priv, 0, sizeof(struct bonding));
+
+	bond = (struct bonding *) dev->priv;
+
+	bond->queue = kmalloc(sizeof(struct slave_queue), GFP_KERNEL);
+	if (bond->queue == NULL)
+		return -ENOMEM;
+
+	memset(bond->queue, 0, sizeof(struct slave_queue));
+
+	bond->stats = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+	if (bond->stats == NULL)
+		return -ENOMEM;
+
+	memset(bond->stats, 0, sizeof(struct enet_statistics));
+
+	dev->get_stats	= bond_get_stats;
+
+	dev->open = bond_open;
+	dev->stop = bond_close;
+	dev->set_multicast_list = set_multicast_list;
+
+	dev->do_ioctl = bond_ioctl;
+
+	/* Fill in the fields of the device structure with ethernet-generic 
+	   values. */
+	ether_setup(dev);
+	dev->tx_queue_len = 0;
+	dev->flags |= (IFF_MASTER|IFF_MULTICAST);
+#ifdef CONFIG_NET_FASTROUTE
+	dev->accept_fastpath = bond_accept_fastpath;
+#endif
+
+	return 0;
+}
+
+static int bond_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct device *slave;
+	struct bonding *bond = (struct bonding *) dev->priv;
+	struct slave_queue *queue = bond->queue;
+	int good = 0;
+	
+	while (good == 0) {
+		slave = queue->current_slave->dev;
+		if (slave->flags & (IFF_UP|IFF_RUNNING)) {
+			skb->dev = slave;
+			skb->priority = 1;
+			dev_queue_xmit(skb);
+			good = 1;
+		}
+		if (queue->current_slave->next != NULL) {
+			queue->current_slave = queue->current_slave->next;
+		} else {
+			queue->current_slave = queue->head;
+		}
+	}
+
+	return 0;
+}
+
+static struct net_device_stats *bond_get_stats(struct device *dev)
+{
+	bonding_t *private = dev->priv;
+	slave_queue_t *queue = private->queue;
+	struct net_device_stats *stats = private->stats, *sstats;
+	slave_t *slave;
+	
+	memset(private->stats, 0, sizeof(struct net_device_stats));
+	for (slave=queue->head; slave != NULL; slave=slave->next) {
+		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;
+
+	}
+
+	return stats;
+}
+
+#ifdef MODULE
+
+__initfunc(static int bond_probe(struct device *dev))
+{
+	bond_init(dev);
+	return 0;
+}
+
+static char bond_name[16];
+
+static struct device dev_bond = {
+		bond_name, 	/* Needs to be writeable */
+		0, 0, 0, 0,
+	 	0x0, 0,
+	 	0, 0, 0, NULL, bond_probe };
+
+int init_module(void)
+{
+	/* Find a name for this unit */
+	int err=dev_alloc_name(&dev_bond,"bond%d");
+
+	if (err<0)
+		return err;
+
+	if (register_netdev(&dev_bond) != 0)
+		return -EIO;
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	struct bonding *bond = (struct bonding *) dev_bond.priv;
+
+	unregister_netdev(&dev_bond);
+
+	kfree(bond->queue);
+	kfree(bond->stats);
+	kfree(dev_bond.priv);
+
+	dev_bond.priv = NULL;
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
Index: oldkernel/linux/include/linux/if_bonding.h
diff -u /dev/null linux/include/linux/if_bonding.h:1.1
--- /dev/null	Mon Jul 31 21:13:35 2000
+++ linux/include/linux/if_bonding.h	Thu Jun  1 15:42:31 2000
@@ -0,0 +1,59 @@
+/*
+ * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'.
+ *
+ * 
+ * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Management, Inc.
+ *
+ * BUT, I'm the one who modified it for ethernet, so:
+ * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov
+ *
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
+ * 
+ */
+
+#ifndef _LINUX_IF_BONDING_H
+#define _LINUX_IF_BONDING_H
+
+#include <linux/timer.h>
+
+#define BOND_ENSLAVE     (SIOCDEVPRIVATE)
+#define BOND_RELEASE     (SIOCDEVPRIVATE + 1)
+#define BOND_SETHWADDR   (SIOCDEVPRIVATE + 2)
+
+typedef struct slave {
+	struct device *dev;
+	struct slave *next;
+	struct slave *prev;
+} slave_t;
+
+typedef struct slave_queue {
+	slave_t *head;
+	slave_t *tail;
+	slave_t *current_slave;
+	int num_slaves;
+	struct device *master_dev;
+	char lock;
+} slave_queue_t;
+
+typedef struct bonding {
+	slave_queue_t *queue;
+	int min_slaves;
+	int max_slaves;
+	struct net_device_stats *stats;
+	struct timer_list timer;
+	char timer_on;
+} bonding_t;  
+
+#endif /* _LINUX_BOND_H */
+
+/*
+ * Local variables:
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
Index: oldkernel/linux/net/core/dev.c
diff -u linux/net/core/dev.c:1.1.1.1 linux/net/core/dev.c:1.2
--- linux/net/core/dev.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/core/dev.c	Thu Jun  1 15:42:31 2000
@@ -784,6 +784,9 @@
 #else
 		netdev_dropping = 0;
 #endif
+		if (skb->dev->flags & IFF_SLAVE  &&  skb->dev->slave) {
+			skb->dev = skb->dev->slave;
+		}
 		skb_queue_tail(&backlog,skb);
 		mark_bh(NET_BH);
 		return;
