aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-07-20 06:13:53 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-23 19:52:47 -0400
commit4aa5dee4d9997879adff858514844efab5a15a01 (patch)
treef3f3bf83f34dd832c8e163095c03e6aff29f20df
parentfc423ff00df3a19554414eed80aef9de9b50313e (diff)
net: convert resend IGMP to notifier event
Until now, bond_resend_igmp_join_requests() looks for vlans attached to bonding device, bridge where bonding act as port manually. It does not care of other scenarios, like stacked bonds or team device above. Make this more generic and use netdev notifier to propagate the event to upper devices and to actually call ip_mc_rejoin_groups(). Signed-off-by: Jiri Pirko <jiri@resnulli.us> Acked-by: Veaceslav Falico <vfalico@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c44
-rw-r--r--drivers/net/team/team.c4
-rw-r--r--include/linux/igmp.h1
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--net/8021q/vlan.c1
-rw-r--r--net/bridge/br_notify.c5
-rw-r--r--net/ipv4/igmp.c46
7 files changed, 60 insertions, 42 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 07f257d44a1e..ae9864c9fa38 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -715,15 +715,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
715 return err; 715 return err;
716} 716}
717 717
718static void __bond_resend_igmp_join_requests(struct net_device *dev)
719{
720 struct in_device *in_dev;
721
722 in_dev = __in_dev_get_rcu(dev);
723 if (in_dev)
724 ip_mc_rejoin_groups(in_dev);
725}
726
727/* 718/*
728 * Retrieve the list of registered multicast addresses for the bonding 719 * Retrieve the list of registered multicast addresses for the bonding
729 * device and retransmit an IGMP JOIN request to the current active 720 * device and retransmit an IGMP JOIN request to the current active
@@ -731,33 +722,12 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
731 */ 722 */
732static void bond_resend_igmp_join_requests(struct bonding *bond) 723static void bond_resend_igmp_join_requests(struct bonding *bond)
733{ 724{
734 struct net_device *bond_dev, *vlan_dev, *upper_dev; 725 if (!rtnl_trylock()) {
735 struct vlan_entry *vlan; 726 queue_delayed_work(bond->wq, &bond->mcast_work, 0);
736 727 return;
737 read_lock(&bond->lock);
738 rcu_read_lock();
739
740 bond_dev = bond->dev;
741
742 /* rejoin all groups on bond device */
743 __bond_resend_igmp_join_requests(bond_dev);
744
745 /*
746 * if bond is enslaved to a bridge,
747 * then rejoin all groups on its master
748 */
749 upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
750 if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
751 __bond_resend_igmp_join_requests(upper_dev);
752
753 /* rejoin all groups on vlan devices */
754 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
755 vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
756 vlan->vlan_id);
757 if (vlan_dev)
758 __bond_resend_igmp_join_requests(vlan_dev);
759 } 728 }
760 rcu_read_unlock(); 729 call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev);
730 rtnl_unlock();
761 731
762 /* We use curr_slave_lock to protect against concurrent access to 732 /* We use curr_slave_lock to protect against concurrent access to
763 * igmp_retrans from multiple running instances of this function and 733 * igmp_retrans from multiple running instances of this function and
@@ -3234,6 +3204,10 @@ static int bond_slave_netdev_event(unsigned long event,
3234 case NETDEV_FEAT_CHANGE: 3204 case NETDEV_FEAT_CHANGE:
3235 bond_compute_features(bond); 3205 bond_compute_features(bond);
3236 break; 3206 break;
3207 case NETDEV_RESEND_IGMP:
3208 /* Propagate to master device */
3209 call_netdevice_notifiers(event, slave->bond->dev);
3210 break;
3237 default: 3211 default:
3238 break; 3212 break;
3239 } 3213 }
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 0433ee994f8c..2587dc86d533 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2785,6 +2785,10 @@ static int team_device_event(struct notifier_block *unused,
2785 case NETDEV_PRE_TYPE_CHANGE: 2785 case NETDEV_PRE_TYPE_CHANGE:
2786 /* Forbid to change type of underlaying device */ 2786 /* Forbid to change type of underlaying device */
2787 return NOTIFY_BAD; 2787 return NOTIFY_BAD;
2788 case NETDEV_RESEND_IGMP:
2789 /* Propagate to master device */
2790 call_netdevice_notifiers(event, port->team->dev);
2791 break;
2788 } 2792 }
2789 return NOTIFY_DONE; 2793 return NOTIFY_DONE;
2790} 2794}
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index e3362b5f13e8..f47550d75f85 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -129,6 +129,5 @@ extern void ip_mc_unmap(struct in_device *);
129extern void ip_mc_remap(struct in_device *); 129extern void ip_mc_remap(struct in_device *);
130extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr); 130extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
131extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr); 131extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
132extern void ip_mc_rejoin_groups(struct in_device *in_dev);
133 132
134#endif 133#endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0741a1e919a5..2bb2357d83bb 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1633,6 +1633,7 @@ struct packet_offload {
1633#define NETDEV_NOTIFY_PEERS 0x0013 1633#define NETDEV_NOTIFY_PEERS 0x0013
1634#define NETDEV_JOIN 0x0014 1634#define NETDEV_JOIN 0x0014
1635#define NETDEV_CHANGEUPPER 0x0015 1635#define NETDEV_CHANGEUPPER 0x0015
1636#define NETDEV_RESEND_IGMP 0x0016
1636 1637
1637extern int register_netdevice_notifier(struct notifier_block *nb); 1638extern int register_netdevice_notifier(struct notifier_block *nb);
1638extern int unregister_netdevice_notifier(struct notifier_block *nb); 1639extern int unregister_netdevice_notifier(struct notifier_block *nb);
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 2fb2d88e8c2e..03a92e117657 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -459,6 +459,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
459 459
460 case NETDEV_NOTIFY_PEERS: 460 case NETDEV_NOTIFY_PEERS:
461 case NETDEV_BONDING_FAILOVER: 461 case NETDEV_BONDING_FAILOVER:
462 case NETDEV_RESEND_IGMP:
462 /* Propagate to vlan devices */ 463 /* Propagate to vlan devices */
463 vlan_group_for_each_dev(grp, i, vlandev) 464 vlan_group_for_each_dev(grp, i, vlandev)
464 call_netdevice_notifiers(event, vlandev); 465 call_netdevice_notifiers(event, vlandev);
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 3a3f371b2841..2998dd1769a0 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -102,6 +102,11 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
102 case NETDEV_PRE_TYPE_CHANGE: 102 case NETDEV_PRE_TYPE_CHANGE:
103 /* Forbid underlaying device to change its type. */ 103 /* Forbid underlaying device to change its type. */
104 return NOTIFY_BAD; 104 return NOTIFY_BAD;
105
106 case NETDEV_RESEND_IGMP:
107 /* Propagate to master device */
108 call_netdevice_notifiers(event, br->dev);
109 break;
105 } 110 }
106 111
107 /* Events that may cause spanning tree to refresh */ 112 /* Events that may cause spanning tree to refresh */
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index cd71190d2962..375aca372250 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1323,16 +1323,17 @@ out:
1323EXPORT_SYMBOL(ip_mc_inc_group); 1323EXPORT_SYMBOL(ip_mc_inc_group);
1324 1324
1325/* 1325/*
1326 * Resend IGMP JOIN report; used for bonding. 1326 * Resend IGMP JOIN report; used by netdev notifier.
1327 * Called with rcu_read_lock()
1328 */ 1327 */
1329void ip_mc_rejoin_groups(struct in_device *in_dev) 1328static void ip_mc_rejoin_groups(struct in_device *in_dev)
1330{ 1329{
1331#ifdef CONFIG_IP_MULTICAST 1330#ifdef CONFIG_IP_MULTICAST
1332 struct ip_mc_list *im; 1331 struct ip_mc_list *im;
1333 int type; 1332 int type;
1334 1333
1335 for_each_pmc_rcu(in_dev, im) { 1334 ASSERT_RTNL();
1335
1336 for_each_pmc_rtnl(in_dev, im) {
1336 if (im->multiaddr == IGMP_ALL_HOSTS) 1337 if (im->multiaddr == IGMP_ALL_HOSTS)
1337 continue; 1338 continue;
1338 1339
@@ -1349,7 +1350,6 @@ void ip_mc_rejoin_groups(struct in_device *in_dev)
1349 } 1350 }
1350#endif 1351#endif
1351} 1352}
1352EXPORT_SYMBOL(ip_mc_rejoin_groups);
1353 1353
1354/* 1354/*
1355 * A socket has left a multicast group on device dev 1355 * A socket has left a multicast group on device dev
@@ -2735,8 +2735,42 @@ static struct pernet_operations igmp_net_ops = {
2735 .exit = igmp_net_exit, 2735 .exit = igmp_net_exit,
2736}; 2736};
2737 2737
2738static int igmp_netdev_event(struct notifier_block *this,
2739 unsigned long event, void *ptr)
2740{
2741 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
2742 struct in_device *in_dev;
2743
2744 switch (event) {
2745 case NETDEV_RESEND_IGMP:
2746 in_dev = __in_dev_get_rtnl(dev);
2747 if (in_dev)
2748 ip_mc_rejoin_groups(in_dev);
2749 break;
2750 default:
2751 break;
2752 }
2753 return NOTIFY_DONE;
2754}
2755
2756static struct notifier_block igmp_notifier = {
2757 .notifier_call = igmp_netdev_event,
2758};
2759
2738int __init igmp_mc_proc_init(void) 2760int __init igmp_mc_proc_init(void)
2739{ 2761{
2740 return register_pernet_subsys(&igmp_net_ops); 2762 int err;
2763
2764 err = register_pernet_subsys(&igmp_net_ops);
2765 if (err)
2766 return err;
2767 err = register_netdevice_notifier(&igmp_notifier);
2768 if (err)
2769 goto reg_notif_fail;
2770 return 0;
2771
2772reg_notif_fail:
2773 unregister_pernet_subsys(&igmp_net_ops);
2774 return err;
2741} 2775}
2742#endif 2776#endif