[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230309220544.177248-1-sudheer.mogilappagari@intel.com>
Date: Thu, 9 Mar 2023 14:05:44 -0800
From: Sudheer Mogilappagari <sudheer.mogilappagari@...el.com>
To: netdev@...r.kernel.org
Cc: kuba@...nel.org, mkubecek@...e.cz, sridhar.samudrala@...el.com,
anthony.l.nguyen@...el.com
Subject: [PATCH net-next] ethtool: add netlink support for rss set
Add netlink based support for "ethtool -X <dev>" command by
implementing ETHTOOL_MSG_RSS_SET netlink message. This is
equivalent to functionality provided via ETHTOOL_SRSSH in
ioctl path. It allows creation and deletion of RSS context
and modifying RSS table, hash key and hash function of an
interface.
Functionality is backward compatible with the one available
in ioctl path but enables addition of new RSS context based
parameters in future.
Signed-off-by: Sudheer Mogilappagari <sudheer.mogilappagari@...el.com>
---
Documentation/networking/ethtool-netlink.rst | 31 ++++
include/uapi/linux/ethtool_netlink.h | 3 +
net/ethtool/netlink.c | 7 +
net/ethtool/netlink.h | 2 +
net/ethtool/rss.c | 155 +++++++++++++++++++
5 files changed, 198 insertions(+)
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index e1bc6186d7ea..e03228978d1a 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -223,6 +223,7 @@ Userspace to kernel:
``ETHTOOL_MSG_PSE_SET`` set PSE parameters
``ETHTOOL_MSG_PSE_GET`` get PSE parameters
``ETHTOOL_MSG_RSS_GET`` get RSS settings
+ ``ETHTOOL_MSG_RSS_SET`` set RSS settings
``ETHTOOL_MSG_MM_GET`` get MAC merge layer state
``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters
===================================== =================================
@@ -1756,6 +1757,36 @@ being used. Current supported options are toeplitz, xor or crc32.
ETHTOOL_A_RSS_INDIR attribute returns RSS indrection table where each byte
indicates queue number.
+RSS_SET
+=======
+
+Update indirection table, hash key and hash function of a RSS context.
+similar to ``ETHTOOL_SRSSH`` ioctl request.
+
+Request contents:
+
+===================================== ====== ==========================
+ ``ETHTOOL_A_RSS_HEADER`` nested request header
+ ``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_DELETE`` u8 context delete flag
+===================================== ====== ==========================
+
+Kernel response contents:
+
+===================================== ====== ==========================
+ ``ETHTOOL_A_RSS_HEADER`` nested reply header
+ ``ETHTOOL_A_RSS_CONTEXT`` u32 context number created
+===================================== ====== ==========================
+
+RSS context value of ETH_RXFH_CONTEXT_ALLOC indicates creation of new
+context. Response contains newly created context number or same context
+number as request. ETHTOOL_A_RSS_HFUNC attribute is bitmap indicating
+the hash function being used. Current supported options are toeplitz,
+xor or crc32.
+
PLCA_GET_CFG
============
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index d39ce21381c5..56c4e8570dc6 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -52,6 +52,7 @@ enum {
ETHTOOL_MSG_PSE_GET,
ETHTOOL_MSG_PSE_SET,
ETHTOOL_MSG_RSS_GET,
+ ETHTOOL_MSG_RSS_SET,
ETHTOOL_MSG_PLCA_GET_CFG,
ETHTOOL_MSG_PLCA_SET_CFG,
ETHTOOL_MSG_PLCA_GET_STATUS,
@@ -104,6 +105,7 @@ enum {
ETHTOOL_MSG_MODULE_NTF,
ETHTOOL_MSG_PSE_GET_REPLY,
ETHTOOL_MSG_RSS_GET_REPLY,
+ ETHTOOL_MSG_RSS_SET_REPLY,
ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
ETHTOOL_MSG_PLCA_NTF,
@@ -906,6 +908,7 @@ enum {
ETHTOOL_A_RSS_HFUNC, /* u32 */
ETHTOOL_A_RSS_INDIR, /* binary */
ETHTOOL_A_RSS_HKEY, /* binary */
+ ETHTOOL_A_RSS_DELETE, /* u8 */
__ETHTOOL_A_RSS_CNT,
ETHTOOL_A_RSS_MAX = (__ETHTOOL_A_RSS_CNT - 1),
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 08120095cc68..22177883438b 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -1115,6 +1115,13 @@ static const struct genl_ops ethtool_genl_ops[] = {
.policy = ethnl_rss_get_policy,
.maxattr = ARRAY_SIZE(ethnl_rss_get_policy) - 1,
},
+ {
+ .cmd = ETHTOOL_MSG_RSS_SET,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .doit = ethnl_set_rss,
+ .policy = ethnl_rss_set_policy,
+ .maxattr = ARRAY_SIZE(ethnl_rss_set_policy) - 1,
+ },
{
.cmd = ETHTOOL_MSG_PLCA_GET_CFG,
.doit = ethnl_default_doit,
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index f7b189ed96b2..67d7e4e5b916 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -436,6 +436,7 @@ extern const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MO
extern const struct nla_policy ethnl_pse_get_policy[ETHTOOL_A_PSE_HEADER + 1];
extern const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1];
extern const struct nla_policy ethnl_rss_get_policy[ETHTOOL_A_RSS_CONTEXT + 1];
+extern const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_MAX + 1];
extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1];
extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1];
extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1];
@@ -443,6 +444,7 @@ extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1];
extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1];
int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
+int ethnl_set_rss(struct sk_buff *skb, struct genl_info *info);
int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info);
int ethnl_tunnel_info_doit(struct sk_buff *skb, struct genl_info *info);
diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c
index be260ab34e58..f19e4baa83e2 100644
--- a/net/ethtool/rss.c
+++ b/net/ethtool/rss.c
@@ -154,3 +154,158 @@ const struct ethnl_request_ops ethnl_rss_request_ops = {
.fill_reply = rss_fill_reply,
.cleanup_data = rss_cleanup_data,
};
+
+/* RSS_SET */
+
+const struct nla_policy ethnl_rss_set_policy[] = {
+ [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
+ [ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32 },
+ [ETHTOOL_A_RSS_HFUNC] = { .type = NLA_U32 },
+ [ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY },
+ [ETHTOOL_A_RSS_HKEY] = { .type = NLA_BINARY },
+ [ETHTOOL_A_RSS_DELETE] = { .type = NLA_U8 },
+};
+
+static int srss_send_reply(struct net_device *dev, struct genl_info *info,
+ u32 rss_context)
+{
+ struct sk_buff *rskb;
+ void *reply_payload;
+ int reply_len;
+ int ret;
+
+ reply_len = ethnl_reply_header_size() +
+ nla_total_size(sizeof(u32)); /* RSS_CONTEXT */
+
+ rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_RSS_SET_REPLY,
+ ETHTOOL_A_RSS_HEADER, info, &reply_payload);
+
+ ret = nla_put_u32(rskb, ETHTOOL_A_RSS_CONTEXT, rss_context);
+ if (ret < 0)
+ goto nla_put_failure;
+
+ genlmsg_end(rskb, reply_payload);
+ ret = genlmsg_reply(rskb, info);
+ return ret;
+
+nla_put_failure:
+ nlmsg_free(rskb);
+ WARN_ONCE(1, "calculated message payload length (%d) not sufficient\n",
+ reply_len);
+ GENL_SET_ERR_MSG(info, "failed to send reply message");
+ return ret;
+}
+
+int ethnl_set_rss(struct sk_buff *skb, struct genl_info *info)
+{
+ struct ethnl_req_info req_info = {};
+ u32 rss_hfunc = 0, rss_context = 0;
+ u32 hkey_bytes = 0, indir_size = 0;
+ struct nlattr **tb = info->attrs;
+ const struct ethtool_ops *ops;
+ struct ethtool_rxnfc rx_rings;
+ struct net_device *dev;
+ u32 *rss_indir = NULL;
+ u8 *rss_hkey = NULL;
+ u32 delete = false;
+ bool mod = false;
+ int ret, i;
+
+ ret = ethnl_parse_header_dev_get(&req_info,
+ tb[ETHTOOL_A_RSS_HEADER],
+ genl_info_net(info), info->extack,
+ true);
+ if (ret < 0)
+ return ret;
+
+ dev = req_info.dev;
+ ops = dev->ethtool_ops;
+ if (!ops->get_rxnfc || !ops->set_rxfh) {
+ ret = -EOPNOTSUPP;
+ goto out_dev;
+ }
+
+ rtnl_lock();
+ ret = ethnl_ops_begin(dev);
+ if (ret < 0)
+ goto out_rtnl;
+
+ ethnl_update_u32(&rss_context, tb[ETHTOOL_A_RSS_CONTEXT], &mod);
+ if (rss_context && !ops->set_rxfh_context) {
+ ret = -EOPNOTSUPP;
+ goto out_ops;
+ }
+
+ ethnl_update_bool32(&delete, tb[ETHTOOL_A_RSS_DELETE], &mod);
+ ethnl_update_u32(&rss_hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
+
+ if (tb[ETHTOOL_A_RSS_HKEY]) {
+ if (ops->get_rxfh_key_size)
+ hkey_bytes = ops->get_rxfh_key_size(dev);
+
+ if (!hkey_bytes ||
+ nla_len(tb[ETHTOOL_A_RSS_HKEY]) != hkey_bytes) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ rss_hkey = kzalloc(hkey_bytes, GFP_KERNEL);
+ if (!rss_hkey) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+ ethnl_update_binary(rss_hkey, hkey_bytes,
+ tb[ETHTOOL_A_RSS_HKEY], &mod);
+ }
+
+ if (tb[ETHTOOL_A_RSS_INDIR]) {
+ u32 indir_bytes;
+
+ if (ops->get_rxfh_indir_size)
+ indir_size = ops->get_rxfh_indir_size(dev);
+
+ indir_bytes = indir_size * sizeof(u32);
+ if (!indir_bytes ||
+ nla_len(tb[ETHTOOL_A_RSS_INDIR]) != indir_bytes) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ rss_indir = kzalloc(indir_bytes, GFP_KERNEL);
+ if (!rss_indir) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+ ethnl_update_binary(rss_indir, indir_bytes,
+ tb[ETHTOOL_A_RSS_INDIR], &mod);
+
+ /* Validate ring indices */
+ rx_rings.cmd = ETHTOOL_GRXRINGS;
+ ret = ops->get_rxnfc(dev, &rx_rings, NULL);
+ if (ret)
+ goto out_free;
+
+ for (i = 0; i < indir_size; i++)
+ if (rss_indir[i] >= rx_rings.data)
+ goto out_free;
+ }
+
+ if (rss_context)
+ ret = ops->set_rxfh_context(dev, rss_indir, rss_hkey, rss_hfunc,
+ &rss_context, delete);
+ else
+ ret = ops->set_rxfh(dev, rss_indir, rss_hkey, rss_hfunc);
+
+ srss_send_reply(dev, info, rss_context);
+
+out_free:
+ kfree(rss_hkey);
+ kfree(rss_indir);
+out_ops:
+ ethnl_ops_complete(dev);
+out_rtnl:
+ rtnl_unlock();
+out_dev:
+ ethnl_parse_header_dev_put(&req_info);
+ return ret;
+}
--
2.31.1
Powered by blists - more mailing lists