Commit 51798c51 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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: default avatarGal Pressman <gal@nvidia.com>
Link: https://patch.msgid.link/20250716000331.1378807-7-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 82ae67cb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2656,6 +2656,7 @@ operations:
            - context
            - hfunc
            - indir
            - hkey
    -
      name: rss-ntf
      doc: |
+1 −0
Original line number Diff line number Diff line
@@ -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
+40 −1
Original line number Diff line number Diff line
@@ -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 @@ rss_set_prep_indir(struct net_device *dev, struct genl_info *info,
	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);