@@ -222,6 +222,7 @@ Userspace to kernel:
``ETHTOOL_MSG_MODULE_GET`` get transceiver module parameters
``ETHTOOL_MSG_PSE_SET`` set PSE parameters
``ETHTOOL_MSG_PSE_GET`` get PSE parameters
+ ``ETHTOOL_MSG_RXFH_GET`` get RSS settings
===================================== =================================
Kernel to userspace:
@@ -263,6 +264,7 @@ Kernel to userspace:
``ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY`` PHC virtual clocks info
``ETHTOOL_MSG_MODULE_GET_REPLY`` transceiver module parameters
``ETHTOOL_MSG_PSE_GET_REPLY`` PSE parameters
+ ``ETHTOOL_MSG_RXFH_GET_REPLY`` RSS settings
======================================== =================================
``GET`` requests are sent by userspace applications to retrieve device
@@ -1686,6 +1688,30 @@ to control PoDL PSE Admin functions. This option is implementing
``IEEE 802.3-2018`` 30.15.1.2.1 acPoDLPSEAdminControl. See
``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` for supported values.
+RXFH_GET
+========
+
+Get RSS table, hash key and hash function info like ``ETHTOOL_GRSSH``
+ioctl request.
+
+Request contents:
+
+===================================== ====== ==========================
+ ``ETHTOOL_A_RXFH_HEADER`` nested request header
+ ``ETHTOOL_A_RXFH_RSS_CONTEXT`` u32 context number
+ ==================================== ====== ==========================
+
+Kernel response contents:
+
+===================================== ====== ==========================
+ ``ETHTOOL_A_RXFH_HEADER`` nested reply header
+ ``ETHTOOL_A_RXFH_RSS_CONTEXT`` u32 RSS context number
+ ``ETHTOOL_A_RXFH_INDIR_SIZE`` u32 RSS Indirection table size
+ ``ETHTOOL_A_RXFH_KEY_SIZE`` u32 RSS hash key size
+ ``ETHTOOL_A_RXFH_HFUNC`` u32 RSS hash func
+ ``ETHTOOL_A_RXFH_RSS_CONFIG`` u32 Indir table and hkey bytes
+ ==================================== ====== ==========================
+
Request translation
===================
@@ -1738,7 +1764,7 @@ are netlink only.
``ETHTOOL_SFLAGS`` ``ETHTOOL_MSG_FEATURES_SET``
``ETHTOOL_GPFLAGS`` ``ETHTOOL_MSG_PRIVFLAGS_GET``
``ETHTOOL_SPFLAGS`` ``ETHTOOL_MSG_PRIVFLAGS_SET``
- ``ETHTOOL_GRXFH`` n/a
+ ``ETHTOOL_GRXFH`` ``ETHTOOL_MSG_RXFH_GET``
``ETHTOOL_SRXFH`` n/a
``ETHTOOL_GGRO`` ``ETHTOOL_MSG_FEATURES_GET``
``ETHTOOL_SGRO`` ``ETHTOOL_MSG_FEATURES_SET``
@@ -51,6 +51,7 @@ enum {
ETHTOOL_MSG_MODULE_SET,
ETHTOOL_MSG_PSE_GET,
ETHTOOL_MSG_PSE_SET,
+ ETHTOOL_MSG_RXFH_GET,
/* add new constants above here */
__ETHTOOL_MSG_USER_CNT,
@@ -97,6 +98,7 @@ enum {
ETHTOOL_MSG_MODULE_GET_REPLY,
ETHTOOL_MSG_MODULE_NTF,
ETHTOOL_MSG_PSE_GET_REPLY,
+ ETHTOOL_MSG_RXFH_GET_REPLY,
/* add new constants above here */
__ETHTOOL_MSG_KERNEL_CNT,
@@ -879,6 +881,19 @@ enum {
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
};
+enum {
+ ETHTOOL_A_RXFH_UNSPEC,
+ ETHTOOL_A_RXFH_HEADER,
+ ETHTOOL_A_RXFH_RSS_CONTEXT, /* u32 */
+ ETHTOOL_A_RXFH_INDIR_SIZE, /* u32 */
+ ETHTOOL_A_RXFH_KEY_SIZE, /* u32 */
+ ETHTOOL_A_RXFH_HFUNC, /* u8 */
+ ETHTOOL_A_RXFH_RSS_CONFIG,
+
+ __ETHTOOL_A_RXFH_CNT,
+ ETHTOOL_A_RXFH_MAX = (__ETHTOOL_A_RXFH_CNT - 1),
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
@@ -4,7 +4,7 @@ obj-y += ioctl.o common.o
obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o
-ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \
+ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rxfh.o \
linkstate.o debug.o wol.o features.o privflags.o rings.o \
channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o module.o \
@@ -287,6 +287,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
[ETHTOOL_MSG_PHC_VCLOCKS_GET] = ðnl_phc_vclocks_request_ops,
[ETHTOOL_MSG_MODULE_GET] = ðnl_module_request_ops,
[ETHTOOL_MSG_PSE_GET] = ðnl_pse_request_ops,
+ [ETHTOOL_MSG_RXFH_GET] = ðnl_rxfh_request_ops,
};
static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -1040,6 +1041,15 @@ static const struct genl_ops ethtool_genl_ops[] = {
.policy = ethnl_pse_set_policy,
.maxattr = ARRAY_SIZE(ethnl_pse_set_policy) - 1,
},
+ {
+ .cmd = ETHTOOL_MSG_RXFH_GET,
+ .doit = ethnl_default_doit,
+ .start = ethnl_default_start,
+ .dumpit = ethnl_default_dumpit,
+ .done = ethnl_default_done,
+ .policy = ethnl_rxfh_get_policy,
+ .maxattr = ARRAY_SIZE(ethnl_rxfh_get_policy) - 1,
+ },
};
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
@@ -346,6 +346,7 @@ extern const struct ethnl_request_ops ethnl_stats_request_ops;
extern const struct ethnl_request_ops ethnl_phc_vclocks_request_ops;
extern const struct ethnl_request_ops ethnl_module_request_ops;
extern const struct ethnl_request_ops ethnl_pse_request_ops;
+extern const struct ethnl_request_ops ethnl_rxfh_request_ops;
extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
@@ -386,6 +387,7 @@ extern const struct nla_policy ethnl_module_get_policy[ETHTOOL_A_MODULE_HEADER +
extern const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MODE_POLICY + 1];
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_rxfh_get_policy[ETHTOOL_A_RXFH_RSS_CONTEXT + 1];
int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
new file mode 100644
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "netlink.h"
+#include "common.h"
+
+struct rxfh_req_info {
+ struct ethnl_req_info base;
+};
+
+struct rxfh_reply_data {
+ struct ethnl_reply_data base;
+ struct ethtool_rxfh rxfh;
+ u32 *rss_config;
+};
+
+#define RXFH_REPDATA(__reply_base) \
+ container_of(__reply_base, struct rxfh_reply_data, base)
+
+const struct nla_policy ethnl_rxfh_get_policy[] = {
+ [ETHTOOL_A_RXFH_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
+ [ETHTOOL_A_RXFH_RSS_CONTEXT] = { .type = NLA_U32 },
+};
+
+static int rxfh_prepare_data(const struct ethnl_req_info *req_base,
+ struct ethnl_reply_data *reply_base,
+ struct genl_info *info)
+{
+ struct rxfh_reply_data *data = RXFH_REPDATA(reply_base);
+ u32 indir_size, hkey_size, total_size, indir_bytes;
+ struct net_device *dev = reply_base->dev;
+ struct ethtool_rxfh *rxfh = &data->rxfh;
+ struct ethnl_req_info req_info = {};
+ struct nlattr **tb = info->attrs;
+ const struct ethtool_ops *ops;
+ bool mod = false;
+ u8 dev_hfunc = 0;
+ u8 *hkey = NULL;
+ u8 *rss_config;
+ int ret;
+
+ ops = dev->ethtool_ops;
+ if (!ops->get_rxfh)
+ return -EOPNOTSUPP;
+
+ ret = ethnl_parse_header_dev_get(&req_info,
+ tb[ETHTOOL_A_RXFH_HEADER],
+ genl_info_net(info), info->extack,
+ true);
+ if (ret < 0)
+ return ret;
+
+ ethnl_update_u32(&rxfh->rss_context, tb[ETHTOOL_A_RXFH_RSS_CONTEXT],
+ &mod);
+
+ ret = ethnl_ops_begin(dev);
+ if (ret < 0)
+ return ret;
+
+ /* Some drivers don't handle rss_context */
+ if (rxfh->rss_context && !ops->get_rxfh_context)
+ return -EOPNOTSUPP;
+
+ if (ops->get_rxfh_indir_size)
+ indir_size = ops->get_rxfh_indir_size(dev);
+ if (ops->get_rxfh_key_size)
+ hkey_size = ops->get_rxfh_key_size(dev);
+
+ indir_bytes = indir_size * sizeof(rxfh->rss_config[0]);
+ total_size = indir_bytes + hkey_size;
+ rss_config = kzalloc(total_size, GFP_USER);
+ if (!rss_config)
+ return -ENOMEM;
+
+ if (indir_size) {
+ data->rss_config = (u32 *)rss_config;
+ rxfh->indir_size = indir_size;
+ }
+
+ if (hkey_size) {
+ hkey = rss_config + indir_bytes;
+ rxfh->key_size = hkey_size;
+ }
+
+ if (rxfh->rss_context)
+ ret = ops->get_rxfh_context(dev, data->rss_config, hkey,
+ &dev_hfunc, rxfh->rss_context);
+ else
+ ret = ops->get_rxfh(dev, data->rss_config, hkey, &dev_hfunc);
+
+ rxfh->hfunc = dev_hfunc;
+
+ ethnl_ops_complete(dev);
+ ethnl_parse_header_dev_put(&req_info);
+ return ret;
+}
+
+static int rxfh_reply_size(const struct ethnl_req_info *req_base,
+ const struct ethnl_reply_data *reply_base)
+{
+ const struct rxfh_reply_data *data = RXFH_REPDATA(reply_base);
+ const struct ethtool_rxfh *rxfh = &data->rxfh;
+ int len;
+
+ len = nla_total_size(sizeof(u32)) + /* _RSS_CONTEXT */
+ nla_total_size(sizeof(u32)) + /* _RXFH_INDIR_SIZE */
+ nla_total_size(sizeof(u32)) + /* _RXFH_KEY_SIZE */
+ nla_total_size(sizeof(u8)); /* _RXFH_HFUNC */
+ len += nla_total_size(sizeof(u32)) * rxfh->indir_size +
+ rxfh->key_size;
+
+ return len;
+}
+
+static int rxfh_fill_reply(struct sk_buff *skb,
+ const struct ethnl_req_info *req_base,
+ const struct ethnl_reply_data *reply_base)
+{
+ const struct rxfh_reply_data *data = RXFH_REPDATA(reply_base);
+ const struct ethtool_rxfh *rxfh = &data->rxfh;
+
+ if (nla_put_u32(skb, ETHTOOL_A_RXFH_RSS_CONTEXT, rxfh->rss_context) ||
+ nla_put_u32(skb, ETHTOOL_A_RXFH_INDIR_SIZE, rxfh->indir_size) ||
+ nla_put_u32(skb, ETHTOOL_A_RXFH_KEY_SIZE, rxfh->key_size) ||
+ nla_put_u8(skb, ETHTOOL_A_RXFH_HFUNC, rxfh->hfunc) ||
+ nla_put(skb, ETHTOOL_A_RXFH_RSS_CONFIG,
+ sizeof(u32) * rxfh->indir_size + rxfh->key_size,
+ data->rss_config))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static void rxfh_cleanup_data(struct ethnl_reply_data *reply_base)
+{
+ const struct rxfh_reply_data *data = RXFH_REPDATA(reply_base);
+
+ kfree(data->rss_config);
+}
+
+const struct ethnl_request_ops ethnl_rxfh_request_ops = {
+ .request_cmd = ETHTOOL_MSG_RXFH_GET,
+ .reply_cmd = ETHTOOL_MSG_RXFH_GET_REPLY,
+ .hdr_attr = ETHTOOL_A_RXFH_HEADER,
+ .req_info_size = sizeof(struct rxfh_req_info),
+ .reply_data_size = sizeof(struct rxfh_reply_data),
+
+ .prepare_data = rxfh_prepare_data,
+ .reply_size = rxfh_reply_size,
+ .fill_reply = rxfh_fill_reply,
+ .cleanup_data = rxfh_cleanup_data,
+};
Implement RXFH_GET request to get RSS table, hash key and hash function of an interface. This is netlink equivalent implementation of ETHTOOL_GRSSH ioctl request. Signed-off-by: Sudheer Mogilappagari <sudheer.mogilappagari@intel.com> --- Documentation/networking/ethtool-netlink.rst | 28 +++- include/uapi/linux/ethtool_netlink.h | 15 ++ net/ethtool/Makefile | 2 +- net/ethtool/netlink.c | 10 ++ net/ethtool/netlink.h | 2 + net/ethtool/rxfh.c | 151 +++++++++++++++++++ 6 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 net/ethtool/rxfh.c