From nobody Wed Nov 27 21:44:44 2024 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C4E8F1D7986 for ; Mon, 7 Oct 2024 14:17:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728310654; cv=none; b=FU+It16PGBf/PNQ9BBgzHSy1m2xkH6hjKG4QSouYRWrO/DHkjUyXoTq/4P2UdJa1TaBvA+WPu2kyiXGM70NqLJJ1SeqBdzXOyetKecbfifIifNqOEDrqvP5yNrcwNgW8dzHAmqJCd87OWgnHwHH753Vxe9hC/C3KzkPtEtp1z3U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728310654; c=relaxed/simple; bh=w85rAFZ+a9VjpaEsbec1z60WY2nfBeNCdSS5loJlCIY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=U8l5hSim6cEbVUyiLcU0letCLi1hyHLQX9ciUHrJAK6O4StWqqhQfn7yWB2QGiRNs+nzK8c7yMS0LXXxSsmes0DdYayfeSyKFcPuC0z7N2V4zFdBYE3BM9zzGsOgqsQZnGBHpriEKbx/STwomaWmJyasPS3dCooOSTudsZJxQIc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from dude04.red.stw.pengutronix.de ([2a0a:edc0:0:1101:1d::ac]) by metis.whiteo.stw.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1sxoY4-0008LN-TF; Mon, 07 Oct 2024 16:17:20 +0200 From: Jonas Rebmann Date: Mon, 07 Oct 2024 16:17:11 +0200 Subject: [PATCH 1/2] net: ipv4: igmp: optimize ____ip_mc_inc_group() using mc_hash Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20241007-igmp-speedup-v1-1-6c0a387890a5@pengutronix.de> References: <20241007-igmp-speedup-v1-0-6c0a387890a5@pengutronix.de> In-Reply-To: <20241007-igmp-speedup-v1-0-6c0a387890a5@pengutronix.de> To: "David S. Miller" , David Ahern , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Madalin Bucur , Sean Anderson Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, kernel@pengutronix.de, Jonas Rebmann X-Mailer: b4 0.14.2 X-SA-Exim-Connect-IP: 2a0a:edc0:0:1101:1d::ac X-SA-Exim-Mail-From: jre@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-kernel@vger.kernel.org The runtime cost of joining a single multicast group in the current implementation of ____ip_mc_inc_group grows linearly with the number of existing memberships. This is caused by the linear search for an existing group record in the multicast address list. This linear complexity results in quadratic complexity when successively adding memberships, which becomes a performance bottleneck when setting up large numbers of multicast memberships. If available, use the existing multicast hash map mc_hash to quickly search for an existing group membership record. This leads to near-constant complexity on the addition of a new multicast record, significantly improving performance for workloads involving many multicast memberships. On profiling with a loopback device, this patch presented a speedup of around 6 when successively setting up 2000 multicast groups using setsockopt without measurable drawbacks on smaller numbers of multicast groups. Signed-off-by: Jonas Rebmann Reviewed-by: Eric Dumazet --- net/ipv4/igmp.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 9bf09de6a2e77c32f5eed565db8fd6c14bc7ea86..6a238398acc9d5684ec3d6305ef= 2a74834f5a3b3 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1437,16 +1437,32 @@ static void ip_mc_hash_remove(struct in_device *in_= dev, static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr, unsigned int mode, gfp_t gfp) { + struct ip_mc_list __rcu **mc_hash; struct ip_mc_list *im; =20 ASSERT_RTNL(); =20 - for_each_pmc_rtnl(in_dev, im) { - if (im->multiaddr =3D=3D addr) { - im->users++; - ip_mc_add_src(in_dev, &addr, mode, 0, NULL, 0); - goto out; + mc_hash =3D rtnl_dereference(in_dev->mc_hash); + if (mc_hash) { + u32 hash =3D hash_32((__force u32)addr, MC_HASH_SZ_LOG); + + for (im =3D rtnl_dereference(mc_hash[hash]); + im; + im =3D rtnl_dereference(im->next_hash)) { + if (im->multiaddr =3D=3D addr) + break; } + } else { + for_each_pmc_rtnl(in_dev, im) { + if (im->multiaddr =3D=3D addr) + break; + } + } + + if (im) { + im->users++; + ip_mc_add_src(in_dev, &addr, mode, 0, NULL, 0); + goto out; } =20 im =3D kzalloc(sizeof(*im), gfp); --=20 2.39.5 From nobody Wed Nov 27 21:44:44 2024 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C4EEA1D7992 for ; Mon, 7 Oct 2024 14:17:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728310654; cv=none; b=hsx7jaZaLn6cSckEDjhwdSwMw6aAEHA8nuHVH6z0lyGnMEW/ZMVFeYFE6jkAj7NgqVrgreJJLxQJ3nuGyq3+ywpkyiwauIcjq8pr2HJdV+7/PfVB3urT/2jRSuCj+nZnhMTdg8bbaEfGqeOcFoMQT6Bd86+NjNwWvLggSeLeKEk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728310654; c=relaxed/simple; bh=sZkmrTYr8EVyASnS0JbfcOEzrJeJOvpqLS/GrMmDYJo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Rx+L0y5iSgdugscvt4ZmTLBX0VSK1gDmxD50ySbLUCku1A5YlxtKPl8xijmTnrF+lmWL2L3Q3v+SUvzYes0zVYQVRj+zwPt1u2SetlYxL7QJwSODxdslMcBTcLop+Ke0AanmPleo+wZI0zj+59xu++hyMwx1biaNxcQFOE0/lck= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from dude04.red.stw.pengutronix.de ([2a0a:edc0:0:1101:1d::ac]) by metis.whiteo.stw.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1sxoY4-0008LN-Uu; Mon, 07 Oct 2024 16:17:20 +0200 From: Jonas Rebmann Date: Mon, 07 Oct 2024 16:17:12 +0200 Subject: [PATCH 2/2] net: dpaa: use __dev_mc_sync in dpaa_set_rx_mode() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20241007-igmp-speedup-v1-2-6c0a387890a5@pengutronix.de> References: <20241007-igmp-speedup-v1-0-6c0a387890a5@pengutronix.de> In-Reply-To: <20241007-igmp-speedup-v1-0-6c0a387890a5@pengutronix.de> To: "David S. Miller" , David Ahern , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Madalin Bucur , Sean Anderson Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, kernel@pengutronix.de, Jonas Rebmann X-Mailer: b4 0.14.2 X-SA-Exim-Connect-IP: 2a0a:edc0:0:1101:1d::ac X-SA-Exim-Mail-From: jre@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-kernel@vger.kernel.org The original driver first unregisters then re-registers all multicast addresses in the struct net_device_ops::ndo_set_rx_mode() callback. As the networking stack calls ndo_set_rx_mode() if a single multicast address change occurs, a significant amount of time may be used to first unregister and then re-register unchanged multicast addresses. This leads to performance issues when tracking large numbers of multicast addresses. Replace the unregister and register loop and the hand crafted mc_addr_list list handling with __dev_mc_sync(), to only update entries which have changed. On profiling with an fsl_dpa NIC, this patch presented a speedup of around 40 when successively setting up 2000 multicast groups using setsockopt(), without drawbacks on smaller numbers of multicast groups. Signed-off-by: Jonas Rebmann Reviewed-by: Sean Anderson --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 20 +++++++++-- drivers/net/ethernet/freescale/fman/fman_dtsec.c | 1 - drivers/net/ethernet/freescale/fman/fman_memac.c | 1 - drivers/net/ethernet/freescale/fman/fman_tgec.c | 1 - drivers/net/ethernet/freescale/fman/mac.c | 42 --------------------= ---- drivers/net/ethernet/freescale/fman/mac.h | 2 -- 6 files changed, 18 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/e= thernet/freescale/dpaa/dpaa_eth.c index 6b9b6d72db98c22b9c104833b3c8c675931fd1aa..ac06b01fe93401b0416cd6a654b= ac2cb40ce12aa 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -463,6 +463,22 @@ static int dpaa_set_mac_address(struct net_device *net= _dev, void *addr) return 0; } =20 +static int dpaa_addr_sync(struct net_device *net_dev, const u8 *addr) +{ + const struct dpaa_priv *priv =3D netdev_priv(net_dev); + + return priv->mac_dev->add_hash_mac_addr(priv->mac_dev->fman_mac, + (enet_addr_t *)addr); +} + +static int dpaa_addr_unsync(struct net_device *net_dev, const u8 *addr) +{ + const struct dpaa_priv *priv =3D netdev_priv(net_dev); + + return priv->mac_dev->remove_hash_mac_addr(priv->mac_dev->fman_mac, + (enet_addr_t *)addr); +} + static void dpaa_set_rx_mode(struct net_device *net_dev) { const struct dpaa_priv *priv; @@ -490,9 +506,9 @@ static void dpaa_set_rx_mode(struct net_device *net_dev) err); } =20 - err =3D priv->mac_dev->set_multi(net_dev, priv->mac_dev); + err =3D __dev_mc_sync(net_dev, dpaa_addr_sync, dpaa_addr_unsync); if (err < 0) - netif_err(priv, drv, net_dev, "mac_dev->set_multi() =3D %d\n", + netif_err(priv, drv, net_dev, "dpaa_addr_sync() =3D %d\n", err); } =20 diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net= /ethernet/freescale/fman/fman_dtsec.c index 3088da7adf0f846744079107f7f72fea74114f4a..85617bb94959f3789d75766bce8= f3e11a7b321d5 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@ -1415,7 +1415,6 @@ int dtsec_initialization(struct mac_device *mac_dev, mac_dev->set_exception =3D dtsec_set_exception; mac_dev->set_allmulti =3D dtsec_set_allmulti; mac_dev->set_tstamp =3D dtsec_set_tstamp; - mac_dev->set_multi =3D fman_set_multi; mac_dev->enable =3D dtsec_enable; mac_dev->disable =3D dtsec_disable; =20 diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net= /ethernet/freescale/fman/fman_memac.c index 796e6f4e583d18be6069f78af15fbedf9557378e..3925441143fac9eecc40ea45d05= f36be63b16a78 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -1087,7 +1087,6 @@ int memac_initialization(struct mac_device *mac_dev, mac_dev->set_exception =3D memac_set_exception; mac_dev->set_allmulti =3D memac_set_allmulti; mac_dev->set_tstamp =3D memac_set_tstamp; - mac_dev->set_multi =3D fman_set_multi; mac_dev->enable =3D memac_enable; mac_dev->disable =3D memac_disable; =20 diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.c b/drivers/net/= ethernet/freescale/fman/fman_tgec.c index c2261d26db5b9374a5e52bac41c25ed8831f4822..fecfca6eba03e571cfb569b8aad= 20dc3fa8dc1c7 100644 --- a/drivers/net/ethernet/freescale/fman/fman_tgec.c +++ b/drivers/net/ethernet/freescale/fman/fman_tgec.c @@ -771,7 +771,6 @@ int tgec_initialization(struct mac_device *mac_dev, mac_dev->set_exception =3D tgec_set_exception; mac_dev->set_allmulti =3D tgec_set_allmulti; mac_dev->set_tstamp =3D tgec_set_tstamp; - mac_dev->set_multi =3D fman_set_multi; mac_dev->enable =3D tgec_enable; mac_dev->disable =3D tgec_disable; =20 diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethern= et/freescale/fman/mac.c index 43f4ad29eadd495ce7f4861b3e635e22379ddc72..974d2e7e131c087ddbb41dcb906= f6144a150db46 100644 --- a/drivers/net/ethernet/freescale/fman/mac.c +++ b/drivers/net/ethernet/freescale/fman/mac.c @@ -32,8 +32,6 @@ MODULE_DESCRIPTION("FSL FMan MAC API based driver"); struct mac_priv_s { u8 cell_index; struct fman *fman; - /* List of multicast addresses */ - struct list_head mc_addr_list; struct platform_device *eth_dev; u16 speed; }; @@ -57,44 +55,6 @@ static void mac_exception(struct mac_device *mac_dev, __func__, ex); } =20 -int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev) -{ - struct mac_priv_s *priv; - struct mac_address *old_addr, *tmp; - struct netdev_hw_addr *ha; - int err; - enet_addr_t *addr; - - priv =3D mac_dev->priv; - - /* Clear previous address list */ - list_for_each_entry_safe(old_addr, tmp, &priv->mc_addr_list, list) { - addr =3D (enet_addr_t *)old_addr->addr; - err =3D mac_dev->remove_hash_mac_addr(mac_dev->fman_mac, addr); - if (err < 0) - return err; - - list_del(&old_addr->list); - kfree(old_addr); - } - - /* Add all the addresses from the new list */ - netdev_for_each_mc_addr(ha, net_dev) { - addr =3D (enet_addr_t *)ha->addr; - err =3D mac_dev->add_hash_mac_addr(mac_dev->fman_mac, addr); - if (err < 0) - return err; - - tmp =3D kmalloc(sizeof(*tmp), GFP_ATOMIC); - if (!tmp) - return -ENOMEM; - - ether_addr_copy(tmp->addr, ha->addr); - list_add(&tmp->list, &priv->mc_addr_list); - } - return 0; -} - static DEFINE_MUTEX(eth_lock); =20 static struct platform_device *dpaa_eth_add_device(int fman_id, @@ -181,8 +141,6 @@ static int mac_probe(struct platform_device *_of_dev) mac_dev->priv =3D priv; mac_dev->dev =3D dev; =20 - INIT_LIST_HEAD(&priv->mc_addr_list); - /* Get the FM node */ dev_node =3D of_get_parent(mac_node); if (!dev_node) { diff --git a/drivers/net/ethernet/freescale/fman/mac.h b/drivers/net/ethern= et/freescale/fman/mac.h index fe747915cc73792b66d8bfe4339894476fc841af..be9d48aad5ef16d6826e0dc3c93= b8c456cdfa925 100644 --- a/drivers/net/ethernet/freescale/fman/mac.h +++ b/drivers/net/ethernet/freescale/fman/mac.h @@ -39,8 +39,6 @@ struct mac_device { int (*change_addr)(struct fman_mac *mac_dev, const enet_addr_t *enet_addr= ); int (*set_allmulti)(struct fman_mac *mac_dev, bool enable); int (*set_tstamp)(struct fman_mac *mac_dev, bool enable); - int (*set_multi)(struct net_device *net_dev, - struct mac_device *mac_dev); int (*set_exception)(struct fman_mac *mac_dev, enum fman_mac_exceptions exception, bool enable); int (*add_hash_mac_addr)(struct fman_mac *mac_dev, --=20 2.39.5