Skip to content

Commit 1666d49

Browse files
liuhangbindavem330
authored andcommitted
mld: do not remove mld souce list info when set link down
This is an IPv6 version of commit 24803f3 ("igmp: do not remove igmp souce list..."). In mld_del_delrec(), we will restore back all source filter info instead of flush them. Move mld_clear_delrec() from ipv6_mc_down() to ipv6_mc_destroy_dev() since we should not remove source list info when set link down. Remove igmp6_group_dropped() in ipv6_mc_destroy_dev() since we have called it in ipv6_mc_down(). Also clear all source info after igmp6_group_dropped() instead of in it because ipv6_mc_down() will call igmp6_group_dropped(). Signed-off-by: Hangbin Liu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3439352 commit 1666d49

File tree

1 file changed

+30
-21
lines changed

1 file changed

+30
-21
lines changed

net/ipv6/mcast.c

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static void mld_gq_timer_expire(unsigned long data);
8181
static void mld_ifc_timer_expire(unsigned long data);
8282
static void mld_ifc_event(struct inet6_dev *idev);
8383
static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
84-
static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr);
84+
static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
8585
static void mld_clear_delrec(struct inet6_dev *idev);
8686
static bool mld_in_v1_mode(const struct inet6_dev *idev);
8787
static int sf_setstate(struct ifmcaddr6 *pmc);
@@ -692,18 +692,16 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc)
692692
dev_mc_del(dev, buf);
693693
}
694694

695-
if (mc->mca_flags & MAF_NOREPORT)
696-
goto done;
697695
spin_unlock_bh(&mc->mca_lock);
696+
if (mc->mca_flags & MAF_NOREPORT)
697+
return;
698698

699699
if (!mc->idev->dead)
700700
igmp6_leave_group(mc);
701701

702702
spin_lock_bh(&mc->mca_lock);
703703
if (del_timer(&mc->mca_timer))
704704
atomic_dec(&mc->mca_refcnt);
705-
done:
706-
ip6_mc_clear_src(mc);
707705
spin_unlock_bh(&mc->mca_lock);
708706
}
709707

@@ -748,10 +746,11 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
748746
spin_unlock_bh(&idev->mc_lock);
749747
}
750748

751-
static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
749+
static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
752750
{
753751
struct ifmcaddr6 *pmc, *pmc_prev;
754-
struct ip6_sf_list *psf, *psf_next;
752+
struct ip6_sf_list *psf;
753+
struct in6_addr *pmca = &im->mca_addr;
755754

756755
spin_lock_bh(&idev->mc_lock);
757756
pmc_prev = NULL;
@@ -768,14 +767,20 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
768767
}
769768
spin_unlock_bh(&idev->mc_lock);
770769

770+
spin_lock_bh(&im->mca_lock);
771771
if (pmc) {
772-
for (psf = pmc->mca_tomb; psf; psf = psf_next) {
773-
psf_next = psf->sf_next;
774-
kfree(psf);
772+
im->idev = pmc->idev;
773+
im->mca_crcount = idev->mc_qrv;
774+
im->mca_sfmode = pmc->mca_sfmode;
775+
if (pmc->mca_sfmode == MCAST_INCLUDE) {
776+
im->mca_tomb = pmc->mca_tomb;
777+
im->mca_sources = pmc->mca_sources;
778+
for (psf = im->mca_sources; psf; psf = psf->sf_next)
779+
psf->sf_crcount = im->mca_crcount;
775780
}
776781
in6_dev_put(pmc->idev);
777-
kfree(pmc);
778782
}
783+
spin_unlock_bh(&im->mca_lock);
779784
}
780785

781786
static void mld_clear_delrec(struct inet6_dev *idev)
@@ -904,7 +909,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
904909
mca_get(mc);
905910
write_unlock_bh(&idev->lock);
906911

907-
mld_del_delrec(idev, &mc->mca_addr);
912+
mld_del_delrec(idev, mc);
908913
igmp6_group_added(mc);
909914
ma_put(mc);
910915
return 0;
@@ -927,6 +932,7 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
927932
write_unlock_bh(&idev->lock);
928933

929934
igmp6_group_dropped(ma);
935+
ip6_mc_clear_src(ma);
930936

931937
ma_put(ma);
932938
return 0;
@@ -2501,15 +2507,17 @@ void ipv6_mc_down(struct inet6_dev *idev)
25012507
/* Withdraw multicast list */
25022508

25032509
read_lock_bh(&idev->lock);
2504-
mld_ifc_stop_timer(idev);
2505-
mld_gq_stop_timer(idev);
2506-
mld_dad_stop_timer(idev);
25072510

25082511
for (i = idev->mc_list; i; i = i->next)
25092512
igmp6_group_dropped(i);
2510-
read_unlock_bh(&idev->lock);
25112513

2512-
mld_clear_delrec(idev);
2514+
/* Should stop timer after group drop. or we will
2515+
* start timer again in mld_ifc_event()
2516+
*/
2517+
mld_ifc_stop_timer(idev);
2518+
mld_gq_stop_timer(idev);
2519+
mld_dad_stop_timer(idev);
2520+
read_unlock_bh(&idev->lock);
25132521
}
25142522

25152523
static void ipv6_mc_reset(struct inet6_dev *idev)
@@ -2531,8 +2539,10 @@ void ipv6_mc_up(struct inet6_dev *idev)
25312539

25322540
read_lock_bh(&idev->lock);
25332541
ipv6_mc_reset(idev);
2534-
for (i = idev->mc_list; i; i = i->next)
2542+
for (i = idev->mc_list; i; i = i->next) {
2543+
mld_del_delrec(idev, i);
25352544
igmp6_group_added(i);
2545+
}
25362546
read_unlock_bh(&idev->lock);
25372547
}
25382548

@@ -2565,6 +2575,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
25652575

25662576
/* Deactivate timers */
25672577
ipv6_mc_down(idev);
2578+
mld_clear_delrec(idev);
25682579

25692580
/* Delete all-nodes address. */
25702581
/* We cannot call ipv6_dev_mc_dec() directly, our caller in
@@ -2579,11 +2590,9 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
25792590
write_lock_bh(&idev->lock);
25802591
while ((i = idev->mc_list) != NULL) {
25812592
idev->mc_list = i->next;
2582-
write_unlock_bh(&idev->lock);
25832593

2584-
igmp6_group_dropped(i);
2594+
write_unlock_bh(&idev->lock);
25852595
ma_put(i);
2586-
25872596
write_lock_bh(&idev->lock);
25882597
}
25892598
write_unlock_bh(&idev->lock);

0 commit comments

Comments
 (0)