diff mbox

[net] igmp: do not remove igmp souce list info when set link down

Message ID 1478502122-6570-1-git-send-email-liuhangbin@gmail.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Hangbin Liu Nov. 7, 2016, 7:02 a.m. UTC
In commit 24cf3af(igmp: call ip_mc_clear_src...), we forgot to remove
igmpv3_clear_delrec() in ip_mc_down(), which also called ip_mc_clear_src().
This make us clear all IGMPv3 source filter info after NETDEV_DOWN.
Move igmpv3_clear_delrec() to ip_mc_destroy_dev() and then no need
ip_mc_clear_src() in ip_mc_destroy_dev().

On the other hand, we should restore back instead of free all source filter
info in igmpv3_del_delrec(). Or we will not able to restore IGMPv3 source
filter info after NETDEV_UP and NETDEV_POST_TYPE_CHANGE.

Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
 net/ipv4/igmp.c | 47 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 33 insertions(+), 14 deletions(-)

Comments

kernel test robot Nov. 7, 2016, 7:35 a.m. UTC | #1
Hi Hangbin,

[auto build test ERROR on net/master]

url:    https://github.com/0day-ci/linux/commits/Hangbin-Liu/igmp-do-not-remove-igmp-souce-list-info-when-set-link-down/20161107-151122
config: i386-randconfig-x007-201645 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   net/ipv4/igmp.c: In function 'igmpv3_del_delrec':
>> net/ipv4/igmp.c:1160:35: error: 'sysctl_igmp_qrv' undeclared (first use in this function)
      im->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
                                      ^~~~~~~~~~~~~~~
   net/ipv4/igmp.c:1160:35: note: each undeclared identifier is reported only once for each function it appears in

vim +/sysctl_igmp_qrv +1160 net/ipv4/igmp.c

  1154		}
  1155		spin_unlock_bh(&in_dev->mc_tomb_lock);
  1156	
  1157		spin_lock_bh(&im->lock);
  1158		if (pmc) {
  1159			im->interface = pmc->interface;
> 1160			im->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
  1161			im->sfmode = pmc->sfmode;
  1162			if (pmc->sfmode == MCAST_INCLUDE) {
  1163				im->tomb = pmc->tomb;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot Nov. 7, 2016, 7:49 a.m. UTC | #2
Hi Hangbin,

[auto build test ERROR on net/master]

url:    https://github.com/0day-ci/linux/commits/Hangbin-Liu/igmp-do-not-remove-igmp-souce-list-info-when-set-link-down/20161107-151122
config: i386-randconfig-x016-201645 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   net/ipv4/igmp.c: In function 'ip_mc_destroy_dev':
>> net/ipv4/igmp.c:1728:2: error: implicit declaration of function 'igmpv3_clear_delrec' [-Werror=implicit-function-declaration]
     igmpv3_clear_delrec(in_dev);
     ^~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/igmpv3_clear_delrec +1728 net/ipv4/igmp.c

  1722		struct ip_mc_list *i;
  1723	
  1724		ASSERT_RTNL();
  1725	
  1726		/* Deactivate timers */
  1727		ip_mc_down(in_dev);
> 1728		igmpv3_clear_delrec(in_dev);
  1729	
  1730		while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) {
  1731			in_dev->mc_list = i->next_rcu;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 606cc3e..97ef4a7 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -162,7 +162,7 @@  static int unsolicited_report_interval(struct in_device *in_dev)
 }
 
 static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
-static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr);
+static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im);
 static void igmpv3_clear_delrec(struct in_device *in_dev);
 static int sf_setstate(struct ip_mc_list *pmc);
 static void sf_markstate(struct ip_mc_list *pmc);
@@ -1130,10 +1130,14 @@  static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
 	spin_unlock_bh(&in_dev->mc_tomb_lock);
 }
 
-static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
+/*
+ * restore ip_mc_list deleted records
+ */
+static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
 {
 	struct ip_mc_list *pmc, *pmc_prev;
-	struct ip_sf_list *psf, *psf_next;
+	struct ip_sf_list *psf;
+	__be32 multiaddr = im->multiaddr;
 
 	spin_lock_bh(&in_dev->mc_tomb_lock);
 	pmc_prev = NULL;
@@ -1149,16 +1153,26 @@  static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
 			in_dev->mc_tomb = pmc->next;
 	}
 	spin_unlock_bh(&in_dev->mc_tomb_lock);
+
+	spin_lock_bh(&im->lock);
 	if (pmc) {
-		for (psf = pmc->tomb; psf; psf = psf_next) {
-			psf_next = psf->sf_next;
-			kfree(psf);
+		im->interface = pmc->interface;
+		im->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
+		im->sfmode = pmc->sfmode;
+		if (pmc->sfmode == MCAST_INCLUDE) {
+			im->tomb = pmc->tomb;
+			im->sources = pmc->sources;
+			for (psf = im->sources; psf; psf = psf->sf_next)
+				psf->sf_crcount = im->crcount;
 		}
 		in_dev_put(pmc->interface);
-		kfree(pmc);
 	}
+	spin_unlock_bh(&im->lock);
 }
 
+/*
+ * flush ip_mc_list deleted records
+ */
 static void igmpv3_clear_delrec(struct in_device *in_dev)
 {
 	struct ip_mc_list *pmc, *nextpmc;
@@ -1366,7 +1380,7 @@  void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 	ip_mc_hash_add(in_dev, im);
 
 #ifdef CONFIG_IP_MULTICAST
-	igmpv3_del_delrec(in_dev, im->multiaddr);
+	igmpv3_del_delrec(in_dev, im);
 #endif
 	igmp_group_added(im);
 	if (!in_dev->dead)
@@ -1626,8 +1640,12 @@  void ip_mc_remap(struct in_device *in_dev)
 
 	ASSERT_RTNL();
 
-	for_each_pmc_rtnl(in_dev, pmc)
+	for_each_pmc_rtnl(in_dev, pmc) {
+#ifdef CONFIG_IP_MULTICAST
+		igmpv3_del_delrec(in_dev, pmc);
+#endif
 		igmp_group_added(pmc);
+	}
 }
 
 /* Device going down */
@@ -1648,7 +1666,6 @@  void ip_mc_down(struct in_device *in_dev)
 	in_dev->mr_gq_running = 0;
 	if (del_timer(&in_dev->mr_gq_timer))
 		__in_dev_put(in_dev);
-	igmpv3_clear_delrec(in_dev);
 #endif
 
 	ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
@@ -1688,8 +1705,12 @@  void ip_mc_up(struct in_device *in_dev)
 #endif
 	ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
 
-	for_each_pmc_rtnl(in_dev, pmc)
+	for_each_pmc_rtnl(in_dev, pmc) {
+#ifdef CONFIG_IP_MULTICAST
+		igmpv3_del_delrec(in_dev, pmc);
+#endif
 		igmp_group_added(pmc);
+	}
 }
 
 /*
@@ -1704,13 +1725,11 @@  void ip_mc_destroy_dev(struct in_device *in_dev)
 
 	/* Deactivate timers */
 	ip_mc_down(in_dev);
+	igmpv3_clear_delrec(in_dev);
 
 	while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) {
 		in_dev->mc_list = i->next_rcu;
 		in_dev->mc_count--;
-
-		/* We've dropped the groups in ip_mc_down already */
-		ip_mc_clear_src(i);
 		ip_ma_put(i);
 	}
 }