From nobody Mon Apr 13 21:40:00 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 A2180191F94; Wed, 4 Mar 2026 13:19:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772630348; cv=none; b=Z7B5muQUKFoHCE9f7E+8kko+etEQw8gSs56ss+BJaBsUqy7+D+6TY4nfspMQODRQ9oHdAZ74iOXX7OCMPSjVFoXIS5+uy8mh21wLR8mc5MqgXmgF7FpMKGwOkjwQqtWAy7/9tOfiK3Gm332IN0BBtTxghHaKVGKwjWpK29Ed7nw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772630348; c=relaxed/simple; bh=LP4IF/u3I83dDFvCB9HkHytrNq68YMX/VcY+pJgdwZQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qmGO7VZQRV94T0A2ZCMhV6BQFAOMm/5BikdFGoQZLKpikqThDHaq6FrBum0X9s/Iq7EifSLQdpI6FC+nPtaY5VyQ5A+THGRzZx2WN+ikzSwzQ1/be2WV+qt87yr/pOlL7SV3yaNLve06I7cSqRgI+perLPqmG97gEApSPsas0ic= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=n0Ta6HwS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="n0Ta6HwS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AF7C6C2BC87; Wed, 4 Mar 2026 13:19:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772630348; bh=LP4IF/u3I83dDFvCB9HkHytrNq68YMX/VcY+pJgdwZQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=n0Ta6HwSM1YGeUAggNheujmYROwkNzICilL+zsCU2ErryqxyqG3yS3qj24U4Z4Qma kU7JK8Eg/ypJ6L4siRngvd8eXwLKMLEt7ts74MPVrdOoL7I/n1lMLBGlptM85zS3FE JOjLFMKwUDdb9nV7g2xp1Hs+NCzDIoyzRrpoLX6Gb+kZ/+an0eSVJ8Aw/ab6RtQBL4 Fjo9mB1Q6Ze5HFdqOcsRKJ50Z8XehtDB5mz7iRVm0ocjOXMWAs1r/3Bhc6dvsflbQJ ekLh9lVl9S/ypOr2MQ0lk+MHfajkQB0xCzG9MU5ro/p4ppRi2dTpL2syuswT3AHJq4 1EcQcsp/VGb9A== From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= To: Michael Chan , Pavan Chebbi , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= , Willem de Bruijn Subject: [PATCH net-next v2 1/3] ethtool: Add RSS indirection table resize helpers Date: Wed, 4 Mar 2026 14:18:51 +0100 Message-ID: <20260304131855.3225539-2-bjorn@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260304131855.3225539-1-bjorn@kernel.org> References: <20260304131855.3225539-1-bjorn@kernel.org> 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 The core locks ctx->indir_size when an RSS context is created. Some NICs (e.g. bnxt) change their indirection table size based on the channel count, because the hardware table is a shared resource. This forces drivers to reject channel changes when RSS contexts exist. Add helpers to resize indirection tables: ethtool_rxfh_can_resize() checks whether a table can be resized without modifying it. ethtool_rxfh_resize() resizes a raw u32 table in place. Folding (shrink) requires the table to be periodic at the new size; non-periodic tables are rejected. Unfolding (grow) replicates the existing pattern. Sizes must be multiples of each other. ethtool_rxfh_ctxs_can_resize() validates all non-default RSS contexts can be resized. ethtool_rxfh_ctxs_resize() applies the resize and sends ETHTOOL_MSG_RSS_NTF per resized context after releasing rss_lock. No reallocation is needed because ethtool_rxfh_ctx_alloc() reserves space for rxfh_indir_space entries, and key_off is based on that maximum. Signed-off-by: Bj=C3=B6rn T=C3=B6pel Tested-by: Pavan Chebbi --- include/linux/ethtool.h | 4 ++ net/ethtool/common.c | 146 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 798abec67a1b..57f480444607 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -214,6 +214,10 @@ static inline u8 *ethtool_rxfh_context_key(struct etht= ool_rxfh_context *ctx) } =20 void ethtool_rxfh_context_lost(struct net_device *dev, u32 context_id); +int ethtool_rxfh_can_resize(const u32 *tbl, u32 old_size, u32 new_size); +int ethtool_rxfh_resize(u32 *tbl, u32 old_size, u32 new_size); +int ethtool_rxfh_ctxs_can_resize(struct net_device *dev, u32 new_indir_siz= e); +void ethtool_rxfh_ctxs_resize(struct net_device *dev, u32 new_indir_size); =20 struct link_mode_info { int speed; diff --git a/net/ethtool/common.c b/net/ethtool/common.c index e252cf20c22f..5041b7ebf50a 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -1204,6 +1204,152 @@ void ethtool_rxfh_context_lost(struct net_device *d= ev, u32 context_id) } EXPORT_SYMBOL(ethtool_rxfh_context_lost); =20 +static bool rxfh_indir_is_periodic(const u32 *tbl, u32 old_size, u32 new_s= ize) +{ + u32 i; + + for (i =3D new_size; i < old_size; i++) + if (tbl[i] !=3D tbl[i % new_size]) + return false; + return true; +} + +/** + * ethtool_rxfh_can_resize - Check if an indirection table can be resized + * @tbl: indirection table + * @old_size: current number of entries in the table + * @new_size: desired number of entries + * + * Validate that @tbl can be resized from @old_size to @new_size without + * data loss. Read-only; does not modify the table. + * + * Return: 0 if resize is possible, -%EINVAL otherwise. + */ +int ethtool_rxfh_can_resize(const u32 *tbl, u32 old_size, u32 new_size) +{ + if (new_size =3D=3D old_size) + return 0; + + if (new_size < old_size) { + if (old_size % new_size) + return -EINVAL; + if (!rxfh_indir_is_periodic(tbl, old_size, new_size)) + return -EINVAL; + return 0; + } + + if (new_size % old_size) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(ethtool_rxfh_can_resize); + +/* Resize without validation; caller must have called can_resize first */ +static void __ethtool_rxfh_resize(u32 *tbl, u32 old_size, u32 new_size) +{ + u32 i; + + /* Grow: replicate existing pattern; shrink is a no-op on the data */ + for (i =3D old_size; i < new_size; i++) + tbl[i] =3D tbl[i % old_size]; +} + +/** + * ethtool_rxfh_resize - Fold or unfold an indirection table + * @tbl: indirection table (must have room for max(old_size, new_size) ent= ries) + * @old_size: current number of entries in the table + * @new_size: desired number of entries + * + * Resize an RSS indirection table in place. When folding (shrinking), + * the table must be periodic with period @new_size; otherwise the + * operation is rejected. When unfolding (growing), the existing + * pattern is replicated. Both directions require the sizes to be + * multiples of each other. + * + * Return: 0 on success, -%EINVAL on failure (no mutation on failure). + */ +int ethtool_rxfh_resize(u32 *tbl, u32 old_size, u32 new_size) +{ + int ret; + + ret =3D ethtool_rxfh_can_resize(tbl, old_size, new_size); + if (ret) + return ret; + + __ethtool_rxfh_resize(tbl, old_size, new_size); + return 0; +} +EXPORT_SYMBOL(ethtool_rxfh_resize); + +/** + * ethtool_rxfh_ctxs_can_resize - Validate resize for all RSS contexts + * @dev: network device + * @new_indir_size: new indirection table size + * + * Validate that the indirection tables of all non-default RSS contexts + * can be resized to @new_indir_size. Read-only; does not modify any + * context. Intended to be paired with ethtool_rxfh_ctxs_resize(). + * + * Return: 0 if all contexts can be resized, negative errno on failure. + */ +int ethtool_rxfh_ctxs_can_resize(struct net_device *dev, + u32 new_indir_size) +{ + struct ethtool_rxfh_context *ctx; + unsigned long context; + int ret; + + if (!dev->ethtool_ops->rxfh_indir_space || + new_indir_size > dev->ethtool_ops->rxfh_indir_space) + return -EINVAL; + + mutex_lock(&dev->ethtool->rss_lock); + xa_for_each(&dev->ethtool->rss_ctx, context, ctx) { + u32 *indir =3D ethtool_rxfh_context_indir(ctx); + + ret =3D ethtool_rxfh_can_resize(indir, ctx->indir_size, + new_indir_size); + if (ret) + goto unlock; + } + ret =3D 0; +unlock: + mutex_unlock(&dev->ethtool->rss_lock); + return ret; +} +EXPORT_SYMBOL(ethtool_rxfh_ctxs_can_resize); + +/** + * ethtool_rxfh_ctxs_resize - Resize all RSS context indirection tables + * @dev: network device + * @new_indir_size: new indirection table size + * + * Resize the indirection table of every non-default RSS context to + * @new_indir_size. Caller must have validated with + * ethtool_rxfh_ctxs_can_resize() first. An %ETHTOOL_MSG_RSS_NTF is + * sent for each resized context. + * + * Notifications are sent outside the RSS lock to avoid holding the + * mutex during notification delivery. + */ +void ethtool_rxfh_ctxs_resize(struct net_device *dev, u32 new_indir_size) +{ + struct ethtool_rxfh_context *ctx; + unsigned long context; + + mutex_lock(&dev->ethtool->rss_lock); + xa_for_each(&dev->ethtool->rss_ctx, context, ctx) { + __ethtool_rxfh_resize(ethtool_rxfh_context_indir(ctx), + ctx->indir_size, new_indir_size); + ctx->indir_size =3D new_indir_size; + } + mutex_unlock(&dev->ethtool->rss_lock); + + xa_for_each(&dev->ethtool->rss_ctx, context, ctx) + ethtool_rss_notify(dev, ETHTOOL_MSG_RSS_NTF, context); +} +EXPORT_SYMBOL(ethtool_rxfh_ctxs_resize); + enum ethtool_link_medium ethtool_str_to_medium(const char *str) { int i; --=20 2.53.0 From nobody Mon Apr 13 21:40:00 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 49DE3306B05; Wed, 4 Mar 2026 13:19:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772630352; cv=none; b=Tqv8Mlj6bw/RmcTwUtrUt2JIny5Lq+ePTLhB/OVvZM8S4qWPa26vupZU6vQqYwGTt+mUkgIrb+5p9XnCX1heshvEDPOQsOB1mNMX9kopiEBZDpVdDkTdZ49W3/ksJJe18BL5bwx8lP0zkjR9d5zRUXBscb5QM1bw//k+xioUfHI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772630352; c=relaxed/simple; bh=liM9aKRaCeLeCmRb8zzZkPZAQMDFRbi1yJdJ/iV4U4Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jqyltzrMO1cRPVTwMFiolxNdu8QrP8i9pVUwhZAhyx4x3kDxOBwpaNmxjyK0Q1tB+ECPFgwq0H0khekwyN+5Bt/XnFhGjfcgaPDPxW5r1/sjH2utImdUWnZ7SGQYmqJeJR4oN2vbKnVq4avdyitarzy7/kIJb3fqguewHqpgJnQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AL6fWosZ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AL6fWosZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 056C5C19423; Wed, 4 Mar 2026 13:19:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772630351; bh=liM9aKRaCeLeCmRb8zzZkPZAQMDFRbi1yJdJ/iV4U4Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AL6fWosZofn9K1Pxv92DjCtG1Lr9mlCFKH7SKz9AAzH9Dtb5PjQV9CWKgEJ+HCvfe dMhhSjNGstHSYsuYqKbuFzEECVi6JxpBe5yhLq8hEOb4vFle9v1zPfoXZ44/sFxq5Q /65Ifs0q0ka0gNDluMIj9oedS3ceT8yRsKDLb2kjKcsrRZu12MhtpenYleTK7xOC78 /4DVKOmEb4kCyia61wp4f9L78FHSFoHjw4YD7/0tVy0FcYih5WkBiDoR1yRl35VT6h X1pwh2UoEJ/LZAQHRSvb18X8CY5RH6f/xglC3zFrekW4QN0Kp0eMRUk/iMMXDIrH+N iL7WriPwQloAw== From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= To: Michael Chan , Pavan Chebbi , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= , Willem de Bruijn Subject: [PATCH net-next v2 2/3] bnxt_en: Resize RSS contexts on channel count change Date: Wed, 4 Mar 2026 14:18:52 +0100 Message-ID: <20260304131855.3225539-3-bjorn@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260304131855.3225539-1-bjorn@kernel.org> References: <20260304131855.3225539-1-bjorn@kernel.org> 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 bnxt_set_channels() rejects channel changes that alter the RSS table size when IFF_RXFH_CONFIGURED is set, because non-default context sizes were locked at creation. Replace the rejection with the new resize helpers. All validation runs before the device is closed; actual resize is deferred until after bnxt_close_nic(): 1. ethtool_rxfh_can_resize() checks context 0. 2. ethtool_rxfh_ctxs_can_resize() validates all non-default contexts. 3. After bnxt_close_nic(), ethtool_rxfh_resize() applies context 0 changes, and ethtool_rxfh_ctxs_resize() resizes non-default contexts. RSS table size only changes on P5 chips with older firmware; newer firmware always uses the largest table size. When context 0 uses defaults (!IFF_RXFH_CONFIGURED), steps 1 and 3 are skipped; the driver regenerates the table via bnxt_set_dflt_rss_indir_tbl(). Signed-off-by: Bj=C3=B6rn T=C3=B6pel Tested-by: Pavan Chebbi --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/ne= t/ethernet/broadcom/bnxt/bnxt_ethtool.c index 26fcd52c8a61..1bb0dd5bb683 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -942,6 +942,7 @@ static int bnxt_set_channels(struct net_device *dev, { struct bnxt *bp =3D netdev_priv(dev); int req_tx_rings, req_rx_rings, tcs; + u32 new_tbl_size =3D 0, old_tbl_size; bool sh =3D false; int tx_xdp =3D 0; int rc =3D 0; @@ -977,19 +978,33 @@ static int bnxt_set_channels(struct net_device *dev, tx_xdp =3D req_rx_rings; } =20 - if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) !=3D - bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) && - netif_is_rxfh_configured(dev)) { - netdev_warn(dev, "RSS table size change required, RSS table entries must= be default to proceed\n"); - return -EINVAL; - } - rc =3D bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp); if (rc) { netdev_warn(dev, "Unable to allocate the requested rings\n"); return rc; } =20 + /* RSS table size only changes on P5 chips with older firmware; + * newer firmware always uses the largest table size. + */ + if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) !=3D + bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings)) { + new_tbl_size =3D bnxt_get_nr_rss_ctxs(bp, req_rx_rings) * + BNXT_RSS_TABLE_ENTRIES_P5; + old_tbl_size =3D bnxt_get_rxfh_indir_size(dev); + + if (netif_is_rxfh_configured(dev) && + ethtool_rxfh_can_resize(bp->rss_indir_tbl, + old_tbl_size, new_tbl_size)) { + netdev_warn(dev, "RSS table resize not possible\n"); + return -EINVAL; + } + + rc =3D ethtool_rxfh_ctxs_can_resize(dev, new_tbl_size); + if (rc) + return rc; + } + if (netif_running(dev)) { if (BNXT_PF(bp)) { /* TODO CHIMP_FW: Send message to all VF's @@ -999,6 +1014,13 @@ static int bnxt_set_channels(struct net_device *dev, bnxt_close_nic(bp, true, false); } =20 + if (new_tbl_size) { + if (netif_is_rxfh_configured(dev)) + ethtool_rxfh_resize(bp->rss_indir_tbl, + old_tbl_size, new_tbl_size); + ethtool_rxfh_ctxs_resize(dev, new_tbl_size); + } + if (sh) { bp->flags |=3D BNXT_FLAG_SHARED_RINGS; bp->rx_nr_rings =3D channel->combined_count; --=20 2.53.0 From nobody Mon Apr 13 21:40:00 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 7DA71260592; Wed, 4 Mar 2026 13:19:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772630355; cv=none; b=qM50dVb26f19a/eViJacqbiaXnOrOX2U6mSBRqSndWWqsPLU3kHXvrf4iPXRfGnXncqm0sdopJXY4qQvPXMpFb/esehlwSMcN9l5RZqKh608sU1HP7VOOWzZSwjWFmqCZNuzFN8SvqDLKt/k83c7x3yW0zFIvaeV9w0KVPEn0T8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772630355; c=relaxed/simple; bh=iO9teAmlJC4dUs2VeHJVVKZOS0flR2zqooYmkpkZims=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Pa0nWuKXK4aS6wG98d56NJo8ARpW8w1HX8rpd72D/cTqPM6WLr+ptgqaB5cFdEglBJHmsk0hT52LlaRAQu+bhdT45Ltqsxo9cG28Da7OBgUFyHuzgJuAmZgRvq4GAGPMFGtW2kVDdqlG5v2cFGz9TWgNIvSvZqInvtlpx10FGP4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NBycilZh; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NBycilZh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 527C0C2BC9E; Wed, 4 Mar 2026 13:19:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772630355; bh=iO9teAmlJC4dUs2VeHJVVKZOS0flR2zqooYmkpkZims=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NBycilZh4WQO0JA7EPpRslcT5gNMaR8Q3BygT4jSh/T4S7/yTLOknpQayaecjXz7y 40eE7UKGjbHCUtuBlUMkAxBidZxx1Z84n009moi5oIZoulXRtKcuAuA0n0PfTKCuey JEq+aBi+Kk8hGlssJ9bK9GIxSsXhOj/JKTPP/EM/7NKSPkp+jIdV1+A0qBT1xePBB2 Vl2kzksllToQOPLWLZoVnY3rZNqk8jNhDKf2P8SMPJ4THzRCU/w2ci10nRmkO7D42F cZrdnIgowPweqUkHLm3LRKOnFqTBm1q2bPIThDq5A+IeUhk7KI3+4lo+zNZaljUxBy J/NtbmBhpkiUQ== From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= To: Michael Chan , Pavan Chebbi , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= , Willem de Bruijn Subject: [PATCH net-next v2 3/3] selftests: rss_drv: Add RSS indirection table resize tests Date: Wed, 4 Mar 2026 14:18:53 +0100 Message-ID: <20260304131855.3225539-4-bjorn@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260304131855.3225539-1-bjorn@kernel.org> References: <20260304131855.3225539-1-bjorn@kernel.org> 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 Add resize tests to rss_drv.py. Devices without dynamic table sizing are skipped via _require_dynamic_indir_size(). resize_periodic: set a periodic table (equal 4), shrink channels to fold, grow back to unfold. Check the exact pattern is preserved. Has main and non-default context variants. resize_nonperiodic_reject: set a non-periodic table (equal N), verify that channel reduction is rejected. Signed-off-by: Bj=C3=B6rn T=C3=B6pel Tested-by: Pavan Chebbi --- .../selftests/drivers/net/hw/rss_drv.py | 163 +++++++++++++++++- 1 file changed, 159 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/rss_drv.py b/tools/test= ing/selftests/drivers/net/hw/rss_drv.py index 2d1a33189076..9763760f8306 100755 --- a/tools/testing/selftests/drivers/net/hw/rss_drv.py +++ b/tools/testing/selftests/drivers/net/hw/rss_drv.py @@ -5,9 +5,9 @@ Driver-related behavior tests for RSS. """ =20 -from lib.py import ksft_run, ksft_exit, ksft_ge -from lib.py import ksft_variants, KsftNamedVariant, KsftSkipEx -from lib.py import defer, ethtool +from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge +from lib.py import ksft_variants, KsftNamedVariant, KsftSkipEx, ksft_raises +from lib.py import defer, ethtool, CmdExitFailure from lib.py import EthtoolFamily, NlError from lib.py import NetDrvEnv =20 @@ -45,6 +45,18 @@ def _maybe_create_context(cfg, create_context): return ctx_id =20 =20 +def _require_dynamic_indir_size(cfg, ch_max): + """Skip if the device does not dynamically size its indirection table.= """ + ethtool(f"-X {cfg.ifname} default") + ethtool(f"-L {cfg.ifname} combined 2") + small =3D len(_get_rss(cfg)['rss-indirection-table']) + ethtool(f"-L {cfg.ifname} combined {ch_max}") + large =3D len(_get_rss(cfg)['rss-indirection-table']) + + if small =3D=3D large: + raise KsftSkipEx("Device does not dynamically size indirection tab= le") + + @ksft_variants([ KsftNamedVariant("main", False), KsftNamedVariant("ctx", True), @@ -76,11 +88,154 @@ def indir_size_4x(cfg, create_context): _test_rss_indir_size(cfg, test_max, context=3Dctx_id) =20 =20 +@ksft_variants([ + KsftNamedVariant("main", False), + KsftNamedVariant("ctx", True), +]) +def resize_periodic(cfg, create_context): + """Test that a periodic indirection table survives channel changes. + + Set a non-default periodic table ([3, 2, 1, 0] x N) via netlink, + reduce channels to trigger a fold, then increase to trigger an + unfold. Using a reversed pattern (instead of [0, 1, 2, 3]) ensures + the test can distinguish a correct fold from a driver that silently + resets the table to defaults. Verify the exact pattern is preserved + and the size tracks the channel count. + """ + channels =3D cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifind= ex}}) + ch_max =3D channels.get('combined-max', 0) + qcnt =3D channels['combined-count'] + + if ch_max < 4: + raise KsftSkipEx(f"Not enough queues for the test: max=3D{ch_max}") + + defer(ethtool, f"-L {cfg.ifname} combined {qcnt}") + + _require_dynamic_indir_size(cfg, ch_max) + + ctx_id =3D _maybe_create_context(cfg, create_context) + + # Set a non-default periodic pattern via netlink + rss =3D _get_rss(cfg, context=3Dctx_id) + orig_size =3D len(rss['rss-indirection-table']) + pattern =3D [3, 2, 1, 0] * (orig_size // 4) + req =3D {'header': {'dev-index': cfg.ifindex}, 'indir': pattern} + if ctx_id: + req['context'] =3D ctx_id + else: + defer(ethtool, f"-X {cfg.ifname} default") + cfg.ethnl.rss_set(req) + + # Shrink =E2=80=94 should fold + ethtool(f"-L {cfg.ifname} combined 4") + rss =3D _get_rss(cfg, context=3Dctx_id) + indir =3D rss['rss-indirection-table'] + + ksft_ge(orig_size, len(indir), "Table did not shrink") + ksft_eq(indir, [3, 2, 1, 0] * (len(indir) // 4), + "Folded table has wrong pattern") + + # Grow back =E2=80=94 should unfold + ethtool(f"-L {cfg.ifname} combined {ch_max}") + rss =3D _get_rss(cfg, context=3Dctx_id) + indir =3D rss['rss-indirection-table'] + + ksft_eq(len(indir), orig_size, "Table size not restored") + ksft_eq(indir, [3, 2, 1, 0] * (len(indir) // 4), + "Unfolded table has wrong pattern") + + +@ksft_variants([ + KsftNamedVariant("main", False), + KsftNamedVariant("ctx", True), +]) +def resize_nonperiodic_reject(cfg, create_context): + """Test that a non-periodic table blocks channel reduction. + + Set equal weight across all queues so the table is not periodic + at any smaller size, then verify channel reduction is rejected. + An additional context with a periodic table is created to verify + that validation catches the non-periodic one even when others + are fine. + """ + channels =3D cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifind= ex}}) + ch_max =3D channels.get('combined-max', 0) + qcnt =3D channels['combined-count'] + + if ch_max < 4: + raise KsftSkipEx(f"Not enough queues for the test: max=3D{ch_max}") + + defer(ethtool, f"-L {cfg.ifname} combined {qcnt}") + + _require_dynamic_indir_size(cfg, ch_max) + + ctx_id =3D _maybe_create_context(cfg, create_context) + ctx_ref =3D f"context {ctx_id}" if ctx_id else "" + + # Create an extra context with a periodic (foldable) table so that + # the validation must iterate all contexts to find the bad one. + extra_ctx =3D _maybe_create_context(cfg, True) + ethtool(f"-X {cfg.ifname} context {extra_ctx} equal 2") + + ethtool(f"-X {cfg.ifname} {ctx_ref} equal {ch_max}") + if not create_context: + defer(ethtool, f"-X {cfg.ifname} default") + + with ksft_raises(CmdExitFailure): + ethtool(f"-L {cfg.ifname} combined 2") + + +@ksft_variants([ + KsftNamedVariant("main", False), + KsftNamedVariant("ctx", True), +]) +def resize_nonperiodic_no_corruption(cfg, create_context): + """Test that a failed resize does not corrupt table or channel count. + + Set a non-periodic table, attempt a channel reduction (which must + fail), then verify both the indirection table contents and the + channel count are unchanged. + """ + channels =3D cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifind= ex}}) + ch_max =3D channels.get('combined-max', 0) + qcnt =3D channels['combined-count'] + + if ch_max < 4: + raise KsftSkipEx(f"Not enough queues for the test: max=3D{ch_max}") + + defer(ethtool, f"-L {cfg.ifname} combined {qcnt}") + + _require_dynamic_indir_size(cfg, ch_max) + + ctx_id =3D _maybe_create_context(cfg, create_context) + ctx_ref =3D f"context {ctx_id}" if ctx_id else "" + + ethtool(f"-X {cfg.ifname} {ctx_ref} equal {ch_max}") + if not create_context: + defer(ethtool, f"-X {cfg.ifname} default") + + rss_before =3D _get_rss(cfg, context=3Dctx_id) + + with ksft_raises(CmdExitFailure): + ethtool(f"-L {cfg.ifname} combined 2") + + rss_after =3D _get_rss(cfg, context=3Dctx_id) + ksft_eq(rss_after['rss-indirection-table'], + rss_before['rss-indirection-table'], + "Indirection table corrupted after failed resize") + + channels =3D cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifind= ex}}) + ksft_eq(channels['combined-count'], ch_max, + "Channel count changed after failed resize") + + def main() -> None: """ Ksft boiler plate main """ with NetDrvEnv(__file__) as cfg: cfg.ethnl =3D EthtoolFamily() - ksft_run([indir_size_4x], args=3D(cfg, )) + ksft_run([indir_size_4x, resize_periodic, + resize_nonperiodic_reject, + resize_nonperiodic_no_corruption], args=3D(cfg, )) ksft_exit() =20 =20 --=20 2.53.0