|
From: Peter O. <pet...@vi...> - 2005-05-30 15:38:04
|
Hello,
=20
Jay Vosburgh has made a patch for the bonding driver in the 2.6.x
kernel, this patch adds better vlan support for self generated ARP
packets. I have ported and tested this patch in 2.4.31-rc1, and it works
great. Hopefully the patch will be apart of the kernel mainline in a
near future, but it's not there yet. I was thinking, will you accept
patches like this, and apply them in the next release of DL, or what's
your policy for patching?
=20
I'm attaching the patch to this mail, you're free to use it if you like,
it is made against 2.4.31-rc1, I'm not sure if it works against 2.4.30,
but it should, maybe except the first part that adds information to the
changelog in the top of bond_main.c.
=20
----
=20
diff -Naur -p linux-2.4.31-rc1/drivers/net/bonding/bond_main.c
linux-2.4.31-rc1-patched/drivers/net/bonding/bond_main.c
--- linux-2.4.31-rc1/drivers/net/bonding/bond_main.c 2005-05-26
16:17:31.000000000 +0200
+++ linux-2.4.31-rc1-patched/drivers/net/bonding/bond_main.c
2005-05-26 16:20:34.000000000 +0200
@@ -469,6 +469,7 @@
* * 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.
@@ -476,6 +477,13 @@
* spinlock.
* Set version to 2.6.1.
*
+ * 2005/05/26 - Peter Olsson <peter at visionutv dot se>
+ * - Enhance VLAN support:
+ * * Implement gratuitous ARP patch in 2.4.x kernel (better VLAN
support)
+ * Originally written by Jay Vosburgh <fubar at us dot ibm dot
com>
+ * - Implement patch written by David S. Miller <davem at davemloft
dot net>
+ * * Fix "bonding using arp_ip_target may stay down with active
path"
+ * Set version to 2.6.2.
*/
=20
//#define BONDING_DEBUG 1
@@ -519,6 +527,7 @@
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
+#include <net/route.h>
#include "bonding.h"
#include "bond_3ad.h"
#include "bond_alb.h"
@@ -574,7 +583,6 @@ static struct proc_dir_entry *bond_proc_
=20
static u32 arp_target[BOND_MAX_ARP_TARGETS] =3D { 0, } ;
static int arp_ip_count =3D 0;
-static u32 my_ip =3D 0;
static int bond_mode =3D BOND_MODE_ROUNDROBIN;
static int lacp_fast =3D 0;
static int app_abi_ver =3D 0;
@@ -611,6 +619,7 @@ static struct bond_parm_tbl bond_mode_tb
/*-------------------------- Forward declarations
---------------------------*/
=20
static inline void bond_set_mode_ops(struct net_device *bond_dev, int
mode);
+static void bond_send_gratuitous_arp(struct bonding *bond);
=20
/*---------------------------- General routines
-----------------------------*/
=20
@@ -659,6 +668,7 @@ static int bond_add_vlan(struct bonding=20
=20
INIT_LIST_HEAD(&vlan->vlan_list);
vlan->vlan_id =3D vlan_id;
+ vlan->vlan_ip =3D 0;
=20
write_lock_bh(&bond->lock);
=20
@@ -1477,16 +1487,6 @@ static void bond_change_active_slave(str
}
}
=20
- if (bond->params.mode =3D=3D BOND_MODE_ACTIVEBACKUP) {
- if (old_active) {
- bond_set_slave_inactive_flags(old_active);
- }
-
- if (new_active) {
- bond_set_slave_active_flags(new_active);
- }
- }
-
if (USES_PRIMARY(bond->params.mode)) {
bond_mc_swap(bond, new_active, old_active);
}
@@ -1497,6 +1497,17 @@ static void bond_change_active_slave(str
} else {
bond->curr_active_slave =3D new_active;
}
+
+ if (bond->params.mode =3D=3D BOND_MODE_ACTIVEBACKUP) {
+ if (old_active) {
+ bond_set_slave_inactive_flags(old_active);
+ }
+
+ if (new_active) {
+ bond_set_slave_active_flags(new_active);
+ }
+ bond_send_gratuitous_arp(bond);
+ }
}
=20
/**
@@ -2703,15 +2714,177 @@ out:
read_unlock(&bond->lock);
}
=20
+
+static u32 bond_glean_dev_ip(struct net_device *dev)
+{
+ struct in_device *in_dev;
+ struct in_ifaddr *ifa;
+ u32 addr =3D 0;
+
+ if (!dev)
+ return 0;
+
+ in_dev =3D in_dev_get(dev);
+ if (!in_dev)
+ return 0;
+ =09
+ read_lock(&in_dev->lock);
+ =09
+ ifa =3D in_dev->ifa_list;
+ if (!ifa) {
+ goto out;
+ }
+
+ addr =3D ifa->ifa_local;
+out:
+ read_unlock(&in_dev->lock);
+ in_dev_put(in_dev);
+ return addr;
+}
+
+static int bond_has_ip(struct bonding *bond)
+{
+ struct vlan_entry *vlan, *vlan_next;
+
+ if (bond->master_ip)
+ return 1;
+
+ if (list_empty(&bond->vlan_list))
+ return 0;
+
+ list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+ vlan_list) {
+ if (vlan->vlan_ip)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * We go to the (large) trouble of VLAN tagging ARP frames because
+ * switches in VLAN mode (especially if ports are configured as
+ * "native" to a VLAN) might not pass non-tagged frames.
+ */
+static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32
dest_ip, u32 src_ip, unsigned short vlan_id)
+{
+ struct sk_buff *skb;
+
+ dprintk("arp %d on slave %s: dst %x src %x vid %d\n", arp_op,
+ slave_dev->name, dest_ip, src_ip, vlan_id);
+ =20
+ skb =3D arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
+ NULL, slave_dev->dev_addr, NULL);
+
+ if (!skb) {
+ printk(KERN_ERR DRV_NAME ": ARP packet allocation
failed\n");
+ return;
+ }
+ if (vlan_id) {
+ skb =3D vlan_put_tag(skb, vlan_id);
+ if (!skb) {
+ printk(KERN_ERR DRV_NAME ": failed to insert
VLAN tag\n");
+ return;
+ }
+ }
+ arp_xmit(skb);
+}
+
+
static void bond_arp_send_all(struct bonding *bond, struct slave
*slave)
{
- int i;
+ int i, vlan_id, rv;
u32 *targets =3D bond->params.arp_targets;
+ struct vlan_entry *vlan, *vlan_next;
+ struct net_device *vlan_dev;
+ struct rt_key fl;
+ struct rtable *rt;
=20
for (i =3D 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
- arp_send(ARPOP_REQUEST, ETH_P_ARP, targets[i],
slave->dev,
- my_ip, NULL, slave->dev->dev_addr,
- NULL);
+ dprintk("basa: target %x\n", targets[i]);
+ if (list_empty(&bond->vlan_list)) {
+ dprintk("basa: empty vlan: arp_send\n");
+ bond_arp_send(slave->dev, ARPOP_REQUEST,
targets[i],
+ bond->master_ip, 0);
+ continue;
+ }
+
+ memset(&fl, 0, sizeof(fl));
+ fl.dst =3D targets[i];
+ fl.tos =3D RTO_ONLINK;
+
+ rv =3D ip_route_output_key(&rt, &fl);
+ if (rv) {
+ if (net_ratelimit())
+ printk("basa: no route to %x\n",
fl.dst);
+ continue;
+ }
+
+ /*
+ * We have VLANs configured, but this target is not on
+ * a VLAN
+ */
+ if (rt->u.dst.dev =3D=3D bond->dev) {
+ dprintk("basa: rtdev =3D=3D bond->dev: arp_send\n");
+ bond_arp_send(slave->dev, ARPOP_REQUEST,
targets[i],
+ bond->master_ip, 0);
+ continue;
+ }
+
+ /*
+ * See if this is one of our VLAN devices
+ */
+ vlan_id =3D 0;
+ list_for_each_entry_safe(vlan, vlan_next,
&bond->vlan_list,
+ vlan_list) {
+ vlan_dev =3D
bond->vlgrp->vlan_devices[vlan->vlan_id];
+ if (vlan_dev =3D=3D rt->u.dst.dev) {
+ vlan_id =3D vlan->vlan_id;
+ dprintk("basa: vlan match on %s %d\n",
+ vlan_dev->name, vlan_id);
+ break;
+ }
+ }
+
+ if (vlan_id) {
+ bond_arp_send(slave->dev, ARPOP_REQUEST,
targets[i],
+ vlan->vlan_ip, vlan_id);
+ continue;
+ }
+
+ if (net_ratelimit())
+ printk("basa: no route via bond to ip %x rt.dev
%s\n",
+ targets[i],
+ rt->u.dst.dev ? rt->u.dst.dev->name :
"NULL");
+ }
+}
+
+/*
+ * Kick out a gratuitous ARP for an IP on bond0 plus one for each VLAN
+ * above us.
+ */
+static void bond_send_gratuitous_arp(struct bonding *bond)
+{
+ struct slave *slave =3D bond->curr_active_slave;
+ struct vlan_entry *vlan;
+ struct net_device *vlan_dev;
+
+ dprintk("bond_send_grat_arp: bond %s slave %s\n",
bond->dev->name,
+ slave ? slave->dev->name : "NULL");
+ if (!slave)
+ return;
+
+ if (bond->master_ip) {
+ bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
+ bond->master_ip, 0);
+ }
+
+ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+ vlan_dev =3D bond->vlgrp->vlan_devices[vlan->vlan_id];
+ if (vlan->vlan_ip) {
+ bond_arp_send(slave->dev, ARPOP_REPLY,
vlan->vlan_ip,
+ vlan->vlan_ip, vlan->vlan_id);
+ }
}
}
=20
@@ -2789,8 +2962,8 @@ static void bond_loadbalance_arp_mon(str
* if we don't know our ip yet
*/
if (((jiffies - slave->dev->trans_start) >=3D
(2*delta_in_ticks)) ||
- (((jiffies - slave->dev->last_rx) >=3D
(2*delta_in_ticks)) &&
- my_ip)) {
+ (((jiffies - slave->dev->last_rx) >=3D
(2*delta_in_ticks))=20
+ && bond_has_ip(bond))) {
=20
slave->link =3D BOND_LINK_DOWN;
slave->state =3D BOND_STATE_BACKUP;
@@ -2928,8 +3101,8 @@ static void bond_activebackup_arp_mon(st
=20
if ((slave !=3D bond->curr_active_slave) &&
(!bond->current_arp_slave) &&
- (((jiffies - slave->dev->last_rx) >=3D
3*delta_in_ticks) &&
- my_ip)) {
+ (((jiffies - slave->dev->last_rx) >=3D
3*delta_in_ticks)=20
+ && bond_has_ip(bond))) {
/* a backup slave has gone down; three
times
* the delta allows the current slave to
be
* taken out before the backup slave.
@@ -2975,8 +3148,8 @@ static void bond_activebackup_arp_mon(st
* if it is up and needs to take over as the
curr_active_slave
*/
if ((((jiffies - slave->dev->trans_start) >=3D
(2*delta_in_ticks)) ||
- (((jiffies - slave->dev->last_rx) >=3D
(2*delta_in_ticks)) &&
- my_ip)) &&
+ (((jiffies - slave->dev->last_rx) >=3D (2*delta_in_ticks))
+ && bond_has_ip(bond))) &&
((jiffies - slave->jiffies) >=3D 2*delta_in_ticks)) {
=20
slave->link =3D BOND_LINK_DOWN;
@@ -3028,7 +3201,7 @@ static void bond_activebackup_arp_mon(st
/* the current slave must tx an arp to ensure backup
slaves
* rx traffic
*/
- if (slave && my_ip) {
+ if (slave && bond_has_ip(bond)) {
bond_arp_send_all(bond, slave);
}
}
@@ -3046,7 +3219,7 @@ static void bond_activebackup_arp_mon(st
=20
bond_set_slave_inactive_flags(bond->current_arp_slave);
=20
/* search for next candidate */
- bond_for_each_slave_from(bond, slave, i,
bond->current_arp_slave) {
+ bond_for_each_slave_from(bond, slave, i,
bond->current_arp_slave->next) {
if (IS_UP(slave->dev)) {
slave->link =3D BOND_LINK_BACK;
=20
bond_set_slave_active_flags(slave);
@@ -3478,10 +3651,83 @@ static int bond_netdev_event(struct noti
return NOTIFY_DONE;
}
=20
+/*
+ * bond_inetaddr_event: handle inetaddr notifier chain events.
+ *
+ * We keep track of device IPs primarily to use as source addresses in
+ * ARP monitor probes (rather than spewing out broadcasts all the
time).
+ *
+ * We track one IP for the main device (if it has one), plus one per
VLAN.
+ */
+static int bond_inetaddr_event(struct notifier_block *this, unsigned
long event, void *ptr)
+{
+ struct in_ifaddr *ifa =3D ptr;
+ struct net_device *vlan_dev, *event_dev =3D ifa->ifa_dev->dev;
+ struct bonding *bond, *bond_next;
+ struct vlan_entry *vlan, *vlan_next;
+
+ dprintk("bond_inetaddr_event this %p event %ld ptr %p\n",
+ this, event, ptr);
+ dprintk("event_dev %p %s ifa_local %x\n", event_dev,
+ event_dev ? event_dev->name : "NULL", ifa->ifa_local);
+
+ ASSERT_RTNL();
+
+ list_for_each_entry_safe(bond, bond_next, &bond_dev_list,
bond_list) {
+ dprintk("check bond %p %s\n", bond, bond->dev->name);
+ if (bond->dev =3D=3D event_dev) {
+ switch (event) {
+ case NETDEV_UP:
+ bond->master_ip =3D ifa->ifa_local;
+ dprintk("UP dev %s my_ip %x\n",
+ bond->dev->name,
bond->master_ip);
+ return NOTIFY_OK;
+ case NETDEV_DOWN:
+ bond->master_ip =3D
bond_glean_dev_ip(bond->dev);
+ dprintk("DOWN dev %s my_ip %x\n",
+ bond->dev->name,
bond->master_ip);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+ }
+
+ if (list_empty(&bond->vlan_list))
+ continue;
+
+ list_for_each_entry_safe(vlan, vlan_next,
&bond->vlan_list,
+ vlan_list) {
+ dprintk("check vlan %p ID %d\n", vlan, vlan ?
vlan->vlan_id: 0);
+ vlan_dev =3D
bond->vlgrp->vlan_devices[vlan->vlan_id];
+ dprintk("check vlan id %d dev %p event_dev
%p\n",
+ vlan->vlan_id, vlan_dev, event_dev);
+ if (vlan_dev =3D=3D event_dev) {
+ switch (event) {
+ case NETDEV_UP:
+ vlan->vlan_ip =3D ifa->ifa_local;
+ dprintk("UP vlan_ip %x\n",
vlan->vlan_ip);
+ return NOTIFY_OK;
+ case NETDEV_DOWN:
+ vlan->vlan_ip =3D
bond_glean_dev_ip(vlan_dev);
+ dprintk("DOWN vlan_ip %x\n",
vlan->vlan_ip);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+ }
+ }
+ }
+ return NOTIFY_DONE;
+}
+
static struct notifier_block bond_netdev_notifier =3D {
.notifier_call =3D bond_netdev_event,
};
=20
+static struct notifier_block bond_inetaddr_notifier =3D {
+ .notifier_call =3D bond_inetaddr_event,
+};
+
/*-------------------------- Packet type handling
---------------------------*/
=20
/* register to receive lacpdus on a bond */
@@ -4075,17 +4321,6 @@ static int bond_xmit_activebackup(struct
struct bonding *bond =3D bond_dev->priv;
int res =3D 1;
=20
- /* if we are sending arp packets, try to at least
- identify our own ip address */
- if (bond->params.arp_interval && !my_ip &&
- (skb->protocol =3D=3D __constant_htons(ETH_P_ARP))) {
- char *the_ip =3D (char *)skb->data +
- sizeof(struct ethhdr) +
- sizeof(struct arphdr) +
- ETH_ALEN;
- memcpy(&my_ip, the_ip, 4);
- }
-
read_lock(&bond->lock);
read_lock(&bond->curr_slave_lock);
=20
@@ -4690,6 +4925,7 @@ static int __init bonding_init(void)
=20
rtnl_unlock();
register_netdevice_notifier(&bond_netdev_notifier);
+ register_inetaddr_notifier(&bond_inetaddr_notifier);
=20
return 0;
=20
@@ -4705,6 +4941,7 @@ out_err:
static void __exit bonding_exit(void)
{
unregister_netdevice_notifier(&bond_netdev_notifier);
+ unregister_inetaddr_notifier(&bond_inetaddr_notifier);
=20
rtnl_lock();
bond_free_all();
diff -Naur -p linux-2.4.31-rc1/drivers/net/bonding/bonding.h
linux-2.4.31-rc1-patched/drivers/net/bonding/bonding.h
--- linux-2.4.31-rc1/drivers/net/bonding/bonding.h 2004-04-14
15:05:30.000000000 +0200
+++ linux-2.4.31-rc1-patched/drivers/net/bonding/bonding.h
2005-05-26 16:15:23.000000000 +0200
@@ -36,8 +36,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
=20
-#define DRV_VERSION "2.6.0"
-#define DRV_RELDATE "January 14, 2004"
+#define DRV_VERSION "2.6.2"
+#define DRV_RELDATE "May 16, 2005"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
=20
@@ -149,6 +149,7 @@ struct bond_params {
=20
struct vlan_entry {
struct list_head vlan_list;
+ u32 vlan_ip;
unsigned short vlan_id;
};
=20
@@ -197,6 +198,7 @@ struct bonding {
#endif /* CONFIG_PROC_FS */
struct list_head bond_list;
struct dev_mc_list *mc_list;
+ u32 master_ip;
u16 flags;
struct ad_bond_info ad_info;
struct alb_bond_info alb_info;
Best regards,
Peter Olsson
Visionutveckling AB
|