From 51798c519a9178d179913ac1417ea3e1d27f5fce Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 15 Jul 2025 17:03:26 -0700 Subject: ethtool: rss: support setting hkey via Netlink Support setting RSS hashing key via ethtool Netlink. Use the Netlink policy to make sure user doesn't pass an empty key, "resetting" the key is not a thing. Reviewed-by: Gal Pressman Link: https://patch.msgid.link/20250716000331.1378807-7-kuba@kernel.org Signed-off-by: Jakub Kicinski --- net/ethtool/rss.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'net/ethtool') diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c index bc9025cfcf1c..55260830639f 100644 --- a/net/ethtool/rss.c +++ b/net/ethtool/rss.c @@ -477,6 +477,7 @@ const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_START_CONTEXT + 1] = [ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32, }, [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1), [ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, }, + [ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1), }; static int @@ -490,8 +491,10 @@ ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info) if (request->rss_context && !ops->create_rxfh_context) bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_CONTEXT]; - if (request->rss_context && !ops->rxfh_per_ctx_key) + if (request->rss_context && !ops->rxfh_per_ctx_key) { bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HFUNC]; + bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HKEY]; + } if (bad_attr) { NL_SET_BAD_ATTR(info->extack, bad_attr); @@ -581,6 +584,31 @@ err_free: return err; } +static int +rss_set_prep_hkey(struct net_device *dev, struct genl_info *info, + struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh, + bool *mod) +{ + struct nlattr **tb = info->attrs; + + if (!tb[ETHTOOL_A_RSS_HKEY]) + return 0; + + if (nla_len(tb[ETHTOOL_A_RSS_HKEY]) != data->hkey_size) { + NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_HKEY]); + return -EINVAL; + } + + rxfh->key_size = data->hkey_size; + rxfh->key = kmemdup(data->hkey, data->hkey_size, GFP_KERNEL); + if (!rxfh->key) + return -ENOMEM; + + ethnl_update_binary(rxfh->key, rxfh->key_size, tb[ETHTOOL_A_RSS_HKEY], + mod); + return 0; +} + static void rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb, struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh) @@ -592,6 +620,11 @@ rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb, ethtool_rxfh_context_indir(ctx)[i] = rxfh->indir[i]; ctx->indir_configured = !!nla_len(tb[ETHTOOL_A_RSS_INDIR]); } + if (rxfh->key) { + memcpy(ethtool_rxfh_context_key(ctx), rxfh->key, + data->hkey_size); + ctx->key_configured = !!rxfh->key_size; + } if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE) ctx->hfunc = rxfh->hfunc; } @@ -629,6 +662,10 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info) if (rxfh.hfunc == data.hfunc) rxfh.hfunc = ETH_RSS_HASH_NO_CHANGE; + ret = rss_set_prep_hkey(dev, info, &data, &rxfh, &mod); + if (ret) + goto exit_free_indir; + rxfh.input_xfrm = RXH_XFRM_NO_CHANGE; mutex_lock(&dev->ethtool->rss_lock); @@ -660,6 +697,8 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info) exit_unlock: mutex_unlock(&dev->ethtool->rss_lock); + kfree(rxfh.key); +exit_free_indir: kfree(rxfh.indir); exit_clean_data: rss_cleanup_data(&data.base); -- cgit v1.2.3