Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Flavio Leitner and committed by
David S. Miller
5a37e8ca a8bb69f7

+51 -12
+50 -12
drivers/net/bonding/bond_main.c
··· 865 865 } 866 866 867 867 868 + static void __bond_resend_igmp_join_requests(struct net_device *dev) 869 + { 870 + struct in_device *in_dev; 871 + struct ip_mc_list *im; 872 + 873 + rcu_read_lock(); 874 + in_dev = __in_dev_get_rcu(dev); 875 + if (in_dev) { 876 + for (im = in_dev->mc_list; im; im = im->next) 877 + ip_mc_rejoin_group(im); 878 + } 879 + 880 + rcu_read_unlock(); 881 + } 882 + 868 883 /* 869 884 * Retrieve the list of registered multicast addresses for the bonding 870 885 * device and retransmit an IGMP JOIN request to the current active ··· 887 872 */ 888 873 static void bond_resend_igmp_join_requests(struct bonding *bond) 889 874 { 890 - struct in_device *in_dev; 891 - struct ip_mc_list *im; 875 + struct net_device *vlan_dev; 876 + struct vlan_entry *vlan; 892 877 893 - rcu_read_lock(); 894 - in_dev = __in_dev_get_rcu(bond->dev); 895 - if (in_dev) { 896 - for (im = in_dev->mc_list; im; im = im->next) 897 - ip_mc_rejoin_group(im); 878 + read_lock(&bond->lock); 879 + 880 + /* rejoin all groups on bond device */ 881 + __bond_resend_igmp_join_requests(bond->dev); 882 + 883 + /* rejoin all groups on vlan devices */ 884 + if (bond->vlgrp) { 885 + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 886 + vlan_dev = vlan_group_get_device(bond->vlgrp, 887 + vlan->vlan_id); 888 + if (vlan_dev) 889 + __bond_resend_igmp_join_requests(vlan_dev); 890 + } 898 891 } 899 892 900 - rcu_read_unlock(); 893 + read_unlock(&bond->lock); 894 + } 895 + 896 + void bond_resend_igmp_join_requests_delayed(struct work_struct *work) 897 + { 898 + struct bonding *bond = container_of(work, struct bonding, 899 + mcast_work.work); 900 + bond_resend_igmp_join_requests(bond); 901 901 } 902 902 903 903 /* ··· 974 944 975 945 netdev_for_each_mc_addr(ha, bond->dev) 976 946 dev_mc_add(new_active->dev, ha->addr); 977 - bond_resend_igmp_join_requests(bond); 978 947 } 979 948 } 980 949 ··· 1209 1180 } 1210 1181 } 1211 1182 1212 - /* resend IGMP joins since all were sent on curr_active_slave */ 1213 - if (bond->params.mode == BOND_MODE_ROUNDROBIN) { 1214 - bond_resend_igmp_join_requests(bond); 1183 + /* resend IGMP joins since active slave has changed or 1184 + * all were sent on curr_active_slave */ 1185 + if ((USES_PRIMARY(bond->params.mode) && new_active) || 1186 + bond->params.mode == BOND_MODE_ROUNDROBIN) { 1187 + queue_delayed_work(bond->wq, &bond->mcast_work, 0); 1215 1188 } 1216 1189 } 1217 1190 ··· 3775 3744 3776 3745 bond->kill_timers = 0; 3777 3746 3747 + INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed); 3748 + 3778 3749 if (bond_is_lb(bond)) { 3779 3750 /* bond_alb_initialize must be called before the timer 3780 3751 * is started. ··· 3861 3828 break; 3862 3829 } 3863 3830 3831 + if (delayed_work_pending(&bond->mcast_work)) 3832 + cancel_delayed_work(&bond->mcast_work); 3864 3833 3865 3834 if (bond_is_lb(bond)) { 3866 3835 /* Must be called only after all ··· 4738 4703 if (bond->params.mode == BOND_MODE_8023AD && 4739 4704 delayed_work_pending(&bond->ad_work)) 4740 4705 cancel_delayed_work(&bond->ad_work); 4706 + 4707 + if (delayed_work_pending(&bond->mcast_work)) 4708 + cancel_delayed_work(&bond->mcast_work); 4741 4709 } 4742 4710 4743 4711 /*
+1
drivers/net/bonding/bonding.h
··· 223 223 struct delayed_work arp_work; 224 224 struct delayed_work alb_work; 225 225 struct delayed_work ad_work; 226 + struct delayed_work mcast_work; 226 227 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 227 228 struct in6_addr master_ipv6; 228 229 #endif