[PATCH] bonding: suppress duplicate packets
Originally submitted by Kenzo Iwami; his original description is: The current bonding driver receives duplicate packets when broadcast/ multicast packets are sent by other devices or packets are flooded by the switch. In this patch, new flags are added in priv_flags of net_device structure to let the bonding driver discard duplicate packets in dev.c:skb_bond(). Modified by Jay Vosburgh to change a define name, update some comments, rearrange the new skb_bond() for clarity, clear all bonding priv_flags on slave release, and update the driver version. Signed-off-by: Kenzo Iwami <k-iwami@cj.jp.nec.com> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
ebe19a4ed7
commit
8f903c708f
6 changed files with 85 additions and 27 deletions
|
@ -1040,6 +1040,10 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
|
||||||
if ((bond->params.mode == BOND_MODE_TLB) ||
|
if ((bond->params.mode == BOND_MODE_TLB) ||
|
||||||
(bond->params.mode == BOND_MODE_ALB)) {
|
(bond->params.mode == BOND_MODE_ALB)) {
|
||||||
bond_alb_handle_active_change(bond, new_active);
|
bond_alb_handle_active_change(bond, new_active);
|
||||||
|
if (old_active)
|
||||||
|
bond_set_slave_inactive_flags(old_active);
|
||||||
|
if (new_active)
|
||||||
|
bond_set_slave_active_flags(new_active);
|
||||||
} else {
|
} else {
|
||||||
bond->curr_active_slave = new_active;
|
bond->curr_active_slave = new_active;
|
||||||
}
|
}
|
||||||
|
@ -1443,15 +1447,16 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||||
|
|
||||||
switch (bond->params.mode) {
|
switch (bond->params.mode) {
|
||||||
case BOND_MODE_ACTIVEBACKUP:
|
case BOND_MODE_ACTIVEBACKUP:
|
||||||
/* if we're in active-backup mode, we need one and only one active
|
/* if we're in active-backup mode, we need one and
|
||||||
* interface. The backup interfaces will have their NOARP flag set
|
* only one active interface. The backup interfaces
|
||||||
* because we need them to be completely deaf and not to respond to
|
* will have their SLAVE_INACTIVE flag set because we
|
||||||
* any ARP request on the network to avoid fooling a switch. Thus,
|
* need them to be drop all packets. Thus, since we
|
||||||
* since we guarantee that curr_active_slave always point to the last
|
* guarantee that curr_active_slave always point to
|
||||||
* usable interface, we just have to verify this interface's flag.
|
* the last usable interface, we just have to verify
|
||||||
|
* this interface's flag.
|
||||||
*/
|
*/
|
||||||
if (((!bond->curr_active_slave) ||
|
if (((!bond->curr_active_slave) ||
|
||||||
(bond->curr_active_slave->dev->flags & IFF_NOARP)) &&
|
(bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
|
||||||
(new_slave->link != BOND_LINK_DOWN)) {
|
(new_slave->link != BOND_LINK_DOWN)) {
|
||||||
dprintk("This is the first active slave\n");
|
dprintk("This is the first active slave\n");
|
||||||
/* first slave or no active slave yet, and this link
|
/* first slave or no active slave yet, and this link
|
||||||
|
@ -1492,6 +1497,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||||
* is OK, so make this interface the active one
|
* is OK, so make this interface the active one
|
||||||
*/
|
*/
|
||||||
bond_change_active_slave(bond, new_slave);
|
bond_change_active_slave(bond, new_slave);
|
||||||
|
} else {
|
||||||
|
bond_set_slave_inactive_flags(new_slave);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1724,13 +1731,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||||
addr.sa_family = slave_dev->type;
|
addr.sa_family = slave_dev->type;
|
||||||
dev_set_mac_address(slave_dev, &addr);
|
dev_set_mac_address(slave_dev, &addr);
|
||||||
|
|
||||||
/* restore the original state of the
|
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
|
||||||
* IFF_NOARP flag that might have been
|
IFF_SLAVE_INACTIVE);
|
||||||
* set by bond_set_slave_inactive_flags()
|
|
||||||
*/
|
|
||||||
if ((slave->original_flags & IFF_NOARP) == 0) {
|
|
||||||
slave_dev->flags &= ~IFF_NOARP;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(slave);
|
kfree(slave);
|
||||||
|
|
||||||
|
@ -1816,12 +1818,8 @@ static int bond_release_all(struct net_device *bond_dev)
|
||||||
addr.sa_family = slave_dev->type;
|
addr.sa_family = slave_dev->type;
|
||||||
dev_set_mac_address(slave_dev, &addr);
|
dev_set_mac_address(slave_dev, &addr);
|
||||||
|
|
||||||
/* restore the original state of the IFF_NOARP flag that might have
|
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
|
||||||
* been set by bond_set_slave_inactive_flags()
|
IFF_SLAVE_INACTIVE);
|
||||||
*/
|
|
||||||
if ((slave->original_flags & IFF_NOARP) == 0) {
|
|
||||||
slave_dev->flags &= ~IFF_NOARP;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(slave);
|
kfree(slave);
|
||||||
|
|
||||||
|
@ -4061,14 +4059,17 @@ void bond_set_mode_ops(struct bonding *bond, int mode)
|
||||||
bond_dev->hard_start_xmit = bond_xmit_broadcast;
|
bond_dev->hard_start_xmit = bond_xmit_broadcast;
|
||||||
break;
|
break;
|
||||||
case BOND_MODE_8023AD:
|
case BOND_MODE_8023AD:
|
||||||
|
bond_set_master_3ad_flags(bond);
|
||||||
bond_dev->hard_start_xmit = bond_3ad_xmit_xor;
|
bond_dev->hard_start_xmit = bond_3ad_xmit_xor;
|
||||||
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
|
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
|
||||||
bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
|
bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
|
||||||
else
|
else
|
||||||
bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
|
bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
|
||||||
break;
|
break;
|
||||||
case BOND_MODE_TLB:
|
|
||||||
case BOND_MODE_ALB:
|
case BOND_MODE_ALB:
|
||||||
|
bond_set_master_alb_flags(bond);
|
||||||
|
/* FALLTHRU */
|
||||||
|
case BOND_MODE_TLB:
|
||||||
bond_dev->hard_start_xmit = bond_alb_xmit;
|
bond_dev->hard_start_xmit = bond_alb_xmit;
|
||||||
bond_dev->set_mac_address = bond_alb_set_mac_address;
|
bond_dev->set_mac_address = bond_alb_set_mac_address;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -424,6 +424,12 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
|
if (bond->params.mode == BOND_MODE_8023AD)
|
||||||
|
bond_unset_master_3ad_flags(bond);
|
||||||
|
|
||||||
|
if (bond->params.mode == BOND_MODE_ALB)
|
||||||
|
bond_unset_master_alb_flags(bond);
|
||||||
|
|
||||||
bond->params.mode = new_value;
|
bond->params.mode = new_value;
|
||||||
bond_set_mode_ops(bond, bond->params.mode);
|
bond_set_mode_ops(bond, bond->params.mode);
|
||||||
printk(KERN_INFO DRV_NAME ": %s: setting mode to %s (%d).\n",
|
printk(KERN_INFO DRV_NAME ": %s: setting mode to %s (%d).\n",
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include "bond_3ad.h"
|
#include "bond_3ad.h"
|
||||||
#include "bond_alb.h"
|
#include "bond_alb.h"
|
||||||
|
|
||||||
#define DRV_VERSION "3.0.1"
|
#define DRV_VERSION "3.0.2"
|
||||||
#define DRV_RELDATE "January 9, 2006"
|
#define DRV_RELDATE "February 21, 2006"
|
||||||
#define DRV_NAME "bonding"
|
#define DRV_NAME "bonding"
|
||||||
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
|
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
|
||||||
|
|
||||||
|
@ -230,14 +230,37 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
|
||||||
|
|
||||||
static inline void bond_set_slave_inactive_flags(struct slave *slave)
|
static inline void bond_set_slave_inactive_flags(struct slave *slave)
|
||||||
{
|
{
|
||||||
slave->state = BOND_STATE_BACKUP;
|
struct bonding *bond = slave->dev->master->priv;
|
||||||
slave->dev->flags |= IFF_NOARP;
|
if (bond->params.mode != BOND_MODE_TLB &&
|
||||||
|
bond->params.mode != BOND_MODE_ALB)
|
||||||
|
slave->state = BOND_STATE_BACKUP;
|
||||||
|
slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void bond_set_slave_active_flags(struct slave *slave)
|
static inline void bond_set_slave_active_flags(struct slave *slave)
|
||||||
{
|
{
|
||||||
slave->state = BOND_STATE_ACTIVE;
|
slave->state = BOND_STATE_ACTIVE;
|
||||||
slave->dev->flags &= ~IFF_NOARP;
|
slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bond_set_master_3ad_flags(struct bonding *bond)
|
||||||
|
{
|
||||||
|
bond->dev->priv_flags |= IFF_MASTER_8023AD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bond_unset_master_3ad_flags(struct bonding *bond)
|
||||||
|
{
|
||||||
|
bond->dev->priv_flags &= ~IFF_MASTER_8023AD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bond_set_master_alb_flags(struct bonding *bond)
|
||||||
|
{
|
||||||
|
bond->dev->priv_flags |= IFF_MASTER_ALB;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bond_unset_master_alb_flags(struct bonding *bond)
|
||||||
|
{
|
||||||
|
bond->dev->priv_flags &= ~IFF_MASTER_ALB;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
|
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
|
||||||
|
|
|
@ -52,6 +52,9 @@
|
||||||
/* Private (from user) interface flags (netdevice->priv_flags). */
|
/* Private (from user) interface flags (netdevice->priv_flags). */
|
||||||
#define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */
|
#define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */
|
||||||
#define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */
|
#define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */
|
||||||
|
#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */
|
||||||
|
#define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */
|
||||||
|
#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
|
||||||
|
|
||||||
#define IF_GET_IFACE 0x0001 /* for querying only */
|
#define IF_GET_IFACE 0x0001 /* for querying only */
|
||||||
#define IF_GET_PROTO 0x0002
|
#define IF_GET_PROTO 0x0002
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
|
#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
|
||||||
#define ETH_P_IPX 0x8137 /* IPX over DIX */
|
#define ETH_P_IPX 0x8137 /* IPX over DIX */
|
||||||
#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
|
#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
|
||||||
|
#define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */
|
||||||
#define ETH_P_WCCP 0x883E /* Web-cache coordination protocol
|
#define ETH_P_WCCP 0x883E /* Web-cache coordination protocol
|
||||||
* defined in draft-wilson-wrec-wccp-v2-00.txt */
|
* defined in draft-wilson-wrec-wccp-v2-00.txt */
|
||||||
#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
|
#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
|
||||||
|
|
|
@ -1446,8 +1446,29 @@ static inline struct net_device *skb_bond(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct net_device *dev = skb->dev;
|
struct net_device *dev = skb->dev;
|
||||||
|
|
||||||
if (dev->master)
|
if (dev->master) {
|
||||||
|
/*
|
||||||
|
* On bonding slaves other than the currently active
|
||||||
|
* slave, suppress duplicates except for 802.3ad
|
||||||
|
* ETH_P_SLOW and alb non-mcast/bcast.
|
||||||
|
*/
|
||||||
|
if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
|
||||||
|
if (dev->master->priv_flags & IFF_MASTER_ALB) {
|
||||||
|
if (skb->pkt_type != PACKET_BROADCAST &&
|
||||||
|
skb->pkt_type != PACKET_MULTICAST)
|
||||||
|
goto keep;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->master->priv_flags & IFF_MASTER_8023AD &&
|
||||||
|
skb->protocol == __constant_htons(ETH_P_SLOW))
|
||||||
|
goto keep;
|
||||||
|
|
||||||
|
kfree_skb(skb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
keep:
|
||||||
skb->dev = dev->master;
|
skb->dev = dev->master;
|
||||||
|
}
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
@ -1591,6 +1612,9 @@ int netif_receive_skb(struct sk_buff *skb)
|
||||||
|
|
||||||
orig_dev = skb_bond(skb);
|
orig_dev = skb_bond(skb);
|
||||||
|
|
||||||
|
if (!orig_dev)
|
||||||
|
return NET_RX_DROP;
|
||||||
|
|
||||||
__get_cpu_var(netdev_rx_stat).total++;
|
__get_cpu_var(netdev_rx_stat).total++;
|
||||||
|
|
||||||
skb->h.raw = skb->nh.raw = skb->data;
|
skb->h.raw = skb->nh.raw = skb->data;
|
||||||
|
|
Loading…
Reference in a new issue