summaryrefslogtreecommitdiff
path: root/net/ethtool
diff options
context:
space:
mode:
authorEdward Cree <ecree.xilinx@gmail.com>2024-06-27 16:33:48 +0100
committerJakub Kicinski <kuba@kernel.org>2024-06-28 18:53:21 -0700
commiteac9122f0c41b832065e01977c34946ec8e76c24 (patch)
tree971a86da2e6a7aa174b3191caa011015aff2f729 /net/ethtool
parent6ad2962f8adfd53fca52dce7f830783e95d99ce7 (diff)
downloadlinux-eac9122f0c41b832065e01977c34946ec8e76c24.tar.gz
linux-eac9122f0c41b832065e01977c34946ec8e76c24.tar.bz2
linux-eac9122f0c41b832065e01977c34946ec8e76c24.zip
net: ethtool: record custom RSS contexts in the XArray
Since drivers are still choosing the context IDs, we have to force the XArray to use the ID they've chosen rather than picking one ourselves, and handle the case where they give us an ID that's already in use. Signed-off-by: Edward Cree <ecree.xilinx@gmail.com> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Link: https://patch.msgid.link/801f5faa4cec87c65b2c6e27fb220c944bce593a.1719502240.git.ecree.xilinx@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/ethtool')
-rw-r--r--net/ethtool/ioctl.c74
1 files changed, 73 insertions, 1 deletions
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 94059ce9e5f2..e901a20e97f5 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1281,10 +1281,12 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
const struct ethtool_ops *ops = dev->ethtool_ops;
u32 dev_indir_size = 0, dev_key_size = 0, i;
struct ethtool_rxfh_param rxfh_dev = {};
+ struct ethtool_rxfh_context *ctx = NULL;
struct netlink_ext_ack *extack = NULL;
struct ethtool_rxnfc rx_rings;
struct ethtool_rxfh rxfh;
u32 indir_bytes = 0;
+ bool create = false;
u8 *rss_config;
int ret;
@@ -1312,6 +1314,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
if ((rxfh.input_xfrm & RXH_XFRM_SYM_XOR) &&
!ops->cap_rss_sym_xor_supported)
return -EOPNOTSUPP;
+ create = rxfh.rss_context == ETH_RXFH_CONTEXT_ALLOC;
/* If either indir, hash key or function is valid, proceed further.
* Must request at least one change: indir size, hash key, function
@@ -1377,13 +1380,42 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
}
}
+ if (create) {
+ if (rxfh_dev.rss_delete) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ctx = kzalloc(ethtool_rxfh_context_size(dev_indir_size,
+ dev_key_size,
+ ops->rxfh_priv_size),
+ GFP_KERNEL_ACCOUNT);
+ if (!ctx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ctx->indir_size = dev_indir_size;
+ ctx->key_size = dev_key_size;
+ ctx->hfunc = rxfh.hfunc;
+ ctx->input_xfrm = rxfh.input_xfrm;
+ ctx->priv_size = ops->rxfh_priv_size;
+ } else if (rxfh.rss_context) {
+ ctx = xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context);
+ if (!ctx) {
+ ret = -ENOENT;
+ goto out;
+ }
+ }
rxfh_dev.hfunc = rxfh.hfunc;
rxfh_dev.rss_context = rxfh.rss_context;
rxfh_dev.input_xfrm = rxfh.input_xfrm;
ret = ops->set_rxfh(dev, &rxfh_dev, extack);
- if (ret)
+ if (ret) {
+ if (create)
+ /* failed to create, free our new tracking entry */
+ kfree(ctx);
goto out;
+ }
if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, rss_context),
&rxfh_dev.rss_context, sizeof(rxfh_dev.rss_context)))
@@ -1396,6 +1428,46 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
dev->priv_flags |= IFF_RXFH_CONFIGURED;
}
+ /* Update rss_ctx tracking */
+ if (create) {
+ /* Ideally this should happen before calling the driver,
+ * so that we can fail more cleanly; but we don't have the
+ * context ID until the driver picks it, so we have to
+ * wait until after.
+ */
+ if (WARN_ON(xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context))) {
+ /* context ID reused, our tracking is screwed */
+ kfree(ctx);
+ goto out;
+ }
+ /* Allocate the exact ID the driver gave us */
+ if (xa_is_err(xa_store(&dev->ethtool->rss_ctx, rxfh.rss_context,
+ ctx, GFP_KERNEL))) {
+ kfree(ctx);
+ goto out;
+ }
+ ctx->indir_configured = rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE;
+ ctx->key_configured = !!rxfh.key_size;
+ }
+ if (rxfh_dev.rss_delete) {
+ WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context) != ctx);
+ kfree(ctx);
+ } else if (ctx) {
+ if (rxfh_dev.indir) {
+ for (i = 0; i < dev_indir_size; i++)
+ ethtool_rxfh_context_indir(ctx)[i] = rxfh_dev.indir[i];
+ ctx->indir_configured = 1;
+ }
+ if (rxfh_dev.key) {
+ memcpy(ethtool_rxfh_context_key(ctx), rxfh_dev.key,
+ dev_key_size);
+ ctx->key_configured = 1;
+ }
+ if (rxfh_dev.hfunc != ETH_RSS_HASH_NO_CHANGE)
+ ctx->hfunc = rxfh_dev.hfunc;
+ if (rxfh_dev.input_xfrm != RXH_XFRM_NO_CHANGE)
+ ctx->input_xfrm = rxfh_dev.input_xfrm;
+ }
out:
kfree(rss_config);