aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/bonding/bond_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r--drivers/net/bonding/bond_main.c4708
1 files changed, 4708 insertions, 0 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
new file mode 100644
index 00000000000..770e28f98fd
--- /dev/null
+++ b/drivers/net/bonding/bond_main.c
@@ -0,0 +1,4708 @@
+/*
+ * 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.
+ *
+ * bonding.c: an Ethernet Bonding driver
+ *
+ * This is useful to talk to a Cisco EtherChannel compatible equipment:
+ * Cisco 5500
+ * Sun Trunking (Solaris)
+ * Alteon AceDirector Trunks
+ * Linux Bonding
+ * and probably many L2 switches ...
+ *
+ * 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 attach 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.
+ *
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * - fix leaks on failure at bond_init
+ *
+ * 2000/09/30 - Willy Tarreau <willy at meta-x.org>
+ * - added trivial code to release a slave device.
+ * - fixed security bug (CAP_NET_ADMIN not checked)
+ * - implemented MII link monitoring to disable dead links :
+ * All MII capable slaves are checked every <miimon> milliseconds
+ * (100 ms seems good). This value can be changed by passing it to
+ * insmod. A value of zero disables the monitoring (default).
+ * - fixed an infinite loop in bond_xmit_roundrobin() when there's no
+ * good slave.
+ * - made the code hopefully SMP safe
+ *
+ * 2000/10/03 - Willy Tarreau <willy at meta-x.org>
+ * - optimized slave lists based on relevant suggestions from Thomas Davis
+ * - implemented active-backup method to obtain HA with two switches:
+ * stay as long as possible on the same active interface, while we
+ * also monitor the backup one (MII link status) because we want to know
+ * if we are able to switch at any time. ( pass "mode=1" to insmod )
+ * - lots of stress testings because we need it to be more robust than the
+ * wires ! :->
+ *
+ * 2000/10/09 - Willy Tarreau <willy at meta-x.org>
+ * - added up and down delays after link state change.
+ * - optimized the slaves chaining so that when we run forward, we never
+ * repass through the bond itself, but we can find it by searching
+ * backwards. Renders the deletion more difficult, but accelerates the
+ * scan.
+ * - smarter enslaving and releasing.
+ * - finer and more robust SMP locking
+ *
+ * 2000/10/17 - Willy Tarreau <willy at meta-x.org>
+ * - fixed two potential SMP race conditions
+ *
+ * 2000/10/18 - Willy Tarreau <willy at meta-x.org>
+ * - small fixes to the monitoring FSM in case of zero delays
+ * 2000/11/01 - Willy Tarreau <willy at meta-x.org>
+ * - fixed first slave not automatically used in trunk mode.
+ * 2000/11/10 : spelling of "EtherChannel" corrected.
+ * 2000/11/13 : fixed a race condition in case of concurrent accesses to ioctl().
+ * 2000/12/16 : fixed improper usage of rtnl_exlock_nowait().
+ *
+ * 2001/1/3 - Chad N. Tindel <ctindel at ieee dot org>
+ * - The bonding driver now simulates MII status monitoring, just like
+ * a normal network device. It will show that the link is down iff
+ * every slave in the bond shows that their links are down. If at least
+ * one slave is up, the bond's MII status will appear as up.
+ *
+ * 2001/2/7 - Chad N. Tindel <ctindel at ieee dot org>
+ * - Applications can now query the bond from user space to get
+ * information which may be useful. They do this by calling
+ * the BOND_INFO_QUERY ioctl. Once the app knows how many slaves
+ * are in the bond, it can call the BOND_SLAVE_INFO_QUERY ioctl to
+ * get slave specific information (# link failures, etc). See
+ * <linux/if_bonding.h> for more details. The structs of interest
+ * are ifbond and ifslave.
+ *
+ * 2001/4/5 - Chad N. Tindel <ctindel at ieee dot org>
+ * - Ported to 2.4 Kernel
+ *
+ * 2001/5/2 - Jeffrey E. Mast <jeff at mastfamily dot com>
+ * - When a device is detached from a bond, the slave device is no longer
+ * left thinking that is has a master.
+ *
+ * 2001/5/16 - Jeffrey E. Mast <jeff at mastfamily dot com>
+ * - memset did not appropriately initialized the bond rw_locks. Used
+ * rwlock_init to initialize to unlocked state to prevent deadlock when
+ * first attempting a lock
+ * - Called SET_MODULE_OWNER for bond device
+ *
+ * 2001/5/17 - Tim Anderson <tsa at mvista.com>
+ * - 2 paths for releasing for slave release; 1 through ioctl
+ * and 2) through close. Both paths need to release the same way.
+ * - the free slave in bond release is changing slave status before
+ * the free. The netdev_set_master() is intended to change slave state
+ * so it should not be done as part of the release process.
+ * - Simple rule for slave state at release: only the active in A/B and
+ * only one in the trunked case.
+ *
+ * 2001/6/01 - Tim Anderson <tsa at mvista.com>
+ * - Now call dev_close when releasing a slave so it doesn't screw up
+ * out routing table.
+ *
+ * 2001/6/01 - Chad N. Tindel <ctindel at ieee dot org>
+ * - Added /proc support for getting bond and slave information.
+ * Information is in /proc/net/<bond device>/info.
+ * - Changed the locking when calling bond_close to prevent deadlock.
+ *
+ * 2001/8/05 - Janice Girouard <girouard at us.ibm.com>
+ * - correct problem where refcnt of slave is not incremented in bond_ioctl
+ * so the system hangs when halting.
+ * - correct locking problem when unable to malloc in bond_enslave.
+ * - adding bond_xmit_xor logic.
+ * - adding multiple bond device support.
+ *
+ * 2001/8/13 - Erik Habbinga <erik_habbinga at hp dot com>
+ * - correct locking problem with rtnl_exlock_nowait
+ *
+ * 2001/8/23 - Janice Girouard <girouard at us.ibm.com>
+ * - bzero initial dev_bonds, to correct oops
+ * - convert SIOCDEVPRIVATE to new MII ioctl calls
+ *
+ * 2001/9/13 - Takao Indoh <indou dot takao at jp dot fujitsu dot com>
+ * - Add the BOND_CHANGE_ACTIVE ioctl implementation
+ *
+ * 2001/9/14 - Mark Huth <mhuth at mvista dot com>
+ * - Change MII_LINK_READY to not check for end of auto-negotiation,
+ * but only for an up link.
+ *
+ * 2001/9/20 - Chad N. Tindel <ctindel at ieee dot org>
+ * - Add the device field to bonding_t. Previously the net_device
+ * corresponding to a bond wasn't available from the bonding_t
+ * structure.
+ *
+ * 2001/9/25 - Janice Girouard <girouard at us.ibm.com>
+ * - add arp_monitor for active backup mode
+ *
+ * 2001/10/23 - Takao Indoh <indou dot takao at jp dot fujitsu dot com>
+ * - Various memory leak fixes
+ *
+ * 2001/11/5 - Mark Huth <mark dot huth at mvista dot com>
+ * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under
+ * certain hotswap conditions.
+ * Note: this same change may be required in bond_arp_monitor ???
+ * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr
+ * - Handle hot swap ethernet interface deregistration events to remove
+ * kernel oops following hot swap of enslaved interface
+ *
+ * 2002/1/2 - Chad N. Tindel <ctindel at ieee dot org>
+ * - Restore original slave flags at release time.
+ *
+ * 2002/02/18 - Erik Habbinga <erik_habbinga at hp dot com>
+ * - bond_release(): calling kfree on our_slave after call to
+ * bond_restore_slave_flags, not before
+ * - bond_enslave(): saving slave flags into original_flags before
+ * call to netdev_set_master, so the IFF_SLAVE flag doesn't end
+ * up in original_flags
+ *
+ * 2002/04/05 - Mark Smith <mark.smith at comdev dot cc> and
+ * 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/10 - Tony Cureington <tony.cureington * hp_com>
+ * - corrected uninitialized pointer (ifr.ifr_data) in bond_check_dev_link;
+ * actually changed function to use MIIPHY, then MIIREG, and finally
+ * ETHTOOL 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/08/30 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - Removed acquisition of xmit_lock in set_multicast_list; caused
+ * deadlock on SMP (lock is held by caller).
+ * - Revamped SIOCGMIIPHY, SIOCGMIIREG portion of bond_check_dev_link().
+ *
+ * 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
+ *
+ * 2002/9/30 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - make sure the ip target matches the arp_target before saving the
+ * hw address.
+ *
+ * 2002/9/30 - Dan Eisner <eisner at 2robots dot com>
+ * - make sure my_ip is set before taking down the link, since
+ * not all switches respond if the source ip is not set.
+ *
+ * 2002/10/8 - Janice Girouard <girouard at us dot ibm dot com>
+ * - read in the local ip address when enslaving a device
+ * - add primary support
+ * - make sure 2*arp_interval has passed when a new device
+ * is brought on-line before taking it down.
+ *
+ * 2002/09/11 - Philippe De Muyter <phdm at macqel dot be>
+ * - Added bond_xmit_broadcast logic.
+ * - Added bond_mode() support function.
+ *
+ * 2002/10/26 - Laurent Deniel <laurent.deniel at free.fr>
+ * - allow to register multicast addresses only on active slave
+ * (useful in active-backup mode)
+ * - add multicast module parameter
+ * - fix deletion of multicast groups after unloading module
+ *
+ * 2002/11/06 - Kameshwara Rayaprolu <kameshwara.rao * wipro_com>
+ * - Changes to prevent panic from closing the device twice; if we close
+ * the device in bond_release, we must set the original_flags to down
+ * so it won't be closed again by the network layer.
+ *
+ * 2002/11/07 - Tony Cureington <tony.cureington * hp_com>
+ * - Fix arp_target_hw_addr memory leak
+ * - Created activebackup_arp_monitor function to handle arp monitoring
+ * in active backup mode - the bond_arp_monitor had several problems...
+ * such as allowing slaves to tx arps sequentially without any delay
+ * for a response
+ * - Renamed bond_arp_monitor to loadbalance_arp_monitor and re-wrote
+ * this function to just handle arp monitoring in load-balancing mode;
+ * it is a lot more compact now
+ * - Changes to ensure one and only one slave transmits in active-backup
+ * mode
+ * - Robustesize parameters; warn users about bad combinations of
+ * parameters; also if miimon is specified and a network driver does
+ * not support MII or ETHTOOL, inform the user of this
+ * - Changes to support link_failure_count when in arp monitoring mode
+ * - Fix up/down delay reported in /proc
+ * - Added version; log version; make version available from "modinfo -d"
+ * - Fixed problem in bond_check_dev_link - if the first IOCTL (SIOCGMIIPH)
+ * failed, the ETHTOOL ioctl never got a chance
+ *
+ * 2002/11/16 - Laurent Deniel <laurent.deniel at free.fr>
+ * - fix multicast handling in activebackup_arp_monitor
+ * - remove one unnecessary and confusing curr_active_slave == slave test
+ * in activebackup_arp_monitor
+ *
+ * 2002/11/17 - Laurent Deniel <laurent.deniel at free.fr>
+ * - fix bond_slave_info_query when slave_id = num_slaves
+ *
+ * 2002/11/19 - Janice Girouard <girouard at us dot ibm dot com>
+ * - correct ifr_data reference. Update ifr_data reference
+ * to mii_ioctl_data struct values to avoid confusion.
+ *
+ * 2002/11/22 - Bert Barbe <bert.barbe at oracle dot com>
+ * - Add support for multiple arp_ip_target
+ *
+ * 2002/12/13 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - Changed to allow text strings for mode and multicast, e.g.,
+ * insmod bonding mode=active-backup. The numbers still work.
+ * One change: an invalid choice will cause module load failure,
+ * rather than the previous behavior of just picking one.
+ * - Minor cleanups; got rid of dup ctype stuff, atoi function
+ *
+ * 2003/02/07 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - Added use_carrier module parameter that causes miimon to
+ * use netif_carrier_ok() test instead of MII/ETHTOOL ioctls.
+ * - Minor cleanups; consolidated ioctl calls to one function.
+ *
+ * 2003/02/07 - Tony Cureington <tony.cureington * hp_com>
+ * - Fix bond_mii_monitor() logic error that could result in
+ * bonding round-robin mode ignoring links after failover/recovery
+ *
+ * 2003/03/17 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - kmalloc fix (GFP_KERNEL to GFP_ATOMIC) reported by
+ * Shmulik dot Hen at intel.com.
+ * - Based on discussion on mailing list, changed use of
+ * update_slave_cnt(), created wrapper functions for adding/removing
+ * slaves, changed bond_xmit_xor() to check slave_cnt instead of
+ * checking slave and slave->dev (which only worked by accident).
+ * - Misc code cleanup: get arp_send() prototype from header file,
+ * add max_bonds to bonding.txt.
+ *
+ * 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
+ * Shmulik Hen <shmulik.hen at intel dot com>
+ * - Make sure only bond_attach_slave() and bond_detach_slave() can
+ * manipulate the slave list, including slave_cnt, even when in
+ * bond_release_all().
+ * - Fixed hang in bond_release() with traffic running:
+ * netdev_set_master() must not be called from within the bond lock.
+ *
+ * 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
+ * Shmulik Hen <shmulik.hen at intel dot com>
+ * - Fixed hang in bond_enslave() with traffic running:
+ * netdev_set_master() must not be called from within the bond lock.
+ *
+ * 2003/03/18 - Amir Noam <amir.noam at intel dot com>
+ * - Added support for getting slave's speed and duplex via ethtool.
+ * Needed for 802.3ad and other future modes.
+ *
+ * 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
+ * Shmulik Hen <shmulik.hen at intel dot com>
+ * - Enable support of modes that need to use the unique mac address of
+ * each slave.
+ * * bond_enslave(): Moved setting the slave's mac address, and
+ * openning it, from the application to the driver. This breaks
+ * backward comaptibility with old versions of ifenslave that open
+ * the slave before enalsving it !!!.
+ * * bond_release(): The driver also takes care of closing the slave
+ * and restoring its original mac address.
+ * - Removed the code that restores all base driver's flags.
+ * Flags are automatically restored once all undo stages are done
+ * properly.
+ * - Block possibility of enslaving before the master is up. This
+ * prevents putting the system in an unstable state.
+ *
+ * 2003/03/18 - Amir Noam <amir.noam at intel dot com>,
+ * Tsippy Mendelson <tsippy.mendelson at intel dot com> and
+ * Shmulik Hen <shmulik.hen at intel dot com>
+ * - Added support for IEEE 802.3ad Dynamic link aggregation mode.
+ *
+ * 2003/05/01 - Amir Noam <amir.noam at intel dot com>
+ * - Added ABI version control to restore compatibility between
+ * new/old ifenslave and new/old bonding.
+ *
+ * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
+ * - Fixed bug in bond_release_all(): save old value of curr_active_slave
+ * before setting it to NULL.
+ * - Changed driver versioning scheme to include version number instead
+ * of release date (that is already in another field). There are 3
+ * fields X.Y.Z where:
+ * X - Major version - big behavior changes
+ * Y - Minor version - addition of features
+ * Z - Extra version - minor changes and bug fixes
+ * The current version is 1.0.0 as a base line.
+ *
+ * 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
+ * Amir Noam <amir.noam at intel dot com>
+ * - Added support for lacp_rate module param.
+ * - Code beautification and style changes (mainly in comments).
+ * new version - 1.0.1
+ *
+ * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
+ * - Based on discussion on mailing list, changed locking scheme
+ * to use lock/unlock or lock_bh/unlock_bh appropriately instead
+ * of lock_irqsave/unlock_irqrestore. The new scheme helps exposing
+ * hidden bugs and solves system hangs that occurred due to the fact
+ * that holding lock_irqsave doesn't prevent softirqs from running.
+ * This also increases total throughput since interrupts are not
+ * blocked on each transmitted packets or monitor timeout.
+ * new version - 2.0.0
+ *
+ * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
+ * - Added support for Transmit load balancing mode.
+ * - Concentrate all assignments of curr_active_slave to a single point
+ * so specific modes can take actions when the primary adapter is
+ * changed.
+ * - Take the updelay parameter into consideration during bond_enslave
+ * since some adapters loose their link during setting the device.
+ * - Renamed bond_3ad_link_status_changed() to
+ * bond_3ad_handle_link_change() for compatibility with TLB.
+ * new version - 2.1.0
+ *
+ * 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com>
+ * - Added support for Adaptive load balancing mode which is
+ * equivalent to Transmit load balancing + Receive load balancing.
+ * new version - 2.2.0
+ *
+ * 2003/05/15 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - Applied fix to activebackup_arp_monitor posted to bonding-devel
+ * by Tony Cureington <tony.cureington * hp_com>. Fixes ARP
+ * monitor endless failover bug. Version to 2.2.10
+ *
+ * 2003/05/20 - Amir Noam <amir.noam at intel dot com>
+ * - Fixed bug in ABI version control - Don't commit to a specific
+ * ABI version if receiving unsupported ioctl commands.
+ *
+ * 2003/05/22 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - Fix ifenslave -c causing bond to loose existing routes;
+ * added bond_set_mac_address() that doesn't require the
+ * bond to be down.
+ * - In conjunction with fix for ifenslave -c, in
+ * bond_change_active(), changing to the already active slave
+ * is no longer an error (it successfully does nothing).
+ *
+ * 2003/06/30 - Amir Noam <amir.noam at intel dot com>
+ * - Fixed bond_change_active() for ALB/TLB modes.
+ * Version to 2.2.14.
+ *
+ * 2003/07/29 - Amir Noam <amir.noam at intel dot com>
+ * - Fixed ARP monitoring bug.
+ * Version to 2.2.15.
+ *
+ * 2003/07/31 - Willy Tarreau <willy at ods dot org>
+ * - Fixed kernel panic when using ARP monitoring without
+ * setting bond's IP address.
+ * Version to 2.2.16.
+ *
+ * 2003/08/06 - Amir Noam <amir.noam at intel dot com>
+ * - Back port from 2.6: use alloc_netdev(); fix /proc handling;
+ * made stats a part of bond struct so no need to allocate
+ * and free it separately; use standard list operations instead
+ * of pre-allocated array of bonds.
+ * Version to 2.3.0.
+ *
+ * 2003/08/07 - Jay Vosburgh <fubar at us dot ibm dot com>,
+ * Amir Noam <amir.noam at intel dot com> and
+ * Shmulik Hen <shmulik.hen at intel dot com>
+ * - Propagating master's settings: Distinguish between modes that
+ * use a primary slave from those that don't, and propagate settings
+ * accordingly; Consolidate change_active opeartions and add
+ * reselect_active and find_best opeartions; Decouple promiscuous
+ * handling from the multicast mode setting; Add support for changing
+ * HW address and MTU with proper unwind; Consolidate procfs code,
+ * add CHANGENAME handler; Enhance netdev notification handling.
+ * Version to 2.4.0.
+ *
+ * 2003/09/15 - Stephen Hemminger <shemminger at osdl dot org>,
+ * Amir Noam <amir.noam at intel dot com>
+ * - Convert /proc to seq_file interface.
+ * Change /proc/net/bondX/info to /proc/net/bonding/bondX.
+ * Set version to 2.4.1.
+ *
+ * 2003/11/20 - Amir Noam <amir.noam at intel dot com>
+ * - Fix /proc creation/destruction.
+ *
+ * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
+ * - Massive cleanup - Set version to 2.5.0
+ * Code changes:
+ * o Consolidate format of prints and debug prints.
+ * o Remove bonding_t/slave_t typedefs and consolidate all casts.
+ * o Remove dead code and unnecessary checks.
+ * o Consolidate starting/stopping timers.
+ * o Consolidate handling of primary module param throughout the code.
+ * o Removed multicast module param support - all settings are done
+ * according to mode.
+ * o Slave list iteration - bond is no longer part of the list,
+ * added cyclic list iteration macros.
+ * o Consolidate error handling in all xmit functions.
+ * Style changes:
+ * o Consolidate function naming and declarations.
+ * o Consolidate function params and local variables names.
+ * o Consolidate return values.
+ * o Consolidate curly braces.
+ * o Consolidate conditionals format.
+ * o Change struct member names and types.
+ * o Chomp trailing spaces, remove empty lines, fix indentations.
+ * o Re-organize code according to context.
+ *
+ * 2003/12/30 - Amir Noam <amir.noam at intel dot com>
+ * - Fixed: Cannot remove and re-enslave the original active slave.
+ * - Fixed: Releasing the original active slave causes mac address
+ * duplication.
+ * - Add support for slaves that use ethtool_ops.
+ * Set version to 2.5.3.
+ *
+ * 2004/01/05 - Amir Noam <amir.noam at intel dot com>
+ * - Save bonding parameters per bond instead of using the global values.
+ * Set version to 2.5.4.
+ *
+ * 2004/01/14 - Shmulik Hen <shmulik.hen at intel dot com>
+ * - Enhance VLAN support:
+ * * Add support for VLAN hardware acceleration capable slaves.
+ * * Add capability to tag self generated packets in ALB/TLB modes.
+ * Set version to 2.6.0.
+ * 2004/10/29 - Mitch Williams <mitch.a.williams at intel dot com>
+ * - Fixed bug when unloading module while using 802.3ad. If
+ * spinlock debugging is turned on, this causes a stack dump.
+ * Solution is to move call to dev_remove_pack outside of the
+ * spinlock.
+ * Set version to 2.6.1.
+ *
+ */
+
+//#define BONDING_DEBUG 1
+
+#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/ip.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/socket.h>
+#include <linux/ctype.h>
+#include <linux/inet.h>
+#include <linux/bitops.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/rtnetlink.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/smp.h>
+#include <linux/if_ether.h>
+#include <net/arp.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bonding.h>
+#include "bonding.h"
+#include "bond_3ad.h"
+#include "bond_alb.h"
+
+/*---------------------------- Module parameters ----------------------------*/
+
+/* monitor all links that often (in milliseconds). <=0 disables monitoring */
+#define BOND_LINK_MON_INTERV 0
+#define BOND_LINK_ARP_INTERV 0
+
+static int max_bonds = BOND_DEFAULT_MAX_BONDS;
+static int miimon = BOND_LINK_MON_INTERV;
+static int updelay = 0;
+static int downdelay = 0;
+static int use_carrier = 1;
+static char *mode = NULL;
+static char *primary = NULL;
+static char *lacp_rate = NULL;
+static int arp_interval = BOND_LINK_ARP_INTERV;
+static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
+
+module_param(max_bonds, int, 0);
+MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
+module_param(miimon, int, 0);
+MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
+module_param(updelay, int, 0);
+MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds");
+module_param(downdelay, int, 0);
+MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds");
+module_param(use_carrier, int, 0);
+MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)");
+module_param(mode, charp, 0);
+MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
+module_param(primary, charp, 0);
+MODULE_PARM_DESC(primary, "Primary network device to use");
+module_param(lacp_rate, charp, 0);
+MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)");
+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");
+
+/*----------------------------- Global variables ----------------------------*/
+
+static const char *version =
+ DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n";
+
+static LIST_HEAD(bond_dev_list);
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *bond_proc_dir = NULL;
+#endif
+
+static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
+static int arp_ip_count = 0;
+static u32 my_ip = 0;
+static int bond_mode = BOND_MODE_ROUNDROBIN;
+static int lacp_fast = 0;
+static int app_abi_ver = 0;
+static int orig_app_abi_ver = -1; /* This is used to save the first ABI version
+ * we receive from the application. Once set,
+ * it won't be changed, and the module will
+ * refuse to enslave/release interfaces if the
+ * command comes from an application using
+ * another ABI version.
+ */
+
+struct bond_parm_tbl {
+ char *modename;
+ int mode;
+};
+
+static struct bond_parm_tbl bond_lacp_tbl[] = {
+{ "slow", AD_LACP_SLOW},
+{ "fast", AD_LACP_FAST},
+{ NULL, -1},
+};
+
+static struct bond_parm_tbl bond_mode_tbl[] = {
+{ "balance-rr", BOND_MODE_ROUNDROBIN},
+{ "active-backup", BOND_MODE_ACTIVEBACKUP},
+{ "balance-xor", BOND_MODE_XOR},
+{ "broadcast", BOND_MODE_BROADCAST},
+{ "802.3ad", BOND_MODE_8023AD},
+{ "balance-tlb", BOND_MODE_TLB},
+{ "balance-alb", BOND_MODE_ALB},
+{ NULL, -1},
+};
+
+/*-------------------------- Forward declarations ---------------------------*/
+
+static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode);
+
+/*---------------------------- General routines -----------------------------*/
+
+static const char *bond_mode_name(int mode)
+{
+ switch (mode) {
+ case BOND_MODE_ROUNDROBIN :
+ return "load balancing (round-robin)";
+ case BOND_MODE_ACTIVEBACKUP :
+ return "fault-tolerance (active-backup)";
+ case BOND_MODE_XOR :
+ return "load balancing (xor)";
+ case BOND_MODE_BROADCAST :
+ return "fault-tolerance (broadcast)";
+ case BOND_MODE_8023AD:
+ return "IEEE 802.3ad Dynamic link aggregation";
+ case BOND_MODE_TLB:
+ return "transmit load balancing";
+ case BOND_MODE_ALB:
+ return "adaptive load balancing";
+ default:
+ return "unknown";
+ }
+}
+
+/*---------------------------------- VLAN -----------------------------------*/
+
+/**
+ * bond_add_vlan - add a new vlan id on bond
+ * @bond: bond that got the notification
+ * @vlan_id: the vlan id to add
+ *
+ * Returns -ENOMEM if allocation failed.
+ */
+static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
+{
+ struct vlan_entry *vlan;
+
+ dprintk("bond: %s, vlan id %d\n",
+ (bond ? bond->dev->name: "None"), vlan_id);
+
+ vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL);
+ if (!vlan) {
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&vlan->vlan_list);
+ vlan->vlan_id = vlan_id;
+
+ write_lock_bh(&bond->lock);
+
+ list_add_tail(&vlan->vlan_list, &bond->vlan_list);
+
+ write_unlock_bh(&bond->lock);
+
+ dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name);
+
+ return 0;
+}
+
+/**
+ * bond_del_vlan - delete a vlan id from bond
+ * @bond: bond that got the notification
+ * @vlan_id: the vlan id to delete
+ *
+ * returns -ENODEV if @vlan_id was not found in @bond.
+ */
+static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
+{
+ struct vlan_entry *vlan, *next;
+ int res = -ENODEV;
+
+ dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
+
+ write_lock_bh(&bond->lock);
+
+ list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) {
+ if (vlan->vlan_id == vlan_id) {
+ list_del(&vlan->vlan_list);
+
+ if ((bond->params.mode == BOND_MODE_TLB) ||
+ (bond->params.mode == BOND_MODE_ALB)) {
+ bond_alb_clear_vlan(bond, vlan_id);
+ }
+
+ dprintk("removed VLAN ID %d from bond %s\n", vlan_id,
+ bond->dev->name);
+
+ kfree(vlan);
+
+ if (list_empty(&bond->vlan_list) &&
+ (bond->slave_cnt == 0)) {
+ /* Last VLAN removed and no slaves, so
+ * restore block on adding VLANs. This will
+ * be removed once new slaves that are not
+ * VLAN challenged will be added.
+ */
+ bond->dev->features |= NETIF_F_VLAN_CHALLENGED;
+ }
+
+ res = 0;
+ goto out;
+ }
+ }
+
+ dprintk("couldn't find VLAN ID %d in bond %s\n", vlan_id,
+ bond->dev->name);
+
+out:
+ write_unlock_bh(&bond->lock);
+ return res;
+}
+
+/**
+ * bond_has_challenged_slaves
+ * @bond: the bond we're working on
+ *
+ * Searches the slave list. Returns 1 if a vlan challenged slave
+ * was found, 0 otherwise.
+ *
+ * Assumes bond->lock is held.
+ */
+static int bond_has_challenged_slaves(struct bonding *bond)
+{
+ struct slave *slave;
+ int i;
+
+ bond_for_each_slave(bond, slave, i) {
+ if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) {
+ dprintk("found VLAN challenged slave - %s\n",
+ slave->dev->name);
+ return 1;
+ }
+ }
+
+ dprintk("no VLAN challenged slaves found\n");
+ return 0;
+}
+
+/**
+ * bond_next_vlan - safely skip to the next item in the vlans list.
+ * @bond: the bond we're working on
+ * @curr: item we're advancing from
+ *
+ * Returns %NULL if list is empty, bond->next_vlan if @curr is %NULL,
+ * or @curr->next otherwise (even if it is @curr itself again).
+ *
+ * Caller must hold bond->lock
+ */
+struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr)
+{
+ struct vlan_entry *next, *last;
+
+ if (list_empty(&bond->vlan_list)) {
+ return NULL;
+ }
+
+ if (!curr) {
+ next = list_entry(bond->vlan_list.next,
+ struct vlan_entry, vlan_list);
+ } else {
+ last = list_entry(bond->vlan_list.prev,
+ struct vlan_entry, vlan_list);
+ if (last == curr) {
+ next = list_entry(bond->vlan_list.next,
+ struct vlan_entry, vlan_list);
+ } else {
+ next = list_entry(curr->vlan_list.next,
+ struct vlan_entry, vlan_list);
+ }
+ }
+
+ return next;
+}
+
+/**
+ * bond_dev_queue_xmit - Prepare skb for xmit.
+ *
+ * @bond: bond device that got this skb for tx.
+ * @skb: hw accel VLAN tagged skb to transmit
+ * @slave_dev: slave that is supposed to xmit this skbuff
+ *
+ * When the bond gets an skb to transmit that is
+ * already hardware accelerated VLAN tagged, and it
+ * needs to relay this skb to a slave that is not
+ * hw accel capable, the skb needs to be "unaccelerated",
+ * i.e. strip the hwaccel tag and re-insert it as part
+ * of the payload.
+ */
+int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev)
+{
+ unsigned short vlan_id;
+
+ if (!list_empty(&bond->vlan_list) &&
+ !(slave_dev->features & NETIF_F_HW_VLAN_TX) &&
+ vlan_get_tag(skb, &vlan_id) == 0) {
+ skb->dev = slave_dev;
+ skb = vlan_put_tag(skb, vlan_id);
+ if (!skb) {
+ /* vlan_put_tag() frees the skb in case of error,
+ * so return success here so the calling functions
+ * won't attempt to free is again.
+ */
+ return 0;
+ }
+ } else {
+ skb->dev = slave_dev;
+ }
+
+ skb->priority = 1;
+ dev_queue_xmit(skb);
+
+ return 0;
+}
+
+/*
+ * In the following 3 functions, bond_vlan_rx_register(), bond_vlan_rx_add_vid
+ * and bond_vlan_rx_kill_vid, We don't protect the slave list iteration with a
+ * lock because:
+ * a. This operation is performed in IOCTL context,
+ * b. The operation is protected by the RTNL semaphore in the 8021q code,
+ * c. Holding a lock with BH disabled while directly calling a base driver
+ * entry point is generally a BAD idea.
+ *
+ * The design of synchronization/protection for this operation in the 8021q
+ * module is good for one or more VLAN devices over a single physical device
+ * and cannot be extended for a teaming solution like bonding, so there is a
+ * potential race condition here where a net device from the vlan group might
+ * be referenced (either by a base driver or the 8021q code) while it is being
+ * removed from the system. However, it turns out we're not making matters
+ * worse, and if it works for regular VLAN usage it will work here too.
+*/
+
+/**
+ * bond_vlan_rx_register - Propagates registration to slaves
+ * @bond_dev: bonding net device that got called
+ * @grp: vlan group being registered
+ */
+static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp)
+{
+ struct bonding *bond = bond_dev->priv;
+ struct slave *slave;
+ int i;
+
+ bond->vlgrp = grp;
+
+ bond_for_each_slave(bond, slave, i) {
+ struct net_device *slave_dev = slave->dev;
+
+ if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
+ slave_dev->vlan_rx_register) {
+ slave_dev->vlan_rx_register(slave_dev, grp);
+ }
+ }
+}
+
+/**
+ * bond_vlan_rx_add_vid - Propagates adding an id to slaves
+ * @bond_dev: bonding net device that got called
+ * @vid: vlan id being added
+ */
+static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid)
+{
+ struct bonding *bond = bond_dev->priv;
+ struct slave *slave;
+ int i, res;
+
+ bond_for_each_slave(bond, slave, i) {
+ struct net_device *slave_dev = slave->dev;
+
+ if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&
+ slave_dev->vlan_rx_add_vid) {
+ slave_dev->vlan_rx_add_vid(slave_dev, vid);
+ }
+ }
+
+ res = bond_add_vlan(bond, vid);
+ if (res) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Failed to add vlan id %d\n",
+ bond_dev->name, vid);
+ }
+}
+
+/**
+ * bond_vlan_rx_kill_vid - Propagates deleting an id to slaves
+ * @bond_dev: bonding net device that got called
+ * @vid: vlan id being removed
+ */
+static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)
+{
+ struct bonding *bond = bond_dev->priv;
+ struct slave *slave;
+ struct net_device *vlan_dev;
+ int i, res;
+
+ bond_for_each_slave(bond, slave, i) {
+ struct net_device *slave_dev = slave->dev;
+
+ if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&
+ slave_dev->vlan_rx_kill_vid) {
+ /* Save and then restore vlan_dev in the grp array,
+ * since the slave's driver might clear it.
+ */
+ vlan_dev = bond->vlgrp->vlan_devices[vid];
+ slave_dev->vlan_rx_kill_vid(slave_dev, vid);
+ bond->vlgrp->vlan_devices[vid] = vlan_dev;
+ }
+ }
+
+ res = bond_del_vlan(bond, vid);
+ if (res) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Failed to remove vlan id %d\n",
+ bond_dev->name, vid);
+ }
+}
+
+static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev)
+{
+ struct vlan_entry *vlan;
+
+ write_lock_bh(&bond->lock);
+
+ if (list_empty(&bond->vlan_list)) {
+ goto out;
+ }
+
+ if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
+ slave_dev->vlan_rx_register) {
+ slave_dev->vlan_rx_register(slave_dev, bond->vlgrp);
+ }
+
+ if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
+ !(slave_dev->vlan_rx_add_vid)) {
+ goto out;
+ }
+
+ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+ slave_dev->vlan_rx_add_vid(slave_dev, vlan->vlan_id);
+ }
+
+out:
+ write_unlock_bh(&bond->lock);
+}
+
+static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev)
+{
+ struct vlan_entry *vlan;
+ struct net_device *vlan_dev;
+
+ write_lock_bh(&bond->lock);
+
+ if (list_empty(&bond->vlan_list)) {
+ goto out;
+ }
+
+ if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
+ !(slave_dev->vlan_rx_kill_vid)) {
+ goto unreg;
+ }