summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2025-07-15 17:03:26 -0700
committerJakub Kicinski <kuba@kernel.org>2025-07-17 16:13:58 -0700
commit51798c519a9178d179913ac1417ea3e1d27f5fce (patch)
tree5e9a0eb8963404617c7c955ef99a01f7ac846de3
parent82ae67cbc423425ecc5836daa520442d4c8bdb33 (diff)
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 <gal@nvidia.com> Link: https://patch.msgid.link/20250716000331.1378807-7-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--Documentation/netlink/specs/ethtool.yaml1
-rw-r--r--Documentation/networking/ethtool-netlink.rst1
-rw-r--r--net/ethtool/rss.c41
3 files changed, 42 insertions, 1 deletions
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 0d02d8342e4c..aa55fc9068e1 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -2656,6 +2656,7 @@ operations:
- context
- hfunc
- indir
+ - hkey
-
name: rss-ntf
doc: |
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index f6e4439caa94..1830354495ae 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -2001,6 +2001,7 @@ Request contents:
``ETHTOOL_A_RSS_CONTEXT`` u32 context number
``ETHTOOL_A_RSS_HFUNC`` u32 RSS hash func
``ETHTOOL_A_RSS_INDIR`` binary Indir table bytes
+ ``ETHTOOL_A_RSS_HKEY`` binary Hash key bytes
===================================== ====== ==============================
``ETHTOOL_A_RSS_INDIR`` is the minimal RSS table the user expects. Kernel and
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);