From nobody Thu Apr 9 13:23:45 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 77AD830F812; Sun, 8 Mar 2026 13:12:28 +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=1772975548; cv=none; b=NOKt+pXW6Gj1JtDSuMgK8Iv3Ca7cm03ieK+0CPnSmk0VxuyeKvZ+CatjHP8rMKCunJJLVmf5R9WKQ4vrcvLak+Z1bRCWtwwJozfelWx6cBf9S3iZ3kjXuDbYONtrQJSDDoooZlkEPdsVKcwXzZwq5Qy74imMoq/J5HTVazWF/7w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772975548; c=relaxed/simple; bh=FvJKbZgamfnmKxUUtbTe6ppykVXHPJ9khlH2c7HuyFk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cLN4znszP+PeL3ebsd0Xh6O92b5pI6k+78AmHegtjx6TJZT1jEtNUnBKhfCoTVwzcz3K5WgS3nwB36zDvpJ64NI/eNyksNGjtPaFp0WFgKkBZpNzwDn6i+/NjkMc0QfZaob47/XMtXUb8qhi6vjq4KngNhs/Mu3F1ZCljA8dvJM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=sM9ApWEX; 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="sM9ApWEX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3B31BC116C6; Sun, 8 Mar 2026 13:12:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772975548; bh=FvJKbZgamfnmKxUUtbTe6ppykVXHPJ9khlH2c7HuyFk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sM9ApWEX6RYA69c3kGZaYmhHIZPmN0lryZ+tIqPxt6rJQZPsrpyiiIj3QqjQGMarx KcGhPVNfdnbSovedWbXxRpCLIyZcUi4Z9xf8kzqqv8Q5ox0XqYpLBxAMH2FWwF2CR3 9+r967VdwMslccAUe6CZAZtJSP7XIrRCsioT/5NgzezMRXWU73X23M0++3pScSZQOY XqOMpOrURgXSsEiOcGU+2EWFm633winBqC8/B/yFDiod+WSRQRIy2Hu21chWgoMX50 lPBh+D60+gnldb5EHgHsm6Pkt9BAAbxXVHQQ4ikaK954LnWZGfz+zLU5ikkeapDV/h H8QK/PF3D5c5w== 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 v3 1/3] ethtool: Add RSS indirection table resize helpers Date: Sun, 8 Mar 2026 14:12:15 +0100 Message-ID: <20260308131218.3172332-2-bjorn@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260308131218.3172332-1-bjorn@kernel.org> References: <20260308131218.3172332-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. Tested-by: Pavan Chebbi Signed-off-by: Bj=C3=B6rn T=C3=B6pel --- include/linux/ethtool.h | 4 ++ net/ethtool/common.c | 143 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 83c375840835..e2c4aa0a3348 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); +bool 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..ad6056297479 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -1204,6 +1204,149 @@ 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: true if resize is possible, false otherwise. + */ +bool ethtool_rxfh_can_resize(const u32 *tbl, u32 old_size, u32 new_size) +{ + if (new_size =3D=3D old_size) + return true; + + if (new_size < old_size) { + if (old_size % new_size) + return false; + if (!rxfh_indir_is_periodic(tbl, old_size, new_size)) + return false; + return true; + } + + if (new_size % old_size) + return false; + return true; +} +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) +{ + if (!ethtool_rxfh_can_resize(tbl, old_size, new_size)) + return -EINVAL; + + __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 =3D 0; + + 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); + + if (!ethtool_rxfh_can_resize(indir, ctx->indir_size, + new_indir_size)) { + ret =3D -EINVAL; + goto unlock; + } + } +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 Thu Apr 9 13:23:45 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 B747536212B; Sun, 8 Mar 2026 13:12:31 +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=1772975551; cv=none; b=snsWUMyeZClXWSLjhOwk+9f9fPvmzQGt59o96rOt0cdL6CiqNQAYQKMCh6a4dwWT09BcSzm1HWzvRgyDL95FLU6Rge5M/FxBwTDcpctoj3Eky4Y7b+Z86Pt9VVe5apBXnCTkd4Zwd7NGpBGgXeStwAq0zfzjtw8YYI4I5Zc6P4I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772975551; c=relaxed/simple; bh=tUMIy6Rh0xANH3/H5q6ZWePe3fnfyPGevW5WgIJCTWo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Y7YF8JSWkmq81RmA4zobYChCDtoQ7yX2o85e8z/65UuVpxu/psQ2A4Qzgt/tG5LYeEGdNW3RtxFl7G+hYPOXZifuvAJHe6gCWeFhKygcPvfUAxT4xW+nxPwxtenP6mAReJGN07y5dO+BP3nBrx9NRqhFK+loGIWEfXRCnVB9Gho= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BWIYuY0K; 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="BWIYuY0K" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 87FF8C19423; Sun, 8 Mar 2026 13:12:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772975551; bh=tUMIy6Rh0xANH3/H5q6ZWePe3fnfyPGevW5WgIJCTWo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BWIYuY0KMxr7kEfxNc028Xk7Y82YN3hnFZljeF3MJ3mMkcXJdpR2M10er9mg7Jclz jcHQ/8KfluS1uvuKnXnNY7w4RpQc1HZsxqwSiHbOZR3LeYflAOswaV+bQ/uTc169Kc iLP3TdWDgRgwgbXiiJQezGqIfpGtd9QgBVjvr4Tqxk84t1ag5TKXYm3ymP6Il7tyLl Ot/A422zNHMhg/9eLNMC+GjlM+tnqXPB6f8elzTtNhQispgCDklSHVHcxHpXzCjfqk P8qbclZSDoNTsQ1moZVT0de75h9DydKbb3h07Z+1VOwAcToJ0KVA6NCZhzlIMkj1+X kQ83G/MyoYXQw== 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 v3 2/3] bnxt_en: Resize RSS contexts on channel count change Date: Sun, 8 Mar 2026 14:12:16 +0100 Message-ID: <20260308131218.3172332-3-bjorn@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260308131218.3172332-1-bjorn@kernel.org> References: <20260308131218.3172332-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(). Tested-by: Pavan Chebbi Signed-off-by: Bj=C3=B6rn T=C3=B6pel Reviewed-by: Michael Chan --- .../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..dc3eb24c9c0b 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 Thu Apr 9 13:23:45 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 0B3F8332636; Sun, 8 Mar 2026 13:12:34 +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=1772975557; cv=none; b=QhiavOZkWV+jHNt7mMFj7sbFCQOpaUiQQVavwxE62l0DTi9Sd1XWdD+OIhdOfZkBGC/C92cRkbuNUG1XgrdckLuxdTRp2XPZlNEzd98LUZLAZk5YFC0ZqphkMCPx2H9sTxhccIuMWJw21gMaPyTabKiJSUqQK39PssUBwKXkXqo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772975557; c=relaxed/simple; bh=pi+jA2SaVz5VZQibrNj7aQIvOkEoJMAlD8C/xK4hfM8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Zl9NesPJU+8XwabMx8uIlT41WuruCivEowfPpjJNSOTr0m/wsoh1jT9/ihtoNVsJmDTF0zDcEOdb8jP/LH8u7hhFpQg95QqAUVKQ6Xl4L67UC2PUKcDQ2J3xFFlCUlAzqJB7npnuxuO01N9gN5nV6az9CYPrkEldD2ZY5A6v+zE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PlNiHoGP; 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="PlNiHoGP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D4BC5C2BC9E; Sun, 8 Mar 2026 13:12:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772975554; bh=pi+jA2SaVz5VZQibrNj7aQIvOkEoJMAlD8C/xK4hfM8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PlNiHoGPXFH/PUPlGpfolQhpwNpMQNvkdtwZag3oFUv9yxJKSsrvfVvfCabh8Ek1n /NGHB9Rk/mvSETTFfzJFm7LWxSg6Sc9IPcN1V6A//FDTYTOsIHdCd9wvRdJZJ1jrU0 7mmeL4pY9VaQIGJDaCWdsPWHTxLu3K4x98rm8hWr0yaJ279WuhjvC1Ahz3AUtcWuDJ LH38KxV+9E2BTPiN9SlpqsbQ6XbjvEyenU4UpV0XdZWPLaKQHfX6DjS+KnkKgcpvkF W+emIAlo5mNHklXqKP1uoYaqHFl3VFpdXCUVchlIse5//TVsLGpkgwWA4ceYa2lkYV pBnoCRbo7pY3Q== 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 v3 3/3] selftests: rss_drv: Add RSS indirection table resize tests Date: Sun, 8 Mar 2026 14:12:17 +0100 Message-ID: <20260308131218.3172332-4-bjorn@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260308131218.3172332-1-bjorn@kernel.org> References: <20260308131218.3172332-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. Tested-by: Pavan Chebbi Signed-off-by: Bj=C3=B6rn T=C3=B6pel --- .../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