[PATCH] bonding: replicate IGMP traffic in activebackup mode
Replicate IGMP frames across all slaves in activebackup mode. This ensures fail-over is rapid for multicast traffic as well. Otherwise, multicast traffic will be lost until the next IGMP membership report poll timeout. This is conceptually similar to the treatment of IGMP traffic in bond_alb_xmit. In that case, IGMP traffic transmitted on any slave is re-routed to the active slave in order to ensure that multicast traffic continues to be directed to the active receiver. Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
6c1792f4e8
commit
075897ce3b
|
@ -4240,6 +4240,39 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bond_activebackup_xmit_copy(struct sk_buff *skb,
|
||||
struct bonding *bond,
|
||||
struct slave *slave)
|
||||
{
|
||||
struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
|
||||
struct ethhdr *eth_data;
|
||||
u8 *hwaddr;
|
||||
int res;
|
||||
|
||||
if (!skb2) {
|
||||
printk(KERN_ERR DRV_NAME ": Error: "
|
||||
"bond_activebackup_xmit_copy(): skb_copy() failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
skb2->mac.raw = (unsigned char *)skb2->data;
|
||||
eth_data = eth_hdr(skb2);
|
||||
|
||||
/* Pick an appropriate source MAC address */
|
||||
hwaddr = slave->perm_hwaddr;
|
||||
if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN))
|
||||
hwaddr = bond->curr_active_slave->perm_hwaddr;
|
||||
|
||||
/* Set source MAC address appropriately */
|
||||
memcpy(eth_data->h_source, hwaddr, ETH_ALEN);
|
||||
|
||||
res = bond_dev_queue_xmit(bond, skb2, slave->dev);
|
||||
if (res)
|
||||
dev_kfree_skb(skb2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* in active-backup mode, we know that bond->curr_active_slave is always valid if
|
||||
* the bond has a usable interface.
|
||||
|
@ -4256,10 +4289,26 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (bond->curr_active_slave) { /* one usable interface */
|
||||
res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
|
||||
if (!bond->curr_active_slave)
|
||||
goto out;
|
||||
|
||||
/* Xmit IGMP frames on all slaves to ensure rapid fail-over
|
||||
for multicast traffic on snooping switches */
|
||||
if (skb->protocol == __constant_htons(ETH_P_IP) &&
|
||||
skb->nh.iph->protocol == IPPROTO_IGMP) {
|
||||
struct slave *slave, *active_slave;
|
||||
int i;
|
||||
|
||||
active_slave = bond->curr_active_slave;
|
||||
bond_for_each_slave_from_to(bond, slave, i, active_slave->next,
|
||||
active_slave->prev)
|
||||
if (IS_UP(slave->dev) &&
|
||||
(slave->link == BOND_LINK_UP))
|
||||
bond_activebackup_xmit_copy(skb, bond, slave);
|
||||
}
|
||||
|
||||
res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
|
||||
|
||||
out:
|
||||
if (res) {
|
||||
/* no suitable interface, frame not sent */
|
||||
|
|
Loading…
Reference in New Issue