| From 4c6980462f32b4f282c5d8e5f7ea8070e2937725 Mon Sep 17 00:00:00 2001 |
| From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| Date: Fri, 20 Nov 2015 13:54:20 +0100 |
| Subject: net: ip6mr: fix static mfc/dev leaks on table destruction |
| |
| commit 4c6980462f32b4f282c5d8e5f7ea8070e2937725 upstream. |
| |
| Similar to ipv4, when destroying an mrt table the static mfc entries and |
| the static devices are kept, which leads to devices that can never be |
| destroyed (because of refcnt taken) and leaked memory. Make sure that |
| everything is cleaned up on netns destruction. |
| |
| Fixes: 8229efdaef1e ("netns: ip6mr: enable namespace support in ipv6 multicast forwarding code") |
| CC: Benjamin Thery <benjamin.thery@bull.net> |
| Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| Reviewed-by: Cong Wang <cwang@twopensource.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Zefan Li <lizefan@huawei.com> |
| --- |
| net/ipv6/ip6mr.c | 15 ++++++++------- |
| 1 file changed, 8 insertions(+), 7 deletions(-) |
| |
| --- a/net/ipv6/ip6mr.c |
| +++ b/net/ipv6/ip6mr.c |
| @@ -117,7 +117,7 @@ static int __ip6mr_fill_mroute(struct mr |
| struct mfc6_cache *c, struct rtmsg *rtm); |
| static int ip6mr_rtm_dumproute(struct sk_buff *skb, |
| struct netlink_callback *cb); |
| -static void mroute_clean_tables(struct mr6_table *mrt); |
| +static void mroute_clean_tables(struct mr6_table *mrt, bool all); |
| static void ipmr_expire_process(unsigned long arg); |
| |
| #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES |
| @@ -334,7 +334,7 @@ static struct mr6_table *ip6mr_new_table |
| static void ip6mr_free_table(struct mr6_table *mrt) |
| { |
| del_timer_sync(&mrt->ipmr_expire_timer); |
| - mroute_clean_tables(mrt); |
| + mroute_clean_tables(mrt, true); |
| kfree(mrt); |
| } |
| |
| @@ -1472,7 +1472,7 @@ static int ip6mr_mfc_add(struct net *net |
| * Close the multicast socket, and clear the vif tables etc |
| */ |
| |
| -static void mroute_clean_tables(struct mr6_table *mrt) |
| +static void mroute_clean_tables(struct mr6_table *mrt, bool all) |
| { |
| int i; |
| LIST_HEAD(list); |
| @@ -1482,8 +1482,9 @@ static void mroute_clean_tables(struct m |
| * Shut down all active vif entries |
| */ |
| for (i = 0; i < mrt->maxvif; i++) { |
| - if (!(mrt->vif6_table[i].flags & VIFF_STATIC)) |
| - mif6_delete(mrt, i, &list); |
| + if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC)) |
| + continue; |
| + mif6_delete(mrt, i, &list); |
| } |
| unregister_netdevice_many(&list); |
| |
| @@ -1492,7 +1493,7 @@ static void mroute_clean_tables(struct m |
| */ |
| for (i = 0; i < MFC6_LINES; i++) { |
| list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) { |
| - if (c->mfc_flags & MFC_STATIC) |
| + if (!all && (c->mfc_flags & MFC_STATIC)) |
| continue; |
| write_lock_bh(&mrt_lock); |
| list_del(&c->list); |
| @@ -1546,7 +1547,7 @@ int ip6mr_sk_done(struct sock *sk) |
| net->ipv6.devconf_all->mc_forwarding--; |
| write_unlock_bh(&mrt_lock); |
| |
| - mroute_clean_tables(mrt); |
| + mroute_clean_tables(mrt, false); |
| err = 0; |
| break; |
| } |