diff options
author | Hangbin Liu <liuhangbin@gmail.com> | 2017-01-12 08:19:37 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-01-16 12:44:59 -0500 |
commit | 1666d49e1d416fcc2cce708242a52fe3317ea8ba (patch) | |
tree | 7a3f4000264d927086aa070fa549e4c5b97d0401 | |
parent | 34393529163af7163ef8459808e3cf2af7db7f16 (diff) |
mld: do not remove mld souce list info when set link down
This is an IPv6 version of commit 24803f38a5c0 ("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 <liuhangbin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv6/mcast.c | 51 |
1 files changed, 30 insertions, 21 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 14a3903f1c82..7139fffd61b6 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -81,7 +81,7 @@ static void mld_gq_timer_expire(unsigned long data); | |||
81 | static void mld_ifc_timer_expire(unsigned long data); | 81 | static void mld_ifc_timer_expire(unsigned long data); |
82 | static void mld_ifc_event(struct inet6_dev *idev); | 82 | static void mld_ifc_event(struct inet6_dev *idev); |
83 | static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc); | 83 | 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); |
85 | static void mld_clear_delrec(struct inet6_dev *idev); | 85 | static void mld_clear_delrec(struct inet6_dev *idev); |
86 | static bool mld_in_v1_mode(const struct inet6_dev *idev); | 86 | static bool mld_in_v1_mode(const struct inet6_dev *idev); |
87 | static int sf_setstate(struct ifmcaddr6 *pmc); | 87 | static int sf_setstate(struct ifmcaddr6 *pmc); |
@@ -692,9 +692,9 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc) | |||
692 | dev_mc_del(dev, buf); | 692 | dev_mc_del(dev, buf); |
693 | } | 693 | } |
694 | 694 | ||
695 | if (mc->mca_flags & MAF_NOREPORT) | ||
696 | goto done; | ||
697 | spin_unlock_bh(&mc->mca_lock); | 695 | spin_unlock_bh(&mc->mca_lock); |
696 | if (mc->mca_flags & MAF_NOREPORT) | ||
697 | return; | ||
698 | 698 | ||
699 | if (!mc->idev->dead) | 699 | if (!mc->idev->dead) |
700 | igmp6_leave_group(mc); | 700 | igmp6_leave_group(mc); |
@@ -702,8 +702,6 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc) | |||
702 | spin_lock_bh(&mc->mca_lock); | 702 | spin_lock_bh(&mc->mca_lock); |
703 | if (del_timer(&mc->mca_timer)) | 703 | if (del_timer(&mc->mca_timer)) |
704 | atomic_dec(&mc->mca_refcnt); | 704 | atomic_dec(&mc->mca_refcnt); |
705 | done: | ||
706 | ip6_mc_clear_src(mc); | ||
707 | spin_unlock_bh(&mc->mca_lock); | 705 | spin_unlock_bh(&mc->mca_lock); |
708 | } | 706 | } |
709 | 707 | ||
@@ -748,10 +746,11 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
748 | spin_unlock_bh(&idev->mc_lock); | 746 | spin_unlock_bh(&idev->mc_lock); |
749 | } | 747 | } |
750 | 748 | ||
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) |
752 | { | 750 | { |
753 | struct ifmcaddr6 *pmc, *pmc_prev; | 751 | 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; | ||
755 | 754 | ||
756 | spin_lock_bh(&idev->mc_lock); | 755 | spin_lock_bh(&idev->mc_lock); |
757 | pmc_prev = NULL; | 756 | pmc_prev = NULL; |
@@ -768,14 +767,20 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca) | |||
768 | } | 767 | } |
769 | spin_unlock_bh(&idev->mc_lock); | 768 | spin_unlock_bh(&idev->mc_lock); |
770 | 769 | ||
770 | spin_lock_bh(&im->mca_lock); | ||
771 | if (pmc) { | 771 | if (pmc) { |
772 | for (psf = pmc->mca_tomb; psf; psf = psf_next) { | 772 | im->idev = pmc->idev; |
773 | psf_next = psf->sf_next; | 773 | im->mca_crcount = idev->mc_qrv; |
774 | kfree(psf); | 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; | ||
775 | } | 780 | } |
776 | in6_dev_put(pmc->idev); | 781 | in6_dev_put(pmc->idev); |
777 | kfree(pmc); | ||
778 | } | 782 | } |
783 | spin_unlock_bh(&im->mca_lock); | ||
779 | } | 784 | } |
780 | 785 | ||
781 | static void mld_clear_delrec(struct inet6_dev *idev) | 786 | 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) | |||
904 | mca_get(mc); | 909 | mca_get(mc); |
905 | write_unlock_bh(&idev->lock); | 910 | write_unlock_bh(&idev->lock); |
906 | 911 | ||
907 | mld_del_delrec(idev, &mc->mca_addr); | 912 | mld_del_delrec(idev, mc); |
908 | igmp6_group_added(mc); | 913 | igmp6_group_added(mc); |
909 | ma_put(mc); | 914 | ma_put(mc); |
910 | return 0; | 915 | return 0; |
@@ -927,6 +932,7 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr) | |||
927 | write_unlock_bh(&idev->lock); | 932 | write_unlock_bh(&idev->lock); |
928 | 933 | ||
929 | igmp6_group_dropped(ma); | 934 | igmp6_group_dropped(ma); |
935 | ip6_mc_clear_src(ma); | ||
930 | 936 | ||
931 | ma_put(ma); | 937 | ma_put(ma); |
932 | return 0; | 938 | return 0; |
@@ -2501,15 +2507,17 @@ void ipv6_mc_down(struct inet6_dev *idev) | |||
2501 | /* Withdraw multicast list */ | 2507 | /* Withdraw multicast list */ |
2502 | 2508 | ||
2503 | read_lock_bh(&idev->lock); | 2509 | read_lock_bh(&idev->lock); |
2504 | mld_ifc_stop_timer(idev); | ||
2505 | mld_gq_stop_timer(idev); | ||
2506 | mld_dad_stop_timer(idev); | ||
2507 | 2510 | ||
2508 | for (i = idev->mc_list; i; i = i->next) | 2511 | for (i = idev->mc_list; i; i = i->next) |
2509 | igmp6_group_dropped(i); | 2512 | igmp6_group_dropped(i); |
2510 | read_unlock_bh(&idev->lock); | ||
2511 | 2513 | ||
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); | ||
2513 | } | 2521 | } |
2514 | 2522 | ||
2515 | static void ipv6_mc_reset(struct inet6_dev *idev) | 2523 | static void ipv6_mc_reset(struct inet6_dev *idev) |
@@ -2531,8 +2539,10 @@ void ipv6_mc_up(struct inet6_dev *idev) | |||
2531 | 2539 | ||
2532 | read_lock_bh(&idev->lock); | 2540 | read_lock_bh(&idev->lock); |
2533 | ipv6_mc_reset(idev); | 2541 | 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); | ||
2535 | igmp6_group_added(i); | 2544 | igmp6_group_added(i); |
2545 | } | ||
2536 | read_unlock_bh(&idev->lock); | 2546 | read_unlock_bh(&idev->lock); |
2537 | } | 2547 | } |
2538 | 2548 | ||
@@ -2565,6 +2575,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) | |||
2565 | 2575 | ||
2566 | /* Deactivate timers */ | 2576 | /* Deactivate timers */ |
2567 | ipv6_mc_down(idev); | 2577 | ipv6_mc_down(idev); |
2578 | mld_clear_delrec(idev); | ||
2568 | 2579 | ||
2569 | /* Delete all-nodes address. */ | 2580 | /* Delete all-nodes address. */ |
2570 | /* We cannot call ipv6_dev_mc_dec() directly, our caller in | 2581 | /* We cannot call ipv6_dev_mc_dec() directly, our caller in |
@@ -2579,11 +2590,9 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) | |||
2579 | write_lock_bh(&idev->lock); | 2590 | write_lock_bh(&idev->lock); |
2580 | while ((i = idev->mc_list) != NULL) { | 2591 | while ((i = idev->mc_list) != NULL) { |
2581 | idev->mc_list = i->next; | 2592 | idev->mc_list = i->next; |
2582 | write_unlock_bh(&idev->lock); | ||
2583 | 2593 | ||
2584 | igmp6_group_dropped(i); | 2594 | write_unlock_bh(&idev->lock); |
2585 | ma_put(i); | 2595 | ma_put(i); |
2586 | |||
2587 | write_lock_bh(&idev->lock); | 2596 | write_lock_bh(&idev->lock); |
2588 | } | 2597 | } |
2589 | write_unlock_bh(&idev->lock); | 2598 | write_unlock_bh(&idev->lock); |