aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFlavio Leitner <fleitner@redhat.com>2010-10-05 10:23:57 -0400
committerDavid S. Miller <davem@davemloft.net>2010-10-05 23:26:56 -0400
commit5a37e8ca8536c47871d46c82211f399adf06fd44 (patch)
treea691902b909171122ebaa51412165051c54a2a85 /drivers
parenta8bb69f78194dc483f6c4a4bf8860c1ede35fa25 (diff)
bonding: rejoin multicast groups on VLANs
During a failover, the IGMP membership is sent to update the switch restoring the traffic, but it misses groups added to VLAN devices running on top of bonding devices. This patch changes it to iterate over all VLAN devices on top of it sending IGMP memberships too. Signed-off-by: Flavio Leitner <fleitner@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/bonding/bond_main.c60
-rw-r--r--drivers/net/bonding/bonding.h1
2 files changed, 50 insertions, 11 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index fb70c3e12927..ad6386671f28 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -865,18 +865,13 @@ static void bond_mc_del(struct bonding *bond, void *addr)
865} 865}
866 866
867 867
868/* 868static void __bond_resend_igmp_join_requests(struct net_device *dev)
869 * Retrieve the list of registered multicast addresses for the bonding
870 * device and retransmit an IGMP JOIN request to the current active
871 * slave.
872 */
873static void bond_resend_igmp_join_requests(struct bonding *bond)
874{ 869{
875 struct in_device *in_dev; 870 struct in_device *in_dev;
876 struct ip_mc_list *im; 871 struct ip_mc_list *im;
877 872
878 rcu_read_lock(); 873 rcu_read_lock();
879 in_dev = __in_dev_get_rcu(bond->dev); 874 in_dev = __in_dev_get_rcu(dev);
880 if (in_dev) { 875 if (in_dev) {
881 for (im = in_dev->mc_list; im; im = im->next) 876 for (im = in_dev->mc_list; im; im = im->next)
882 ip_mc_rejoin_group(im); 877 ip_mc_rejoin_group(im);
@@ -886,6 +881,41 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
886} 881}
887 882
888/* 883/*
884 * Retrieve the list of registered multicast addresses for the bonding
885 * device and retransmit an IGMP JOIN request to the current active
886 * slave.
887 */
888static void bond_resend_igmp_join_requests(struct bonding *bond)
889{
890 struct net_device *vlan_dev;
891 struct vlan_entry *vlan;
892
893 read_lock(&bond->lock);
894
895 /* rejoin all groups on bond device */
896 __bond_resend_igmp_join_requests(bond->dev);
897
898 /* rejoin all groups on vlan devices */
899 if (bond->vlgrp) {
900 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
901 vlan_dev = vlan_group_get_device(bond->vlgrp,
902 vlan->vlan_id);
903 if (vlan_dev)
904 __bond_resend_igmp_join_requests(vlan_dev);
905 }
906 }
907
908 read_unlock(&bond->lock);
909}
910
911void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
912{
913 struct bonding *bond = container_of(work, struct bonding,
914 mcast_work.work);
915 bond_resend_igmp_join_requests(bond);
916}
917
918/*
889 * flush all members of flush->mc_list from device dev->mc_list 919 * flush all members of flush->mc_list from device dev->mc_list
890 */ 920 */
891static void bond_mc_list_flush(struct net_device *bond_dev, 921static void bond_mc_list_flush(struct net_device *bond_dev,
@@ -944,7 +974,6 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
944 974
945 netdev_for_each_mc_addr(ha, bond->dev) 975 netdev_for_each_mc_addr(ha, bond->dev)
946 dev_mc_add(new_active->dev, ha->addr); 976 dev_mc_add(new_active->dev, ha->addr);
947 bond_resend_igmp_join_requests(bond);
948 } 977 }
949} 978}
950 979
@@ -1180,9 +1209,11 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
1180 } 1209 }
1181 } 1210 }
1182 1211
1183 /* resend IGMP joins since all were sent on curr_active_slave */ 1212 /* resend IGMP joins since active slave has changed or
1184 if (bond->params.mode == BOND_MODE_ROUNDROBIN) { 1213 * all were sent on curr_active_slave */
1185 bond_resend_igmp_join_requests(bond); 1214 if ((USES_PRIMARY(bond->params.mode) && new_active) ||
1215 bond->params.mode == BOND_MODE_ROUNDROBIN) {
1216 queue_delayed_work(bond->wq, &bond->mcast_work, 0);
1186 } 1217 }
1187} 1218}
1188 1219
@@ -3744,6 +3775,8 @@ static int bond_open(struct net_device *bond_dev)
3744 3775
3745 bond->kill_timers = 0; 3776 bond->kill_timers = 0;
3746 3777
3778 INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed);
3779
3747 if (bond_is_lb(bond)) { 3780 if (bond_is_lb(bond)) {
3748 /* bond_alb_initialize must be called before the timer 3781 /* bond_alb_initialize must be called before the timer
3749 * is started. 3782 * is started.
@@ -3828,6 +3861,8 @@ static int bond_close(struct net_device *bond_dev)
3828 break; 3861 break;
3829 } 3862 }
3830 3863
3864 if (delayed_work_pending(&bond->mcast_work))
3865 cancel_delayed_work(&bond->mcast_work);
3831 3866
3832 if (bond_is_lb(bond)) { 3867 if (bond_is_lb(bond)) {
3833 /* Must be called only after all 3868 /* Must be called only after all
@@ -4703,6 +4738,9 @@ static void bond_work_cancel_all(struct bonding *bond)
4703 if (bond->params.mode == BOND_MODE_8023AD && 4738 if (bond->params.mode == BOND_MODE_8023AD &&
4704 delayed_work_pending(&bond->ad_work)) 4739 delayed_work_pending(&bond->ad_work))
4705 cancel_delayed_work(&bond->ad_work); 4740 cancel_delayed_work(&bond->ad_work);
4741
4742 if (delayed_work_pending(&bond->mcast_work))
4743 cancel_delayed_work(&bond->mcast_work);
4706} 4744}
4707 4745
4708/* 4746/*
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index c6fdd851579a..308ed10dca90 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -223,6 +223,7 @@ struct bonding {
223 struct delayed_work arp_work; 223 struct delayed_work arp_work;
224 struct delayed_work alb_work; 224 struct delayed_work alb_work;
225 struct delayed_work ad_work; 225 struct delayed_work ad_work;
226 struct delayed_work mcast_work;
226#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 227#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
227 struct in6_addr master_ipv6; 228 struct in6_addr master_ipv6;
228#endif 229#endif