#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
+#include <linux/igmp.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
}
}
+
+/*
+ * Retrieve the list of registered multicast addresses for the bonding
+ * device and retransmit an IGMP JOIN request to the current active
+ * slave.
+ */
+static void bond_resend_igmp_join_requests(struct bonding *bond)
+{
+ struct in_device *in_dev;
+ struct ip_mc_list *im;
+
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(bond->dev);
+ if (in_dev) {
+ for (im = in_dev->mc_list; im; im = im->next) {
+ ip_mc_rejoin_group(im);
+ }
+ }
+
+ rcu_read_unlock();
+}
+
/*
* Totally destroys the mc_list in bond
*/
kfree(dmi);
dmi = bond->mc_list;
}
+ bond->mc_list = NULL;
}
/*
for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) {
dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
}
+ bond_resend_igmp_join_requests(bond);
}
}
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
- * -- use slave's perm MAC addr, unless used by bond
- * -- otherwise, borrow active slave's perm MAC addr
- * since that will not be used
- */
- 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
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:
return;
}
+/*
+ * Resend IGMP JOIN report; used for bonding.
+ */
+void ip_mc_rejoin_group(struct ip_mc_list *im)
+{
+ struct in_device *in_dev = im->interface;
+
+#ifdef CONFIG_IP_MULTICAST
+ if (im->multiaddr == IGMP_ALL_HOSTS)
+ return;
+
+ if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
+ igmp_mod_timer(im, IGMP_Initial_Report_Delay);
+ return;
+ }
+ /* else, v3 */
+ im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
+ IGMP_Unsolicited_Report_Count;
+ igmp_ifc_event(in_dev);
+#endif
+}
+
/*
* A socket has left a multicast group on device dev
*/
EXPORT_SYMBOL(ip_mc_dec_group);
EXPORT_SYMBOL(ip_mc_inc_group);
EXPORT_SYMBOL(ip_mc_join_group);
+EXPORT_SYMBOL(ip_mc_rejoin_group);