]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ethtool: rss: support setting hkey via Netlink
authorJakub Kicinski <kuba@kernel.org>
Wed, 16 Jul 2025 00:03:26 +0000 (17:03 -0700)
committerJakub Kicinski <kuba@kernel.org>
Thu, 17 Jul 2025 23:13:58 +0000 (16:13 -0700)
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>
Documentation/netlink/specs/ethtool.yaml
Documentation/networking/ethtool-netlink.rst
net/ethtool/rss.c

index 0d02d8342e4c5193359b95a8c208f8dd439ee7c3..aa55fc9068e1f582415b5f7ee9d639871f791156 100644 (file)
@@ -2656,6 +2656,7 @@ operations:
             - context
             - hfunc
             - indir
+            - hkey
     -
       name: rss-ntf
       doc: |
index f6e4439caa9474c66b432284701a3ef5ea1578ce..1830354495aee6e3e6596903ed433a87efab09f2 100644 (file)
@@ -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
index bc9025cfcf1c2c60f6363fdd50a714dffef679d6..55260830639f97dffd413b6aede923244d366e3d 100644 (file)
@@ -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);