[Bonding-devel] [PATCH] Support to configure multiple bonds withdifferent module params

From: Radheka Godse
Date: Wed Jan 12 2005 - 21:06:08 EST


The attached patches add support to the channel bonding module for configuring multiple bonds at load time.
This eliminates the need to reload the module for each new differently-configured bond. A maximum of 16 bonds is supported.

This patch has been peer reviewed by our Linux software engineering team,
and the fix has been verified by our test labs.

Summary of changes made from 2.6.1 to 2.7.0 :
 o Removed most global variables.
 o Use module_param_array() to define/set defaults for module params
 o Added new module param arp_ip_count to specify how many
   ip targets in the arp_ip_target array belong to each bond.
   If arp_ip_count is not specified, to preserve backward
   compatibility all arp targets go to the first bond. 
 o Modified bonding_init() to use sub-functions to:
      - parse and separate arp parameters
      - fill insmod parameters
- sanitize (and enforce defaults if needed) on parameters
      - create and configure bond with specified parameters
 o Updated bonding.txt documentation and added examples to configure
   bonds with different parameters.
o Also this patch has initial plumbing work to prepare for adding
  sysfs interface in future (i.e. next set of patches).

Status: Tested on 2.6.11-rc1
Signed-off-by: Radheka Godse radheka.godse@xxxxxxxxx

Note: bond-patch-2.7.0-bonding.txt must be applied last!diff -urN -X dontdiff linux-2.6.11-rc1vanilla/drivers/net/bonding/bonding.h linux-2.6.11-rc1/drivers/net/bonding/bonding.h
--- linux-2.6.11-rc1vanilla/drivers/net/bonding/bonding.h 2005-01-13 12:40:10.000000000 -0800
+++ linux-2.6.11-rc1/drivers/net/bonding/bonding.h 2005-01-13 16:36:36.000000000 -0800
@@ -25,6 +25,10 @@
*
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
+ *
+ * 2005/01/12 - Radheka Godse <radheka.godse at intel dot com>
+ * - Bonding version 2.7 changes to support configuration
+ * of multiple bonds at load time.
*/

#ifndef _LINUX_BONDING_H
@@ -33,19 +37,22 @@
#include <linux/timer.h>
#include <linux/proc_fs.h>
#include <linux/if_bonding.h>
+#include <linux/kobject.h>
#include "bond_3ad.h"
#include "bond_alb.h"

-#define DRV_VERSION "2.6.1"
-#define DRV_RELDATE "October 29, 2004"
+#define DRV_VERSION "2.7.0"
+#define DRV_RELDATE "January 12 2005"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
+#define BOND_DEFAULT_MIN_BONDS 1

-#define BOND_MAX_ARP_TARGETS 16
+#define BOND_MAX_ARP_TARGETS 64 /* For all bond devices */
+#define BOND_MAX_DEV_TARGETS 16 /* per bond device */

#ifdef BONDING_DEBUG
#define dprintk(fmt, args...) \
- printk(KERN_DEBUG \
+ printk(KERN_ERR \
DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args )
#else
#define dprintk(fmt, args...)
@@ -144,7 +151,7 @@
int downdelay;
int lacp_fast;
char primary[IFNAMSIZ];
- u32 arp_targets[BOND_MAX_ARP_TARGETS];
+ u32 arp_targets[BOND_MAX_DEV_TARGETS];
};

struct vlan_entry {
@@ -153,7 +160,7 @@
};

struct slave {
- struct net_device *dev; /* first - usefull for panic debug */
+ struct net_device *dev; /* first - useful for panic debug */
struct slave *next;
struct slave *prev;
s16 delay;
@@ -179,7 +186,7 @@
* beforehand.
*/
struct bonding {
- struct net_device *dev; /* first - usefull for panic debug */
+ struct net_device *dev; /* first - useful for panic debug */
struct slave *first_slave;
struct slave *curr_active_slave;
struct slave *current_arp_slave;
@@ -203,6 +210,8 @@
struct bond_params params;
struct list_head vlan_list;
struct vlan_group *vlgrp;
+ u32 my_ip;
+ struct kobject kobj;
};

/**
@@ -247,6 +256,14 @@

struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
-
+int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
+void bond_deinit(struct net_device *bond_dev);
+int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, struct slave **vassal);
+int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
+int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev);
+void bond_mii_monitor(struct net_device *bond_dev);
+void bond_loadbalance_arp_mon(struct net_device *bond_dev);
+void bond_activebackup_arp_mon(struct net_device *bond_dev);
+const char *bond_mode_name(int mode);
#endif /* _LINUX_BONDING_H */

diff -urN -X dontdiff linux-2.6.11-rc1vanilla/drivers/net/bonding/bond_main.c linux-2.6.11-rc1/drivers/net/bonding/bond_main.c
--- linux-2.6.11-rc1vanilla/drivers/net/bonding/bond_main.c 2005-01-13 12:40:11.000000000 -0800
+++ linux-2.6.11-rc1/drivers/net/bonding/bond_main.c 2005-01-13 17:06:42.000000000 -0800
@@ -475,6 +475,33 @@
* Solution is to move call to dev_remove_pack outside of the
* spinlock.
* Set version to 2.6.1.
+ * 2004/12/14 - Mitch Williams <mitch.a.williams at intel dot com>
+ * - Split out bond creation code to allow for future addition of
+ * sysfs interface.
+ * - Added extra optional parameter to bond_enslave to return a
+ * a pointer to the new slave. This will be used by future
+ * sysfs functionality.
+ * - Removed static declaration on some functions and data items.
+ * Set version to 2.6.3
+ * 2005/01/12 - Radheka Godse <radheka.godse at intel dot com>
+ * - Added support to configure module params for multiple bonds at
+ * load time. A maximum of 16 bonds is supported.
+ * This eliminates most global variables and the need to reload
+ * the bonding module multiple times.
+ * Changes Made:
+ * o Use module_param_array() to define/set defaults for module params
+ * o Added new module param arp_ip_count to specify how many
+ * ip targets in the arp_ip_target array belong to each bond.
+ * If arp_ip_count is not specified, to preserve backward
+ * compatibility all arp targets go to the first bond.
+ * o Modified bonding_init() to use sub-functions to:
+ * - parse and separate arp parameters
+ * - fill insmod parameters
+ * - sanitize (and enforce defaults if needed) on parameters
+ * - create and configure bond with specified parameters
+ * o Updated bonding.txt documetation and added examples to configure
+ * bonds with different parameters.
+ * Set version to 2.7
*
*/

@@ -528,56 +555,65 @@
/* monitor all links that often (in milliseconds). <=0 disables monitoring */
#define BOND_LINK_MON_INTERV 0
#define BOND_LINK_ARP_INTERV 0
+#define BOND_DEFAULT_MAX_BONDS 1
+#define BOND_DEF_USE_CARRIER 1
+#define BOND_DEF_ARP_TARGETS 0
+#define BOND_DEF_ARP_COUNT 0
+#define BOND_DEF_DELAY 0
+#define BOND_MAX_UNITS 15 /* Max num of bonds (16) that can get
+ * module params.
+ */
+
+#define BOND_PARAM_INIT(DEF_VAL) { [0 ... BOND_MAX_UNITS] = DEF_VAL }
+
+#define BOND_PARAM_NUM(X, S, D) \
+static int __initdata X[BOND_MAX_UNITS + 1] = BOND_PARAM_INIT(D); \
+ static int num_##X; \
+ module_param_array(X, int, &num_##X, 0); \
+ MODULE_PARM_DESC(X, S);
+
+#define BOND_PARAM_STR(X, S, D) \
+ static char __initdata *X[BOND_MAX_UNITS +1] = BOND_PARAM_INIT(D); \
+ static int num_##X; \
+ module_param_array(X, charp, &num_##X, 0); \
+ MODULE_PARM_DESC(X, S);
+
+
+/* per each bond */
+BOND_PARAM_NUM(miimon, "Link check interval in milliseconds", BOND_LINK_MON_INTERV);
+BOND_PARAM_NUM(updelay, "Delay before considering link up, in milliseconds", BOND_DEF_DELAY);
+BOND_PARAM_NUM(downdelay, "Delay before considering link down, in milliseconds", BOND_DEF_DELAY);
+BOND_PARAM_NUM(use_carrier, "Use netif_carrier_ok in miimon", BOND_DEF_USE_CARRIER);
+BOND_PARAM_NUM(arp_interval, "arp check interval in milliseconds", BOND_DEF_ARP_TARGETS);
+BOND_PARAM_NUM(arp_ip_count, "Number of arp ip targets for a device", BOND_DEF_ARP_COUNT);
+BOND_PARAM_STR(mode, "Mode of operation", NULL);
+BOND_PARAM_STR(primary, "Primary network device to use", NULL);
+BOND_PARAM_STR(lacp_rate, "LACPDU tx rate to request from 802.3ad partner", NULL);
+
+/* Shared among all bonds */
+
+static char __initdata *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
+static int num_arp_ip_target;
+module_param_array(arp_ip_target, charp, &num_arp_ip_target, 0);
+MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");

-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);
+/* Single value */
+static int __initdata max_bonds = BOND_DEFAULT_MAX_BONDS;
+module_param(max_bonds, int, 0444);
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);
+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 app_abi_ver = 2;
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
@@ -611,10 +647,11 @@
/*-------------------------- Forward declarations ---------------------------*/

static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode);
+static int bond_check_params(struct bond_params *params, int force);

/*---------------------------- General routines -----------------------------*/

-static const char *bond_mode_name(int mode)
+const char *bond_mode_name(int mode)
{
switch (mode) {
case BOND_MODE_ROUNDROBIN :
@@ -1578,7 +1615,7 @@

/*---------------------------------- IOCTL ----------------------------------*/

-static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev)
+int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev)
{
dprintk("bond_dev=%p\n", bond_dev);
dprintk("slave_dev=%p\n", slave_dev);
@@ -1588,7 +1625,7 @@
}

/* enslave device <slave> to bond device <master> */
-static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
+int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, struct slave **vassal)
{
struct bonding *bond = bond_dev->priv;
struct slave *new_slave = NULL;
@@ -1979,6 +2016,8 @@
new_slave->link != BOND_LINK_DOWN ? "n up" : " down");

/* enslave is successful */
+ if (vassal)
+ *vassal=new_slave;
return 0;

/* Undo stages on error */
@@ -2013,7 +2052,7 @@
* for Bonded connections:
* The first up interface should be left on and all others downed.
*/
-static int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
+int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
{
struct bonding *bond = bond_dev->priv;
struct slave *slave, *oldcurrent;
@@ -2113,6 +2152,7 @@
}

if (bond->slave_cnt == 0) {
+ dprintk("last slave removed\n");
/* if the last slave was removed, zero the mac address
* of the master so it will be set by the application
* to the mac address of the first slave
@@ -2462,7 +2502,7 @@
/*-------------------------------- Monitoring -------------------------------*/

/* this function is called regularly to monitor each slave's link. */
-static void bond_mii_monitor(struct net_device *bond_dev)
+void bond_mii_monitor(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
struct slave *slave, *oldcurrent;
@@ -2708,9 +2748,9 @@
int i;
u32 *targets = bond->params.arp_targets;

- for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
+ for (i = 0; (i < BOND_MAX_DEV_TARGETS) && targets[i]; i++) {
arp_send(ARPOP_REQUEST, ETH_P_ARP, targets[i], slave->dev,
- my_ip, NULL, slave->dev->dev_addr,
+ bond->my_ip, NULL, slave->dev->dev_addr,
NULL);
}
}
@@ -2722,7 +2762,7 @@
* arp is transmitted to generate traffic. see activebackup_arp_monitor for
* arp monitoring in active backup mode.
*/
-static void bond_loadbalance_arp_mon(struct net_device *bond_dev)
+void bond_loadbalance_arp_mon(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
struct slave *slave, *oldcurrent;
@@ -2790,7 +2830,7 @@
*/
if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
(((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
- my_ip)) {
+ bond->my_ip)) {

slave->link = BOND_LINK_DOWN;
slave->state = BOND_STATE_BACKUP;
@@ -2860,7 +2900,7 @@
* may have received.
* see loadbalance_arp_monitor for arp monitoring in load balancing mode
*/
-static void bond_activebackup_arp_mon(struct net_device *bond_dev)
+void bond_activebackup_arp_mon(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
struct slave *slave;
@@ -2929,7 +2969,7 @@
if ((slave != bond->curr_active_slave) &&
(!bond->current_arp_slave) &&
(((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) &&
- my_ip)) {
+ bond->my_ip)) {
/* a backup slave has gone down; three times
* the delta allows the current slave to be
* taken out before the backup slave.
@@ -2976,7 +3016,7 @@
*/
if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
(((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
- my_ip)) &&
+ bond->my_ip)) &&
((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {

slave->link = BOND_LINK_DOWN;
@@ -3028,7 +3068,7 @@
/* the current slave must tx an arp to ensure backup slaves
* rx traffic
*/
- if (slave && my_ip) {
+ if (slave && bond->my_ip) {
bond_arp_send_all(bond, slave);
}
}
@@ -3146,6 +3186,8 @@
{
struct bonding *bond = seq->private;
struct slave *curr;
+ int i;
+ u32 target;

read_lock(&bond->curr_slave_lock);
curr = bond->curr_active_slave;
@@ -3170,6 +3212,24 @@
seq_printf(seq, "Down Delay (ms): %d\n",
bond->params.downdelay * bond->params.miimon);

+
+ // ARP information
+ if(bond->params.arp_interval > 0)
+ {
+ seq_printf(seq, "ARP Polling Interval (ms): %d\n", bond->params.arp_interval);
+
+ seq_printf(seq, "ARP IP target/s (n.n.n.n form):");
+ for (i = 0; (i < BOND_MAX_DEV_TARGETS) && bond->params.arp_targets[i] ;i++) {
+ target = ntohl(bond->params.arp_targets[i]);
+ seq_printf(seq, " %d.%d.%d.%d", HIPQUAD(target));
+
+ if((i+1 < BOND_MAX_DEV_TARGETS) && bond->params.arp_targets[i+1])
+ seq_printf(seq, ",");
+ else
+ seq_printf(seq, "\n");
+ }
+ }
+
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;

@@ -3315,7 +3375,7 @@
/* Create the bonding directory under /proc/net, if doesn't exist yet.
* Caller must hold rtnl_lock.
*/
-static void bond_create_proc_dir(void)
+static int bond_create_proc_dir(void)
{
int len = strlen(DRV_NAME);

@@ -3336,7 +3396,14 @@
": Warning: cannot create /proc/net/%s\n",
DRV_NAME);
}
+ } else {
+ printk(KERN_ERR DRV_NAME
+ ": Error: cannot load multiple module instances\n");
+
+ return -EEXIST;
}
+
+ return 0;
}

/* Destroy the bonding directory under /proc/net, if empty.
@@ -3682,8 +3749,8 @@
int prev_abi_ver = orig_app_abi_ver;
int res = 0;

- dprintk("bond_ioctl: master=%s, cmd=%d\n",
- bond_dev->name, cmd);
+// dprintk("bond_ioctl: master=%s, cmd=%d\n",
+// bond_dev->name, cmd);

switch (cmd) {
case SIOCETHTOOL:
@@ -3785,7 +3852,7 @@
switch (cmd) {
case BOND_ENSLAVE_OLD:
case SIOCBONDENSLAVE:
- res = bond_enslave(bond_dev, slave_dev);
+ res = bond_enslave(bond_dev, slave_dev, NULL);
break;
case BOND_RELEASE_OLD:
case SIOCBONDRELEASE:
@@ -3915,6 +3982,9 @@
* is probably not a good idea.
*/
dprintk("err %d %s\n", res, slave->dev->name);
+ printk(KERN_ERR DRV_NAME
+ ": Error: failed to change slave %s's mtu to "
+ "%d\n", slave->dev->name, new_mtu);
goto unwind;
}
}
@@ -4080,13 +4150,13 @@

/* if we are sending arp packets, try to at least
identify our own ip address */
- if (bond->params.arp_interval && !my_ip &&
+ if (bond->params.arp_interval && !bond->my_ip &&
(skb->protocol == __constant_htons(ETH_P_ARP))) {
char *the_ip = (char *)skb->data +
sizeof(struct ethhdr) +
sizeof(struct arphdr) +
ETH_ALEN;
- memcpy(&my_ip, the_ip, 4);
+ memcpy(&bond->my_ip, the_ip, 4);
}

read_lock(&bond->lock);
@@ -4262,12 +4332,10 @@
* Does not allocate but creates a /proc entry.
* Allowed to fail.
*/
-static int __init bond_init(struct net_device *bond_dev, struct bond_params *params)
+static int bond_init(struct net_device *bond_dev, struct bond_params *params)
{
- struct bonding *bond = bond_dev->priv;
-
- dprintk("Begin bond_init for %s\n", bond_dev->name);
-
+ struct bonding *bond;
+ bond = bond_dev->priv;
/* initialize rwlocks */
rwlock_init(&bond->lock);
rwlock_init(&bond->curr_slave_lock);
@@ -4331,7 +4399,7 @@
/* De-initialize device specific data.
* Caller must hold rtnl_lock.
*/
-static inline void bond_deinit(struct net_device *bond_dev)
+void bond_deinit(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;

@@ -4342,6 +4410,53 @@
#endif
}

+/* Create a new bond device with the specified params.
+ * Caller must hold rtnl_lock().
+ */
+int bond_create(char *name, struct bond_params *params, struct bonding **newbond)
+{
+ struct net_device *bond_dev;
+ int res;
+
+ bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup);
+ if (!bond_dev) {
+ printk(KERN_ERR "eek! can't alloc netdev!\n");
+ return -ENOMEM;
+ }
+
+ /* bond_init() must be called after dev_alloc_name() (for the
+ * /proc files), but before register_netdevice(), because we
+ * need to set function pointers.
+ */
+
+ res = bond_init(bond_dev, params);
+ if (res < 0) {
+ free_netdev(bond_dev);
+ return res;
+ }
+
+ SET_MODULE_OWNER(bond_dev);
+
+ res = register_netdevice(bond_dev);
+ if (res < 0) {
+ bond_deinit(bond_dev);
+ free_netdev(bond_dev);
+ return res;
+ }
+ if (newbond) *newbond = bond_dev->priv;
+ return res;
+}
+
+
+/* Destroy a bond device.
+ * Caller must hold rtnl_lock().
+ */
+static inline void bond_destroy_dev(struct net_device *dev)
+{
+ unregister_netdevice(dev);
+ bond_deinit(dev);
+}
+
/* Unregister and free all bond devices.
* Caller must hold rtnl_lock.
*/
@@ -4349,12 +4464,11 @@
{
struct bonding *bond, *nxt;

- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
- struct net_device *bond_dev = bond->dev;
-
- unregister_netdevice(bond_dev);
- bond_deinit(bond_dev);
- }
+ list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+ {
+ //printk(KERN_ERR"Freeing bond %s\n", bond->dev->name);
+ bond_destroy_dev(bond->dev);
+ }

#ifdef CONFIG_PROC_FS
bond_destroy_proc_dir();
@@ -4363,11 +4477,156 @@

/*------------------------- Module initialization ---------------------------*/

+/**
+ * bond_is_valid_ip_target - check validity of ip target
+ *
+ * An ip target is in the format of ddd.ddd.ddd.ddd
+ * where each 'ddd' group is 1-3 digits long, between
+ * 0 and 255, and groups are separated by a '.'
+ */
+static int bond_is_valid_ip_target(char *ip_addr)
+{
+ int groups = 0, digits;
+ unsigned long val;
+ char *pos = ip_addr, buff[4];
+
+ do {
+ digits = 0;
+ memset(buff, 0, 4);
+
+ while (*pos && (*pos != '.')) {
+ if (!isdigit(*pos)) {
+ dprintk("Not a digit (%c)\n", *pos);
+ return -EINVAL;
+ }
+
+ buff[digits++] = *pos++;
+
+ if (digits > 3) {
+ dprintk("Too many digits (%d)\n", digits);
+ return -EINVAL;
+ }
+ }
+
+ if (digits == 0) {
+ dprintk("digits is 0\n");
+ return -EINVAL;
+ }
+
+ val = simple_strtoul(buff, NULL, 10);
+ if (val > 255) {
+ dprintk("val out of range (%d)\n", val);
+ return -EINVAL;
+ }
+
+ groups++;
+ if (groups > 4) {
+ dprintk("Too many groups (%d)\n", groups);
+ return -EINVAL;
+ }
+ } while (*pos++);
+
+ if (groups != 4) {
+ dprintk("Not enough groups (%d)\n", groups);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * bond_check_arp_mon_params - check arp monitoring params.
+ *
+ * This a special case since the arp_ip_target param is already
+ * in array format and could not be extended to a 2 dimentional
+ * array. A separate module param, arp_ip_count, was added to
+ * determine how many arp targets from the arp_ip_target array
+ * belong to each bond device. This function checks:
+ *
+ * 1) arp_interval and arp_ip_count of each bond are in range.
+ * 2) all arp_ip_targets are legal.
+ * 3) total amount of arp_ip_count matches the amount of
+ * arp_ip_targets.
+ *
+ * If arp_ip_count is not specified for any bond, all arp_ip_targets
+ * go to the first bond to preserve backward compatibility.
+ */
+static int bond_check_arp_params(void)
+{
+ int i;
+ int arp_cnt_set = 0;
+ int total_arp_cnt = 0;
+ int total_arp_tgt = 0;
+
+ for (i = 0; i < BOND_MAX_UNITS; i++) {
+ if ((arp_ip_count[i] < 0) ||
+ (arp_ip_count[i] > BOND_MAX_DEV_TARGETS)) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: arp_ip_count module parameter (%d) "
+ "at position %d is not in range 0-%d\n",
+ arp_ip_count[i], i, BOND_MAX_DEV_TARGETS);
+ return -EINVAL;
+ }
+
+ if (arp_ip_count[i]) {
+ arp_cnt_set++;
+ total_arp_cnt += arp_ip_count[i];
+ }
+ }
+
+ for (i = 0; (i < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) {
+ if (bond_is_valid_ip_target(arp_ip_target[i])== 0) {
+ total_arp_tgt++;
+ } else {
+ printk(KERN_ERR DRV_NAME
+ ": Error: Illegal arp_ip_target[%d] %s\n", i,
+ (arp_ip_target[i] ? arp_ip_target[i] :"NULL"));
+ return -EINVAL;
+ }
+ }
+
+ if (!arp_cnt_set && total_arp_tgt) {
+ arp_ip_count[0] = min(total_arp_tgt, BOND_MAX_DEV_TARGETS);
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: no arp_ip_count specified, "
+ "giving %d arp targets to first bond device\n",
+ arp_ip_count[0]);
+ return 0;
+ }
+
+ if (total_arp_cnt != total_arp_tgt) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: Total amount of arp ip targets (%d) does "
+ "not match the sum of arp ip count (%d)\n",
+ total_arp_tgt, total_arp_cnt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * give default values for all params
+ */
+static inline void bond_set_def_params(struct bond_params *params)
+{
+ params->mode = BOND_MODE_ROUNDROBIN;
+ params->miimon = BOND_LINK_MON_INTERV;
+ params->arp_interval = BOND_LINK_ARP_INTERV;
+ params->use_carrier = BOND_DEF_USE_CARRIER;
+ params->updelay = BOND_DEF_DELAY;
+ params->downdelay = BOND_DEF_DELAY;
+ params->lacp_fast = BOND_3AD_LACP_SLOW;
+ params->primary[0] = '\0';
+
+ memset(params->arp_targets, 0, sizeof(params->arp_targets));
+}
+
/*
* Convert string input module parms. Accept either the
* number of the mode or its string name.
*/
-static inline int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl)
+static inline int bond_parse_parm(const char *mode_arg, struct bond_parm_tbl *tbl)
{
int i;

@@ -4383,116 +4642,240 @@
return -1;
}

-static int bond_check_params(struct bond_params *params)
+/*
+ * fill values for all params from global vars.
+ */
+static void bond_fill_insmod_params(struct bond_params *params, int position)
{
- /*
- * Convert string parameters.
- */
- if (mode) {
- bond_mode = bond_parse_parm(mode, bond_mode_tbl);
- if (bond_mode == -1) {
- printk(KERN_ERR DRV_NAME
- ": Error: Invalid bonding mode \"%s\"\n",
- mode == NULL ? "NULL" : mode);
- return -EINVAL;
- }
+ int i, j, start, end;
+ static int arp_ip_offset = 0;
+
+ bond_set_def_params(params);
+
+ if (position > BOND_MAX_UNITS) {
+ return;
}
+
+ // set input values
+ if(miimon[position] != BOND_LINK_MON_INTERV)
+ {
+ params->miimon = miimon[position];
+ }
+
+ if(use_carrier[position] != BOND_DEF_USE_CARRIER)
+ params->use_carrier = use_carrier[position];
+ if(updelay[position] != BOND_DEF_DELAY)
+ params->updelay = updelay[position];
+ if(downdelay[position] != BOND_DEF_DELAY)
+ params->downdelay = downdelay[position];
+
+
+ if (mode[position] && *(mode[position])) {
+ params->mode = bond_parse_parm(mode[position], bond_mode_tbl);
+ }
+
+ if (lacp_rate[position] && *(lacp_rate[position])) {
+ params->lacp_fast = bond_parse_parm(lacp_rate[position],
+ bond_lacp_tbl);

- if (lacp_rate) {
- if (bond_mode != BOND_MODE_8023AD) {
+ if (params->mode != BOND_MODE_8023AD) {
printk(KERN_INFO DRV_NAME
": lacp_rate param is irrelevant in mode %s\n",
- bond_mode_name(bond_mode));
- } else {
- lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl);
- if (lacp_fast == -1) {
- printk(KERN_ERR DRV_NAME
- ": Error: Invalid lacp rate \"%s\"\n",
- lacp_rate == NULL ? "NULL" : lacp_rate);
- return -EINVAL;
- }
+ bond_mode_name(params->mode));
+ // reset to default
+ params->lacp_fast = BOND_3AD_LACP_SLOW;
+ }
+ }
+
+ if (primary[position] && *(primary[position])) {
+ strncpy(params->primary, primary[position], IFNAMSIZ);
+ params->primary[IFNAMSIZ - 1] = 0;
+ }
+
+
+ if(arp_interval[position] != BOND_LINK_ARP_INTERV)
+ {
+ if (params->mode == BOND_MODE_8023AD ||
+ params->mode == BOND_MODE_TLB ||
+ params->mode == BOND_MODE_ALB ) {
+ printk(KERN_INFO DRV_NAME
+ ": arp_interval is irrelevant and will be disabled in mode %s\n",
+ bond_mode_name(params->mode));
+ // reset to default
+ params->arp_interval = BOND_LINK_ARP_INTERV;
+ }
+ else {
+ params->arp_interval = arp_interval[position];
}
}
+
+ /*
+ * Convert arp target parameters.
+ */
+ memset(params->arp_targets, 0, sizeof(params->arp_targets));

- if (max_bonds < 1 || max_bonds > INT_MAX) {
- printk(KERN_WARNING DRV_NAME
- ": Warning: max_bonds (%d) not in range %d-%d, so it "
- "was reset to BOND_DEFAULT_MAX_BONDS (%d)",
- max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS);
- max_bonds = BOND_DEFAULT_MAX_BONDS;
+ start = arp_ip_offset;
+ arp_ip_offset += arp_ip_count[position];
+ end = arp_ip_offset;
+
+ for (j=0, i = start; i < end; i++,j++){
+ params->arp_targets[j] = in_aton(arp_ip_target[i]);
+
+ }
+}
+
+/**
+ * bond_check_params - perform sanity checks on params.
+ *
+ * If @force is set, and there is a reasonable default value,
+ * params can be reset. Otherwise fail the insmod operation.
+ */
+static int bond_check_params(struct bond_params *params, int force)
+{
+ if ((params->mode < 0) ||
+ (params->mode >= BOND_MODE_MAX)) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: Invalid bonding mode\n");
+ return -EINVAL;
+ }
+
+
+ if ((params->lacp_fast < 0) ||
+ (params->lacp_fast >= BOND_3AD_LACP_MAX)) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: Invalid lacp rate \n");
+ return -EINVAL;
}

- if (miimon < 0) {
+ if (params->miimon < 0) {
printk(KERN_WARNING DRV_NAME
": Warning: miimon module parameter (%d), "
- "not in range 0-%d, so it was reset to %d\n",
- miimon, INT_MAX, BOND_LINK_MON_INTERV);
- miimon = BOND_LINK_MON_INTERV;
+ "must be positive\n",
+ params->miimon);
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": resetting miimon to %d\n",
+ BOND_LINK_MON_INTERV);
+ params->miimon = BOND_LINK_MON_INTERV;
+ } else {
+ return -EINVAL;
+ }
}

- if (updelay < 0) {
+ if (params->updelay < 0) {
printk(KERN_WARNING DRV_NAME
": Warning: updelay module parameter (%d), "
- "not in range 0-%d, so it was reset to 0\n",
- updelay, INT_MAX);
- updelay = 0;
+ "must be positive\n",
+ params->updelay);
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": resetting updelay to %d\n",
+ BOND_DEF_DELAY);
+ params->updelay = BOND_DEF_DELAY;
+ } else {
+ return -EINVAL;
+ }
}

- if (downdelay < 0) {
+ if (params->downdelay < 0) {
printk(KERN_WARNING DRV_NAME
": Warning: downdelay module parameter (%d), "
- "not in range 0-%d, so it was reset to 0\n",
- downdelay, INT_MAX);
- downdelay = 0;
+ "must be positive\n",
+ params->downdelay);
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": resetting downdelay to %d\n",
+ BOND_DEF_DELAY);
+ params->downdelay = BOND_DEF_DELAY;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ if (params->arp_interval < 0) {
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: arp_interval module parameter (%d), "
+ "must be positive\n",
+ params->arp_interval);
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": resetting arp_interval to %d\n",
+ BOND_LINK_ARP_INTERV);
+ params->arp_interval = BOND_LINK_ARP_INTERV;
+ } else {
+ return -EINVAL;
+ }
}

- if ((use_carrier != 0) && (use_carrier != 1)) {
+ if ((params->use_carrier != 0) && (params->use_carrier != 1)) {
printk(KERN_WARNING DRV_NAME
": Warning: use_carrier module parameter (%d), "
"not of valid value (0/1), so it was set to 1\n",
- use_carrier);
- use_carrier = 1;
+ params->use_carrier);
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": resetting use_carrier to %d\n",
+ BOND_DEF_USE_CARRIER);
+ params->use_carrier = BOND_DEF_USE_CARRIER;
+ } else {
+ return -EINVAL;
+ }
}

/* reset values for 802.3ad */
- if (bond_mode == BOND_MODE_8023AD) {
- if (!miimon) {
+ if (params->mode == BOND_MODE_8023AD) {
+ if (!params->miimon) {
printk(KERN_WARNING DRV_NAME
": Warning: miimon must be specified, "
"otherwise bonding will not detect link "
"failure, speed and duplex which are "
"essential for 802.3ad operation\n");
- printk(KERN_WARNING "Forcing miimon to 100msec\n");
- miimon = 100;
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": forcing miimon to 100msec\n");
+ params->miimon = 100;
+ } else {
+ return -EINVAL;
+ }
}
}

/* reset values for TLB/ALB */
- if ((bond_mode == BOND_MODE_TLB) ||
- (bond_mode == BOND_MODE_ALB)) {
- if (!miimon) {
+ if ((params->mode == BOND_MODE_TLB) ||
+ (params->mode == BOND_MODE_ALB)) {
+ if (!params->miimon) {
printk(KERN_WARNING DRV_NAME
": Warning: miimon must be specified, "
"otherwise bonding will not detect link "
"failure and link speed which are essential "
"for TLB/ALB load balancing\n");
- printk(KERN_WARNING "Forcing miimon to 100msec\n");
- miimon = 100;
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": forcing miimon to 100msec\n");
+ params->miimon = 100;
+ } else {
+ return -EINVAL;
+ }
}
}

- if (bond_mode == BOND_MODE_ALB) {
- printk(KERN_NOTICE DRV_NAME
- ": In ALB mode you might experience client "
- "disconnections upon reconnection of a link if the "
- "bonding module updelay parameter (%d msec) is "
- "incompatible with the forwarding delay time of the "
- "switch\n",
- updelay);
+ if (params->arp_interval && !params->arp_targets[0]) {
+ /* don't allow arping if no arp_ip_target given... */
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: arp_interval module parameter (%d) "
+ "specified without providing arp ip targets\n",
+ params->arp_interval);
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": disabling ARP monitoring\n");
+ params->arp_interval = 0;
+ } else {
+ return -EINVAL;
+ }
}

- if (!miimon) {
- if (updelay || downdelay) {
+ if (!params->miimon) {
+ if (params->updelay || params->downdelay) {
/* just warn the user the up/down delay will have
* no effect since miimon is zero...
*/
@@ -4501,90 +4884,59 @@
"and updelay (%d) or downdelay (%d) module "
"parameter is set; updelay and downdelay have "
"no effect unless miimon is set\n",
- updelay, downdelay);
+ params->updelay, params->downdelay);
+
+ params->updelay = 0;
+ params->downdelay = 0;
}
} else {
/* don't allow arp monitoring */
- if (arp_interval) {
+ if (params->arp_interval) {
printk(KERN_WARNING DRV_NAME
": Warning: miimon (%d) and arp_interval (%d) "
"can't be used simultaneously, disabling ARP "
"monitoring\n",
- miimon, arp_interval);
- arp_interval = 0;
+ params->miimon, params->arp_interval);
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": disabling ARP monitoring\n");
+ params->arp_interval = 0;
+ } else {
+ return -EINVAL;
+ }
}

- if ((updelay % miimon) != 0) {
+ if ((params->updelay % params->miimon) != 0) {
printk(KERN_WARNING DRV_NAME
": Warning: updelay (%d) is not a multiple "
"of miimon (%d), updelay rounded to %d ms\n",
- updelay, miimon, (updelay / miimon) * miimon);
+ params->updelay, params->miimon,
+ (params->updelay / params->miimon) *
+ params->miimon);
}

- updelay /= miimon;
+ params->updelay /= params->miimon;

- if ((downdelay % miimon) != 0) {
+ if ((params->downdelay % params->miimon) != 0) {
printk(KERN_WARNING DRV_NAME
": Warning: downdelay (%d) is not a multiple "
"of miimon (%d), downdelay rounded to %d ms\n",
- downdelay, miimon,
- (downdelay / miimon) * miimon);
- }
-
- downdelay /= miimon;
+ params->downdelay, params->miimon,
+ (params->downdelay / params->miimon) *
+ params->miimon);
}

- if (arp_interval < 0) {
- printk(KERN_WARNING DRV_NAME
- ": Warning: arp_interval module parameter (%d) "
- ", not in range 0-%d, so it was reset to %d\n",
- arp_interval, INT_MAX, BOND_LINK_ARP_INTERV);
- arp_interval = BOND_LINK_ARP_INTERV;
+ params->downdelay /= params->miimon;
}

- for (arp_ip_count = 0;
- (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[arp_ip_count];
- arp_ip_count++) {
- /* not complete check, but should be good enough to
- catch mistakes */
- if (!isdigit(arp_ip_target[arp_ip_count][0])) {
- printk(KERN_WARNING DRV_NAME
- ": Warning: bad arp_ip_target module parameter "
- "(%s), ARP monitoring will not be performed\n",
- arp_ip_target[arp_ip_count]);
- arp_interval = 0;
- } else {
- u32 ip = in_aton(arp_ip_target[arp_ip_count]);
- arp_target[arp_ip_count] = ip;
- }
- }
-
- if (arp_interval && !arp_ip_count) {
- /* don't allow arping if no arp_ip_target given... */
- printk(KERN_WARNING DRV_NAME
- ": Warning: arp_interval module parameter (%d) "
- "specified without providing an arp_ip_target "
- "parameter, arp_interval was reset to 0\n",
- arp_interval);
- arp_interval = 0;
- }
-
- if (miimon) {
+ if (params->miimon) {
printk(KERN_INFO DRV_NAME
": MII link monitoring set to %d ms\n",
- miimon);
- } else if (arp_interval) {
- int i;
-
+ params->miimon);
+ } else if (params->arp_interval) {
printk(KERN_INFO DRV_NAME
- ": ARP monitoring set to %d ms with %d target(s):",
- arp_interval, arp_ip_count);
-
- for (i = 0; i < arp_ip_count; i++)
- printk (" %s", arp_ip_target[i]);
-
- printk("\n");
-
+ ": ARP monitoring set to %d ms\n",
+ params->arp_interval);
} else {
/* miimon and arp_interval not set, we need one so things
* work as expected, see bonding.txt for details
@@ -4592,113 +4944,117 @@
printk(KERN_WARNING DRV_NAME
": Warning: either miimon or arp_interval and "
"arp_ip_target module parameters must be specified, "
- "otherwise bonding will not detect link failures! see "
+ "otherwise bonding will not detect link failures! See "
"bonding.txt for details.\n");
}

- if (primary && !USES_PRIMARY(bond_mode)) {
+ if ((params->primary[0] != '\0') && !USES_PRIMARY(params->mode)) {
/* currently, using a primary only makes sense
* in active backup, TLB or ALB modes
*/
printk(KERN_WARNING DRV_NAME
": Warning: %s primary device specified but has no "
"effect in %s mode\n",
- primary, bond_mode_name(bond_mode));
- primary = NULL;
+ params->primary, bond_mode_name(params->mode));
+ if (force) {
+ printk(KERN_WARNING DRV_NAME
+ ": clearing primary param\n");
+ params->primary[0] = '\0';
+ } else {
+ return -EINVAL;
+ }
}

- /* fill params struct with the proper values */
- params->mode = bond_mode;
- params->miimon = miimon;
- params->arp_interval = arp_interval;
- params->updelay = updelay;
- params->downdelay = downdelay;
- params->use_carrier = use_carrier;
- params->lacp_fast = lacp_fast;
- params->primary[0] = 0;
-
- if (primary) {
- strncpy(params->primary, primary, IFNAMSIZ);
- params->primary[IFNAMSIZ - 1] = 0;
+ if (!params->arp_interval && params->arp_targets[0]) {
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: arp_ip_targets specified with "
+ "arp_interval disabled, so it has no effect\n");
+ memset(params->arp_targets, 0, sizeof(params->arp_targets));
}

- memcpy(params->arp_targets, arp_target, sizeof(arp_target));
+ if (params->mode == BOND_MODE_ALB) {
+ printk(KERN_NOTICE DRV_NAME
+ ": In ALB mode you might experience client "
+ "disconnections upon reconnection of a link if the "
+ "bonding module updelay parameter (%d msec) is "
+ "incompatible with the forwarding delay time of the "
+ "switch\n",
+ params->updelay * params->miimon);
+ }

return 0;
}

static int __init bonding_init(void)
{
- struct bond_params params;
int i;
- int res;
+ int res = 0;
+ char new_bond_name[8]; // Enough room for 999 bonds at init.
+ // Should be enough...

printk(KERN_INFO "%s", version);
+
+ if (max_bonds < BOND_DEFAULT_MAX_BONDS || max_bonds > (BOND_MAX_UNITS+1)) {
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: max_bonds (%d) not in range %d-%d, so it "
+ "was reset to (%d)\n",
+ max_bonds, BOND_DEFAULT_MAX_BONDS,(BOND_MAX_UNITS+1), BOND_DEFAULT_MAX_BONDS);
+ max_bonds = BOND_DEFAULT_MAX_BONDS;
+ }

- res = bond_check_params(&params);
- if (res) {
+ res = bond_check_arp_params();
+ if (res < 0) {
return res;
}

rtnl_lock();

#ifdef CONFIG_PROC_FS
- bond_create_proc_dir();
+ res = bond_create_proc_dir();
+ if (res < 0) {
+ rtnl_unlock();
+ return res;
+ }
#endif

for (i = 0; i < max_bonds; i++) {
- struct net_device *bond_dev;
-
- bond_dev = alloc_netdev(sizeof(struct bonding), "", ether_setup);
- if (!bond_dev) {
- res = -ENOMEM;
- goto out_err;
- }
-
- res = dev_alloc_name(bond_dev, "bond%d");
- if (res < 0) {
- free_netdev(bond_dev);
- goto out_err;
- }
+ struct bond_params params;
+ sprintf(new_bond_name, "bond%d",i);
+
+ bond_fill_insmod_params(&params, i);

- /* bond_init() must be called after dev_alloc_name() (for the
- * /proc files), but before register_netdevice(), because we
- * need to set function pointers.
- */
- res = bond_init(bond_dev, &params);
+ res = bond_check_params(&params, 1);
if (res < 0) {
- free_netdev(bond_dev);
- goto out_err;
+ goto err;
}

- SET_MODULE_OWNER(bond_dev);
-
- res = register_netdevice(bond_dev);
+ res = bond_create(new_bond_name,&params, NULL);
if (res < 0) {
- bond_deinit(bond_dev);
- free_netdev(bond_dev);
- goto out_err;
+ goto err;
}
}

rtnl_unlock();
+
register_netdevice_notifier(&bond_netdev_notifier);

return 0;

-out_err:
- /* free and unregister all bonds that were successfully added */
+err:
+ /* free and unregister all bonds that were
+ * successfully added.
+ */
+ rtnl_unlock(); /* note: this has to be done to complete
+ * net_dev registeration */
+ rtnl_lock();
bond_free_all();
-
- rtnl_unlock();
-
+ rtnl_unlock();
return res;
}

static void __exit bonding_exit(void)
{
unregister_netdevice_notifier(&bond_netdev_notifier);
-
rtnl_lock();
bond_free_all();
rtnl_unlock();
diff -urN -X dontdiff linux-2.6.11-rc1vanilla/include/linux/if_bonding.h linux-2.6.11-rc1/include/linux/if_bonding.h
--- linux-2.6.11-rc1vanilla/include/linux/if_bonding.h 2005-01-13 12:39:54.000000000 -0800
+++ linux-2.6.11-rc1/include/linux/if_bonding.h 2005-01-13 12:42:26.000000000 -0800
@@ -60,13 +60,17 @@

#define BOND_CHECK_MII_STATUS (SIOCGMIIPHY)

-#define BOND_MODE_ROUNDROBIN 0
-#define BOND_MODE_ACTIVEBACKUP 1
-#define BOND_MODE_XOR 2
-#define BOND_MODE_BROADCAST 3
-#define BOND_MODE_8023AD 4
-#define BOND_MODE_TLB 5
-#define BOND_MODE_ALB 6 /* TLB + RLB (receive load balancing) */
+enum {
+ BOND_MODE_ROUNDROBIN = 0,
+ BOND_MODE_ACTIVEBACKUP = 1,
+ BOND_MODE_XOR = 2,
+ BOND_MODE_BROADCAST = 3,
+ BOND_MODE_8023AD = 4,
+ BOND_MODE_TLB = 5,
+ BOND_MODE_ALB = 6, /* TLB + RLB (receive load balancing) */
+
+ BOND_MODE_MAX /* must be last entry */
+};

/* each slave's link has 4 states */
#define BOND_LINK_UP 0 /* link is up and running */
@@ -78,7 +82,13 @@
#define BOND_STATE_ACTIVE 0 /* link is active */
#define BOND_STATE_BACKUP 1 /* link is backup */

-#define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */
+//#define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */
+enum {
+ BOND_3AD_LACP_SLOW = 0,
+ BOND_3AD_LACP_FAST = 1,
+
+ BOND_3AD_LACP_MAX /* must be last entry */
+};

typedef struct ifbond {
__s32 bond_mode;
diff -urN -X dontdiff linux-2.6.11-rc1/Documentation/networking/bonding.txt linux-2.6.11-rc1gold/Documentation/networking/bonding.txt
--- linux-2.6.11-rc1/Documentation/networking/bonding.txt 2004-12-24 13:34:29.000000000 -0800
+++ linux-2.6.11-rc1gold/Documentation/networking/bonding.txt 2005-01-13 14:15:56.000000000 -0800
@@ -41,21 +41,17 @@

1) Build kernel with the bonding driver
---------------------------------------
-For the latest version of the bonding driver, use kernel 2.4.12 or above
-(otherwise you will need to apply a patch).
-
Configure kernel with `make menuconfig/xconfig/config', and select "Bonding
driver support" in the "Network device support" section. It is recommended
-to configure the driver as module since it is currently the only way to
-pass parameters to the driver and configure more than one bonding device.
+to configure the driver as module.

Build and install the new kernel and modules.

2) Get and install the userspace tools
--------------------------------------
-This version of the bonding driver requires updated ifenslave program. The
+This version of the bonding driver requires an updated ifenslave program. The
original one from extreme-linux and beowulf will not work. Kernels 2.4.12
-and above include the updated version of ifenslave.c in
+and above include the updated version of ifenslave.c in
Documentation/networking directory. For older kernels, please follow the
links at the end of this file.

@@ -195,9 +191,9 @@
is recommended "tail -f /var/log/messages" be run in a separate window to
watch for bonding driver error messages.

-It is critical that either the miimon or arp_interval and arp_ip_target
-parameters be specified, otherwise serious network degradation will occur
-during link failures.
+It is critical that either the miimon or arp_interval and arp_ip_count,
+arp_ip_target parameters be specified for each bond interface, otherwise
+serious network degradation will occur during link failures.

arp_interval

@@ -206,19 +202,30 @@
switch should be configured in a mode that evenly distributes packets
across all links - such as round-robin. If the switch is configured to
distribute the packets in an XOR fashion, all replies from the ARP
- targets will be received on the same link which could cause the other
+ targets will be received on the same link, which could cause the other
team members to fail. ARP monitoring should not be used in conjunction
with miimon. A value of 0 disables ARP monitoring. The default value
- is 0.
+ is 0. Since MII monitoring is preferred over ARP monitoring in
+ 802.3ad(4), TLB(5) and ALB(6) modes if specified arp_interval will be
+ disabled in these modes.

arp_ip_target

- Specifies the ip addresses to use when arp_interval is > 0. These
+ Specifies the IP addresses to use when arp_interval is > 0. These
are the targets of the ARP request sent to determine the health of
the link to the targets. Specify these values in ddd.ddd.ddd.ddd
- format. Multiple ip adresses must be seperated by a comma. At least
- one ip address needs to be given for ARP monitoring to work. The
- maximum number of targets that can be specified is set at 16.
+ format. Multiple IP addresses must be separated by a comma. At least
+ one IP address needs to be given for ARP monitoring to work. The
+ maximum number of targets that can be specified is set at 64 for all
+ bond devices and 16 for each bond device.
+
+arp_ip_count
+
+ Determines how many arp ip targets specified in the arp_ip_target
+ list above belong to each bond device when several bonding interfaces
+ are being created. If arp_ip_count is not specified for any bond device,
+ all arp_ip_targets go to the first device to preserve backward
+ compatibility. Bonding version 2.7 and above support this parameter.

downdelay

@@ -246,10 +253,12 @@

miimon

- Specifies the frequency in milli-seconds that MII link monitoring
+ Specifies the frequency in milli-seconds that MII link monitoring
will occur. A value of zero disables MII link monitoring. A value
of 100 is a good starting point. See High Availability section for
- additional information. The default value is 0.
+ additional information. If not specified MII link monitoring is
+ enabled to 100 ms in 802.3ad(4), TLB(5) and ALB(6) modes. For all
+ other modes the default is 0.

mode

@@ -337,7 +346,7 @@
request is broadcasted it uses the hw address of the
bond. Hence, clients learn the hw address of the bond and
the balancing of receive traffic collapses to the current
- salve. This is handled by sending updates (ARP Replies) to
+ slave. This is handled by sending updates (ARP Replies) to
all the clients with their assigned hw address such that
the traffic is redistributed. Receive traffic is also
redistributed when a new slave is added to the bond and
@@ -347,7 +356,7 @@

When a link is reconnected or a new slave joins the bond
the receive traffic is redistributed among all active
- slaves in the bond by intiating ARP Replies with the
+ slaves in the bond by initiating ARP Replies with the
selected mac address to each of the clients. The updelay
modeprobe parameter must be set to a value equal or greater
than the switch's forwarding delay so that the ARP Replies
@@ -378,7 +387,7 @@
100Mbps. If the 1000Mbps slave fails and is later restored, it may
be preferred the faster slave gracefully become the active slave -
without deliberately failing the 100Mbps slave. Specifying a
- primary is only valid in active-backup mode.
+ primary is only valid in active-backup, ALB and TLB mode.

updelay

@@ -411,23 +420,50 @@
Configuring Multiple Bonds
==========================

-If several bonding interfaces are required, either specify the max_bonds
-parameter (described above), or load the driver multiple times. Using
-the max_bonds parameter is less complicated, but has the limitation that
-all bonding instances created will have the same options. Loading the
-driver multiple times allows each instance of the driver to have differing
-options.
+If several bonding interfaces are required, specify the max_bonds
+parameter (described above. Bonding instances with different options
+can be created by specifiying required options on the command line
+(see examples below).

For example, to configure two bonding interfaces, one with mii link
monitoring performed every 100 milliseconds, and one with ARP link
-monitoring performed every 200 milliseconds, the /etc/conf.modules should
-resemble the following:
+monitoring performed every 200 milliseconds, the /etc/modprobe.conf
+should resemble the following:
+
+alias bond0 bonding
+alias bond1 bonding
+
+options bonding max_bonds=2 miimon=100,0 \
+ arp_interval=0,200 arp_ip_target=10.0.0.1 arp_ip_count=0,1

+Another example, that uses almost all of the module parameters:
alias bond0 bonding
alias bond1 bonding
+alias bond2 bonding
+alias bond3 bonding
+alias bond4 bonding
+alias bond5 bonding
+alias bond6 bonding
+
+options bonding max_bonds=7 mode=0,1,2,3,4,5,6 lacp_rate=0,0,0,0,1,0,0 \
+ miimon=0,0,0,0,100,200,300 arp_interval=100,200,300,400 \
+ arp_ip_target=10.0.0.1,10.0.0.2,10.0.0.3,10.0.0.4 \
+ arp_ip_count=1,1,1,1,0,0,0 updelay=0,0,0,0,0,1000,2100 \
+ downdelay=0,0,0,0,0,1000,2100 \
+ primary=none,eth2,none,none,none,eth10,eth12
+
+Here's what you'll get out of the example above:
+bond0: balance-rr (0) mode with arp_interval=100 and arp_ip_target=10.0.0.1
+bond1: active-backup (1) mode with arp_interval=200, arp_ip_target=10.0.0.2,
+and eth2 as primary
+bond2: balance-xor (2) mode with arp_interval=300 and arp_ip_target=10.0.0.3
+bond3: broadcast (3) mode with arp_interval=400 and arp_ip_target=10.0.0.4
+bond4: 802.3ad (4) mode with lacp_rate=1 (fast) and miimon=100
+bond5: balance-tlb (5) mode with miimon=200, updelay=1000, downdelay=1000,
+and eth10 as primary
+bond6: balance-alb (6) mode with miimon=300, updelay=2100, downdelay=2100,
+and eth12 as primary

-options bond0 miimon=100
-options bond1 -o bonding1 arp_interval=200 arp_ip_target=10.0.0.1

Configuring Multiple ARP Targets
================================
@@ -438,17 +474,35 @@
making it unresponsive to ARP requests. Having an additional target (or
several) increases the reliability of the ARP monitoring.

-Multiple ARP targets must be seperated by commas as follows:
+Multiple ARP targets must be separated by commas as follows:
+
+# example options for ARP monitoring a single bond with three targets
+alias bond0 bonding
+options bonding arp_interval=60 \
+arp_ip_target=192.168.0.1,192.168.0.3,192.168.0.9

-# example options for ARP monitoring with three targets
+If configuring multiple ARP targets for multiple bonds, use arp_ip_count
+to specify how many arp targets from the arp_ip_target list belong to each
+bond device. If arp_ip_count is not specified for any bond, all
+arp_ip_targets go to the first bond to preserve backward compatibility.
+
+# example options for ARP monitoring multiple bonds with multiple arp targets
alias bond0 bonding
-options bond0 arp_interval=60 arp_ip_target=192.168.0.1,192.168.0.3,192.168.0.9
+alias bond1 bonding
+
+options bonding max_bonds=2 arp_interval=60,200 \
+arp_ip_count=1,2 arp_ip_target=192.168.0.1,192.168.0.3,192.168.0.9
+
+# In above example,
+# bond0 is configured with arp interval 60 and one arp target: 192.168.0.1
+# bond1 is configured with arp interval 200 and the remaining two arp targets

For just a single target the options would resemble:

-# example options for ARP monitoring with one target
+# example options for ARP monitoring a single bond with one target
alias bond0 bonding
-options bond0 arp_interval=60 arp_ip_target=192.168.0.100
+options bonding arp_interval=60 arp_ip_target=192.168.0.100
+

Potential Problems When Using ARP Monitor
=========================================
@@ -580,7 +634,8 @@

3. How many bonding devices can I have?

- There is no limit.
+ Up to 16 max bond devices can be created and configured
+ by specifying commandline options to modprobe.

4. How many slaves can a bonding device have?

@@ -631,7 +686,7 @@
units.
* Linux bonding, of course !

- In 802.3ad mode, it works with with systems that support IEEE 802.3ad
+ In 802.3ad mode, it works with systems that support IEEE 802.3ad
Dynamic Link Aggregation:

* Extreme networks Summit 7i (look for link-aggregation).
@@ -649,7 +704,7 @@
If not explicitly configured with ifconfig, the MAC address of the
bonding device is taken from its first slave device. This MAC address
is then passed to all following slaves and remains persistent (even if
- the the first slave is removed) until the bonding device is brought
+ the first slave is removed) until the bonding device is brought
down or reconfigured.

If you wish to change the MAC address, you can set it with ifconfig:
@@ -723,7 +778,7 @@
IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The
check interval is specified by the module argument "miimon" (MII monitoring).
It takes an integer that represents the checking time in milliseconds. It
-should not come to close to (1000/HZ) (10 milli-seconds on i386) because it
+should not come too close to (1000/HZ) (10 milli-seconds on i386) because it
may then reduce the system interactivity. A value of 100 seems to be a good
starting point. It means that a dead link will be detected at most 100
milli-seconds after it goes down.
@@ -932,10 +987,11 @@
those IDs to tag self generated packets.

For simplicity reasons, and to support the use of adapters that can do VLAN
-hardware acceleration offloding, the bonding interface declares itself as
-fully hardware offloaing capable, it gets the add_vid/kill_vid notifications
+hardware acceleration offloading, the bonding interface declares itself as
+fully hardware offloading capable, it gets the add_vid/kill_vid notifications
to gather the necessary information, and it propagates those actions to the
slaves.
+
In case of mixed adapter types, hardware accelerated tagged packets that should
go through an adapter that is not offloading capable are "un-accelerated" by the
bonding driver so the VLAN tag sits in the regular location.