]> err.no Git - linux-2.6/commitdiff
[PATCH] bonding: replicate IGMP traffic in activebackup mode
authorJohn W. Linville <linville@tuxdriver.com>
Wed, 28 Sep 2005 21:50:53 +0000 (17:50 -0400)
committerJeff Garzik <jgarzik@pobox.com>
Tue, 4 Oct 2005 11:57:38 +0000 (07:57 -0400)
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>
drivers/net/bonding/bond_main.c

index fd62e43a3510b732cd6399f1d30cda63bccc04cf..2c9e63a14596630d6054a2154bd2a5639e3ef72d 100644 (file)
@@ -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 */