Received: by 2002:ac0:946b:0:0:0:0:0 with SMTP id j40csp1734340imj; Sun, 17 Feb 2019 13:08:43 -0800 (PST) X-Google-Smtp-Source: AHgI3IYQxMWJlt7ZP675JmEPQGwT8KXSJ65BromZd21/fATTa/Ud63BaAsdPxUbtH22Css/or5gC X-Received: by 2002:a63:6184:: with SMTP id v126mr15579518pgb.277.1550437723580; Sun, 17 Feb 2019 13:08:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550437723; cv=none; d=google.com; s=arc-20160816; b=LLo1HQxeC9xqz4teLxelwdUUzCiH35gwy4C0c4JHw1a8qnXtv4vu6KzG63wqQin0R3 w9ZC4CXIXqZ0Jsktqu906Mc5fcgiV8Pr79drLA916UWEFA++HaoLlefF0blxYuUD3JWD QKKoNtYHV2RT3LY3YzVfJAHWoT3RB+mDw7BVslSHaWYrOHqp2kbKBK5kefK9D1rrkuNf j6r8mg/6vkTZNElN+kOR+SpSRXbfvQb9zDCT+Iu/c78oUV6+D61rGMFUskAV6oWO9RXO ekQb18Jljqja7pGDc9Cb2lmIx0+YgphZljOVP8jaRdnIBoXzbI3C04zBx9rYmsMD5Zyt Tsig== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=RxfYeso134cTrrKx1V87Rj5ZWbE7TMJ6LuN8IYl1wUI=; b=kEdSV2F30rfnIGLY1EBwHoy8w5Lp8ZGoK8AES5y8dmlvldzcBEMMOqqPUmB15uN3Vg fFoqZse6xdZmXw33AlEqc/HSkfDMevXO5lTxsEDRkwW8risoV25CbJA8i3MX/kEyPyjS SZUGZbiE3/F/amLxpiFNpzqveih/RoN4DnkIiMQtIcWo8m9xd0Qd9fDRupedmld4nieo hz3OPcTfdN7tjsTAq3Ka0RMzVgrLdUPHvOpzbL3Rxxkz9a5dOS/f3tWs8pFbnAPaNXHw SEwN3yJwweDFt6/+1RalWi4JhBz3YKrf+xTFoiL4zNHvEL2GGy/KNcPM9O0sjrbAGYTN ucHQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@alliedtelesis.co.nz header.s=mail181024 header.b=eZoD3jY1; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alliedtelesis.co.nz Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 123si11306493pfx.109.2019.02.17.13.08.27; Sun, 17 Feb 2019 13:08:43 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@alliedtelesis.co.nz header.s=mail181024 header.b=eZoD3jY1; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alliedtelesis.co.nz Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726551AbfBQVH6 (ORCPT + 99 others); Sun, 17 Feb 2019 16:07:58 -0500 Received: from gate2.alliedtelesis.co.nz ([202.36.163.20]:51338 "EHLO gate2.alliedtelesis.co.nz" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726124AbfBQVH5 (ORCPT ); Sun, 17 Feb 2019 16:07:57 -0500 Received: from mmarshal3.atlnz.lc (mmarshal3.atlnz.lc [10.32.18.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by gate2.alliedtelesis.co.nz (Postfix) with ESMTPS id 297C08365A; Mon, 18 Feb 2019 10:07:55 +1300 (NZDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alliedtelesis.co.nz; s=mail181024; t=1550437675; bh=RxfYeso134cTrrKx1V87Rj5ZWbE7TMJ6LuN8IYl1wUI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=eZoD3jY1gQhA0H11scWLOByfmbmL7NHzK9k8Z834/qtarivddky1O//oC4VIxDo+J VyLjL81TvHoOTd91Ui5d7Xp920K0zpOts72huO5YuPBs3eBmhN/I+vMqR8pFu4IgYo 22slSG1ymhFGb/qeU8gF5NzGdAEbsXkX1ReQ3VVYLtix9KHQidTuH3yv5Zd8KRWiSy Ifrhs6pvy3OI2on/7bCOE4fRBotwdHtL84XmvNkTCu60Jb3yt8lajol2khHabJ5uC0 vxC9eS6EftqW4i2JXR9tk1sikf085ihaVrFxvBzKvzghCQ2ZOKJGbSJBYXHTTGY7Zb ql2sZ+yY+CTkg== Received: from smtp (Not Verified[10.32.16.33]) by mmarshal3.atlnz.lc with Trustwave SEG (v7,5,8,10121) id ; Mon, 18 Feb 2019 10:07:55 +1300 Received: from callums-dl.ws.atlnz.lc (callums-dl.ws.atlnz.lc [10.33.22.12]) by smtp (Postfix) with ESMTP id F1CDB13EEFC; Mon, 18 Feb 2019 10:07:54 +1300 (NZDT) Received: by callums-dl.ws.atlnz.lc (Postfix, from userid 1764) id D844A3A064C; Mon, 18 Feb 2019 10:07:54 +1300 (NZDT) From: Callum Sinclair To: davem@davemloft.net, kuznet@ms2.inr.ac.ru, yoshfuji@linux-ipv6.org, nikolay@cumulusnetworks.com, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Cc: nicolas.dichtel@6wind.com, Callum Sinclair Subject: [PATCH net-next v6] ipmr: ip6mr: Create new sockopt to clear mfc cache or vifs Date: Mon, 18 Feb 2019 10:07:52 +1300 Message-Id: <20190217210752.20914-2-callum.sinclair@alliedtelesis.co.nz> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190217210752.20914-1-callum.sinclair@alliedtelesis.co.nz> References: <20190217210752.20914-1-callum.sinclair@alliedtelesis.co.nz> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable x-atlnz-ls: pat Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently the only way to clear the forwarding cache was to delete the entries one by one using the MRT_DEL_MFC socket option or to destroy and recreate the socket. Create a new socket option which with the use of optional flags can clear any combination of multicast entries (static or not static) and multicast vifs (static or not static). Calling the new socket option MRT_FLUSH with the flags MRT_FLUSH_MFC and MRT_FLUSH_VIFS will clear all entries and vifs on the socket except for static entries. Signed-off-by: Callum Sinclair --- v1 -> v2: Implemented additional flags for static entries v2 -> v3: Cleaned up flag logic so any combination of routes can be cleared. Fixed style errors Fixed incorrect flag values v3 -> v4: Fixed style errors Fixed incorrect flag (MRT_FLUSH was used instead of MRT_FLUSH_VIFS) v4 -> v5: Only clear the unresolved queue when MRT_FLUSH_MFC flag is set. v5 -> v6: Renamed MRT6_FLUSH_VIFS to MRT6_FLUSH_MIFS include/uapi/linux/mroute.h | 9 ++++- include/uapi/linux/mroute6.h | 9 ++++- net/ipv4/ipmr.c | 75 +++++++++++++++++++++------------- net/ipv6/ip6mr.c | 78 +++++++++++++++++++++++------------- 4 files changed, 115 insertions(+), 56 deletions(-) diff --git a/include/uapi/linux/mroute.h b/include/uapi/linux/mroute.h index 5d37a9ccce63..11c8c1fc1124 100644 --- a/include/uapi/linux/mroute.h +++ b/include/uapi/linux/mroute.h @@ -28,12 +28,19 @@ #define MRT_TABLE (MRT_BASE+9) /* Specify mroute table ID */ #define MRT_ADD_MFC_PROXY (MRT_BASE+10) /* Add a (*,*|G) mfc entry */ #define MRT_DEL_MFC_PROXY (MRT_BASE+11) /* Del a (*,*|G) mfc entry */ -#define MRT_MAX (MRT_BASE+11) +#define MRT_FLUSH (MRT_BASE+12) /* Flush all mfc entries and/or vifs */ +#define MRT_MAX (MRT_BASE+12) =20 #define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ #define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) #define SIOCGETRPF (SIOCPROTOPRIVATE+2) =20 +/* MRT_FLUSH optional flags */ +#define MRT_FLUSH_MFC 1 /* Flush multicast entries */ +#define MRT_FLUSH_MFC_STATIC 2 /* Flush static multicast entries */ +#define MRT_FLUSH_VIFS 4 /* Flush multicast vifs */ +#define MRT_FLUSH_VIFS_STATIC 8 /* Flush static multicast vifs */ + #define MAXVIFS 32 typedef unsigned long vifbitmap_t; /* User mode code depends on this lot= */ typedef unsigned short vifi_t; diff --git a/include/uapi/linux/mroute6.h b/include/uapi/linux/mroute6.h index 9999cc006390..c36177a86516 100644 --- a/include/uapi/linux/mroute6.h +++ b/include/uapi/linux/mroute6.h @@ -31,12 +31,19 @@ #define MRT6_TABLE (MRT6_BASE+9) /* Specify mroute table ID */ #define MRT6_ADD_MFC_PROXY (MRT6_BASE+10) /* Add a (*,*|G) mfc entry */ #define MRT6_DEL_MFC_PROXY (MRT6_BASE+11) /* Del a (*,*|G) mfc entry */ -#define MRT6_MAX (MRT6_BASE+11) +#define MRT6_FLUSH (MRT6_BASE+12) /* Flush all mfc entries and/or vifs *= / +#define MRT6_MAX (MRT6_BASE+12) =20 #define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ #define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) #define SIOCGETRPF (SIOCPROTOPRIVATE+2) =20 +/* MRT6_FLUSH optional flags */ +#define MRT6_FLUSH_MFC 1 /* Flush multicast entries */ +#define MRT6_FLUSH_MFC_STATIC 2 /* Flush static multicast entries */ +#define MRT6_FLUSH_MIFS 4 /* Flushing multicast vifs */ +#define MRT6_FLUSH_MIFS_STATIC 8 /* Flush static multicast vifs */ + #define MAXMIFS 32 typedef unsigned long mifbitmap_t; /* User mode code depends on this lot= */ typedef unsigned short mifi_t; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index e536970557dd..2c931120c494 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -110,7 +110,7 @@ static int ipmr_cache_report(struct mr_table *mrt, static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache = *mfc, int cmd); static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *= pkt); -static void mroute_clean_tables(struct mr_table *mrt, bool all); +static void mroute_clean_tables(struct mr_table *mrt, int flags); static void ipmr_expire_process(struct timer_list *t); =20 #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES @@ -415,7 +415,8 @@ static struct mr_table *ipmr_new_table(struct net *ne= t, u32 id) static void ipmr_free_table(struct mr_table *mrt) { del_timer_sync(&mrt->ipmr_expire_timer); - mroute_clean_tables(mrt, true); + mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC | + MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC); rhltable_destroy(&mrt->mfc_hash); kfree(mrt); } @@ -1296,7 +1297,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_= table *mrt, } =20 /* Close the multicast socket, and clear the vif tables etc */ -static void mroute_clean_tables(struct mr_table *mrt, bool all) +static void mroute_clean_tables(struct mr_table *mrt, int flags) { struct net *net =3D read_pnet(&mrt->net); struct mr_mfc *c, *tmp; @@ -1305,35 +1306,44 @@ static void mroute_clean_tables(struct mr_table *= mrt, bool all) int i; =20 /* Shut down all active vif entries */ - for (i =3D 0; i < mrt->maxvif; i++) { - if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) - continue; - vif_delete(mrt, i, 0, &list); + if (flags & (MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC)) { + for (i =3D 0; i < mrt->maxvif; i++) { + if (((mrt->vif_table[i].flags & VIFF_STATIC) && + !(flags & MRT_FLUSH_VIFS_STATIC)) || + (!(mrt->vif_table[i].flags & VIFF_STATIC) && !(flags & MRT_FLUSH_= VIFS))) + continue; + vif_delete(mrt, i, 0, &list); + } + unregister_netdevice_many(&list); } - unregister_netdevice_many(&list); =20 /* Wipe the cache */ - list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { - if (!all && (c->mfc_flags & MFC_STATIC)) - continue; - rhltable_remove(&mrt->mfc_hash, &c->mnode, ipmr_rht_params); - list_del_rcu(&c->list); - cache =3D (struct mfc_cache *)c; - call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, cache, - mrt->id); - mroute_netlink_event(mrt, cache, RTM_DELROUTE); - mr_cache_put(c); - } - - if (atomic_read(&mrt->cache_resolve_queue_len) !=3D 0) { - spin_lock_bh(&mfc_unres_lock); - list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { - list_del(&c->list); + if (flags & (MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC)) { + list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { + if (((c->mfc_flags & MFC_STATIC) && !(flags & MRT_FLUSH_MFC_STATIC)) = || + (!(c->mfc_flags & MFC_STATIC) && !(flags & MRT_FLUSH_MFC))) + continue; + rhltable_remove(&mrt->mfc_hash, &c->mnode, ipmr_rht_params); + list_del_rcu(&c->list); cache =3D (struct mfc_cache *)c; + call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, cache, + mrt->id); mroute_netlink_event(mrt, cache, RTM_DELROUTE); - ipmr_destroy_unres(mrt, cache); + mr_cache_put(c); + } + } + + if (flags & MRT_FLUSH_MFC) { + if (atomic_read(&mrt->cache_resolve_queue_len) !=3D 0) { + spin_lock_bh(&mfc_unres_lock); + list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { + list_del(&c->list); + cache =3D (struct mfc_cache *)c; + mroute_netlink_event(mrt, cache, RTM_DELROUTE); + ipmr_destroy_unres(mrt, cache); + } + spin_unlock_bh(&mfc_unres_lock); } - spin_unlock_bh(&mfc_unres_lock); } } =20 @@ -1354,7 +1364,7 @@ static void mrtsock_destruct(struct sock *sk) NETCONFA_IFINDEX_ALL, net->ipv4.devconf_all); RCU_INIT_POINTER(mrt->mroute_sk, NULL); - mroute_clean_tables(mrt, false); + mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_MFC); } } rtnl_unlock(); @@ -1479,6 +1489,17 @@ int ip_mroute_setsockopt(struct sock *sk, int optn= ame, char __user *optval, sk =3D=3D rtnl_dereference(mrt->mroute_sk), parent); break; + case MRT_FLUSH: + if (optlen !=3D sizeof(val)) { + ret =3D -EINVAL; + break; + } + if (get_user(val, (int __user *)optval)) { + ret =3D -EFAULT; + break; + } + mroute_clean_tables(mrt, val); + break; /* Control PIM assert. */ case MRT_ASSERT: if (optlen !=3D sizeof(val)) { diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index cc01aa3f2b5e..3594f1d9c68c 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -97,7 +97,7 @@ static void mr6_netlink_event(struct mr_table *mrt, str= uct mfc6_cache *mfc, static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *= pkt); static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb); -static void mroute_clean_tables(struct mr_table *mrt, bool all); +static void mroute_clean_tables(struct mr_table *mrt, int flags); static void ipmr_expire_process(struct timer_list *t); =20 #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES @@ -393,7 +393,8 @@ static struct mr_table *ip6mr_new_table(struct net *n= et, u32 id) static void ip6mr_free_table(struct mr_table *mrt) { del_timer_sync(&mrt->ipmr_expire_timer); - mroute_clean_tables(mrt, true); + mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC | + MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC); rhltable_destroy(&mrt->mfc_hash); kfree(mrt); } @@ -1496,42 +1497,51 @@ static int ip6mr_mfc_add(struct net *net, struct = mr_table *mrt, * Close the multicast socket, and clear the vif tables etc */ =20 -static void mroute_clean_tables(struct mr_table *mrt, bool all) +static void mroute_clean_tables(struct mr_table *mrt, int flags) { struct mr_mfc *c, *tmp; LIST_HEAD(list); int i; =20 /* Shut down all active vif entries */ - for (i =3D 0; i < mrt->maxvif; i++) { - if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) - continue; - mif6_delete(mrt, i, 0, &list); + if (flags & (MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC)) { + for (i =3D 0; i < mrt->maxvif; i++) { + if (((mrt->vif_table[i].flags & VIFF_STATIC) && + !(flags & MRT6_FLUSH_MIFS_STATIC)) || + (!(mrt->vif_table[i].flags & VIFF_STATIC) && !(flags & MRT6_FLUSH= _MIFS))) + continue; + mif6_delete(mrt, i, 0, &list); + } + unregister_netdevice_many(&list); } - unregister_netdevice_many(&list); =20 /* Wipe the cache */ - list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { - if (!all && (c->mfc_flags & MFC_STATIC)) - continue; - rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); - list_del_rcu(&c->list); - call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), - FIB_EVENT_ENTRY_DEL, - (struct mfc6_cache *)c, mrt->id); - mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); - mr_cache_put(c); + if (flags & (MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC)) { + list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { + if (((c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC_STATIC))= || + (!(c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC))) + continue; + rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); + list_del_rcu(&c->list); + call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), + FIB_EVENT_ENTRY_DEL, + (struct mfc6_cache *)c, mrt->id); + mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); + mr_cache_put(c); + } } =20 - if (atomic_read(&mrt->cache_resolve_queue_len) !=3D 0) { - spin_lock_bh(&mfc_unres_lock); - list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { - list_del(&c->list); - mr6_netlink_event(mrt, (struct mfc6_cache *)c, - RTM_DELROUTE); - ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); + if (flags & MRT6_FLUSH_MFC) { + if (atomic_read(&mrt->cache_resolve_queue_len) !=3D 0) { + spin_lock_bh(&mfc_unres_lock); + list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { + list_del(&c->list); + mr6_netlink_event(mrt, (struct mfc6_cache *)c, + RTM_DELROUTE); + ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); + } + spin_unlock_bh(&mfc_unres_lock); } - spin_unlock_bh(&mfc_unres_lock); } } =20 @@ -1587,7 +1597,7 @@ int ip6mr_sk_done(struct sock *sk) NETCONFA_IFINDEX_ALL, net->ipv6.devconf_all); =20 - mroute_clean_tables(mrt, false); + mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MFC); err =3D 0; break; } @@ -1703,6 +1713,20 @@ int ip6_mroute_setsockopt(struct sock *sk, int opt= name, char __user *optval, uns rtnl_unlock(); return ret; =20 + case MRT6_FLUSH: + { + int flags; + + if (optlen !=3D sizeof(flags)) + return -EINVAL; + if (get_user(flags, (int __user *)optval)) + return -EFAULT; + rtnl_lock(); + mroute_clean_tables(mrt, flags); + rtnl_unlock(); + return 0; + } + /* * Control PIM assert (to activate pim will activate assert) */ --=20 2.20.1