Re: Again: EQL - someone's use this thing yet?

Thomas Davis (tadavis@lbl.gov)
Fri, 10 Dec 1999 13:51:45 -0800


This is a multi-part message in MIME format.
--------------2DC8F1831B0DBEDE82E5084E
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Alan Cox wrote:
>
> > I'll look at it for 2.3/2.4.. and I'll send the current bonding for
> > 2.2, if alan wants to include it in his 2.2ac series.
>
> If Alexey is happy with it sure
>
> >

Ok, I've attached my currently working bonding diff.

It includes:

1. Documentation/network/bonding.txt
2. drivers/net/bonding.c
3. include/linux/if_bonding.h
4. changes to config.in
5. changes to net/core/dev.c (4 lines)

This is known to work with v2.2 kernels - I haven't tested it with 2.3
kernels, since the machines that are doing channel bonding also need md
and knfsd. (which is no where ready for 2.3)

Thanks!

-- 
------------------------+--------------------------------------------------
Thomas Davis		| PDSF Project Leader
tadavis@lbl.gov		| 
(510) 486-4524		| "Only a petabyte of data this year?"
--------------2DC8F1831B0DBEDE82E5084E
Content-Type: text/plain; charset=us-ascii;
 name="bonding-0.2.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="bonding-0.2.diff"

diff -ruN linux-2.2.12/Documentation/networking/bonding.txt linux/Documentation/networking/bonding.txt --- linux-2.2.12/Documentation/networking/bonding.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/bonding.txt Wed Nov 24 10:51:30 1999 @@ -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. \ No newline at end of file diff -ruN linux-2.2.12/drivers/net/Config.in linux/drivers/net/Config.in --- linux-2.2.12/drivers/net/Config.in Fri Nov 19 10:14:31 1999 +++ linux/drivers/net/Config.in Wed Nov 24 10:22:47 1999 @@ -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 diff -ruN linux-2.2.12/drivers/net/Makefile linux/drivers/net/Makefile --- linux-2.2.12/drivers/net/Makefile Fri Nov 19 10:14:31 1999 +++ linux/drivers/net/Makefile Wed Nov 24 10:22:47 1999 @@ -362,6 +362,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 diff -ruN linux-2.2.12/drivers/net/bonding.c linux/drivers/net/bonding.c --- linux-2.2.12/drivers/net/bonding.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/bonding.c Wed Nov 24 10:51:48 1999 @@ -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: + */ diff -ruN linux-2.2.12/include/linux/if_bonding.h linux/include/linux/if_bonding.h --- linux-2.2.12/include/linux/if_bonding.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/if_bonding.h Wed Nov 24 10:22:47 1999 @@ -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: + */ diff -ruN linux-2.2.12/net/core/dev.c linux/net/core/dev.c --- linux-2.2.12/net/core/dev.c Fri Nov 19 10:14:31 1999 +++ linux/net/core/dev.c Wed Nov 24 10:22:47 1999 @@ -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;

--------------2DC8F1831B0DBEDE82E5084E--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/