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>
This commit is contained in:
Edward Cree 2024-06-27 16:33:48 +01:00 committed by Jakub Kicinski
parent 6ad2962f8a
commit eac9122f0c
2 changed files with 87 additions and 1 deletions

View File

@ -199,6 +199,17 @@ static inline u8 *ethtool_rxfh_context_key(struct ethtool_rxfh_context *ctx)
return (u8 *)(ethtool_rxfh_context_indir(ctx) + ctx->indir_size);
}
static inline size_t ethtool_rxfh_context_size(u32 indir_size, u32 key_size,
u16 priv_size)
{
size_t indir_bytes = array_size(indir_size, sizeof(u32));
size_t flex_len;
flex_len = size_add(size_add(indir_bytes, key_size),
ALIGN(priv_size, sizeof(u32)));
return struct_size_t(struct ethtool_rxfh_context, data, flex_len);
}
/* declare a link mode bitmap */
#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name) \
DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS)
@ -710,6 +721,8 @@ struct ethtool_rxfh_param {
* contexts.
* @cap_rss_sym_xor_supported: indicates if the driver supports symmetric-xor
* RSS.
* @rxfh_priv_size: size of the driver private data area the core should
* allocate for an RSS context (in &struct ethtool_rxfh_context).
* @supported_coalesce_params: supported types of interrupt coalescing.
* @supported_ring_params: supported ring params.
* @get_drvinfo: Report driver/device information. Modern drivers no
@ -895,6 +908,7 @@ struct ethtool_ops {
u32 cap_link_lanes_supported:1;
u32 cap_rss_ctx_supported:1;
u32 cap_rss_sym_xor_supported:1;
u16 rxfh_priv_size;
u32 supported_coalesce_params;
u32 supported_ring_params;
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);

View File

@ -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);