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 /net/ipv6/mcast.c | |
| 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>
Diffstat (limited to 'net/ipv6/mcast.c')
| -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); |
