diff mbox series

[ethtool,RFC,3/3] ethtool: Add support for configuring frame preemption via netlink

Message ID 20200516013026.3174098-4-vinicius.gomes@intel.com
State New
Headers show
Series [ethtool,RFC,1/3] uapi: Update headers from the kernel [DO NOT APPLY] | expand

Commit Message

Vinicius Costa Gomes May 16, 2020, 1:30 a.m. UTC
Adds the same functionality of the ETHTOOL_{G,S}FP commands, now via
the ETHTOOL_MSG_PREEMPT_{GET,SET} netlink messages.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
 Makefile.am            |   2 +-
 ethtool.c              |   2 +
 netlink/desc-ethtool.c |  13 ++++
 netlink/extapi.h       |   4 ++
 netlink/preempt.c      | 148 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 168 insertions(+), 1 deletion(-)
 create mode 100644 netlink/preempt.c
diff mbox series

Patch

diff --git a/Makefile.am b/Makefile.am
index 0f8465f..3b88533 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,7 +32,7 @@  ethtool_SOURCES += \
 		  netlink/settings.c netlink/parser.c netlink/parser.h \
 		  netlink/permaddr.c netlink/prettymsg.c netlink/prettymsg.h \
 		  netlink/desc-ethtool.c netlink/desc-genlctrl.c \
-		  netlink/desc-rtnl.c \
+		  netlink/desc-rtnl.c netlink/preempt.c \
 		  uapi/linux/ethtool_netlink.h \
 		  uapi/linux/netlink.h uapi/linux/genetlink.h \
 		  uapi/linux/rtnetlink.h uapi/linux/if_link.h
diff --git a/ethtool.c b/ethtool.c
index 4c69d1c..3acdd54 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5587,11 +5587,13 @@  static const struct option args[] = {
 	{
 		.opts	= "--show-frame-preemption",
 		.func	= do_get_preempt,
+		.nlfunc	= nl_get_preempt,
 		.help	= "Show Frame Preemption settings",
 	},
 	{
 		.opts	= "--set-frame-preemption",
 		.func	= do_set_preempt,
+		.nlfunc	= nl_set_preempt,
 		.help	= "Set Frame Preemption settings",
 		.xhelp	= "		[ fp on|off ]\n"
 			  "		[ preemptible-queues-mask %x ]\n"
diff --git a/netlink/desc-ethtool.c b/netlink/desc-ethtool.c
index 76c6f13..f82afd2 100644
--- a/netlink/desc-ethtool.c
+++ b/netlink/desc-ethtool.c
@@ -106,6 +106,17 @@  static const struct pretty_nla_desc __wol_desc[] = {
 	NLATTR_DESC_BINARY(ETHTOOL_A_WOL_SOPASS),
 };
 
+static const struct pretty_nla_desc __preempt_desc[] = {
+	NLATTR_DESC_INVALID(ETHTOOL_A_PREEMPT_UNSPEC),
+	NLATTR_DESC_NESTED(ETHTOOL_A_PREEMPT_HEADER, header),
+	NLATTR_DESC_U8(ETHTOOL_A_PREEMPT_SUPPORTED),
+	NLATTR_DESC_U8(ETHTOOL_A_PREEMPT_ACTIVE),
+	NLATTR_DESC_U32(ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED),
+	NLATTR_DESC_U32(ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE),
+	NLATTR_DESC_U32(ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE),
+	NLATTR_DESC_BINARY(ETHTOOL_A_WOL_SOPASS),
+};
+
 const struct pretty_nlmsg_desc ethnl_umsg_desc[] = {
 	NLMSG_DESC_INVALID(ETHTOOL_MSG_USER_NONE),
 	NLMSG_DESC(ETHTOOL_MSG_STRSET_GET, strset),
@@ -118,6 +129,8 @@  const struct pretty_nlmsg_desc ethnl_umsg_desc[] = {
 	NLMSG_DESC(ETHTOOL_MSG_DEBUG_SET, debug),
 	NLMSG_DESC(ETHTOOL_MSG_WOL_GET, wol),
 	NLMSG_DESC(ETHTOOL_MSG_WOL_SET, wol),
+	NLMSG_DESC(ETHTOOL_MSG_PREEMPT_GET, preempt),
+	NLMSG_DESC(ETHTOOL_MSG_PREEMPT_SET, preempt),
 };
 
 const unsigned int ethnl_umsg_n_desc = ARRAY_SIZE(ethnl_umsg_desc);
diff --git a/netlink/extapi.h b/netlink/extapi.h
index 9484b4c..2436f70 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -21,6 +21,8 @@  int nl_gset(struct cmd_context *ctx);
 int nl_sset(struct cmd_context *ctx);
 int nl_permaddr(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
+int nl_get_preempt(struct cmd_context *ctx);
+int nl_set_preempt(struct cmd_context *ctx);
 
 void nl_monitor_usage(void);
 
@@ -44,6 +46,8 @@  static inline void nl_monitor_usage(void)
 #define nl_gset			NULL
 #define nl_sset			NULL
 #define nl_permaddr		NULL
+#define nl_get_preempt		NULL
+#define nl_set_preempt		NULL
 
 #endif /* ETHTOOL_ENABLE_NETLINK */
 
diff --git a/netlink/preempt.c b/netlink/preempt.c
new file mode 100644
index 0000000..976ae39
--- /dev/null
+++ b/netlink/preempt.c
@@ -0,0 +1,148 @@ 
+/*
+ * preempt.c - netlink implementation of frame preemption settings
+ *
+ * Implementation of "ethtool --{show,set}-frame-preemption <dev>"
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_link.h>
+
+#include "../internal.h"
+#include "../common.h"
+#include "netlink.h"
+#include "parser.h"
+
+/* PREEMPT_GET */
+
+static int preempt_get_prep_request(struct nl_socket *nlsk)
+{
+	int ret;
+
+	ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_PREEMPT_GET,
+				      ETHTOOL_A_PREEMPT_HEADER, 0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+int preempt_get_reply_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct nlattr *tb[ETHTOOL_A_PREEMPT_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	struct nl_context *nlctx = data;
+	int ret;
+
+	if (nlctx->is_dump || nlctx->is_monitor)
+		nlctx->no_banner = false;
+
+	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
+	if (ret < 0)
+		return ret;
+
+	nlctx->devname = get_dev_name(tb[ETHTOOL_A_PREEMPT_HEADER]);
+	if (!dev_ok(nlctx))
+		return MNL_CB_OK;
+
+	printf("Frame preemption settings for %s:\n", nlctx->devname);
+
+	if (tb[ETHTOOL_A_PREEMPT_SUPPORTED]) {
+		int supported = mnl_attr_get_u8(
+			tb[ETHTOOL_A_PREEMPT_SUPPORTED]);
+
+		printf("\tsupport: %s\n",
+		       supported ? "supported" : "not supported");
+	}
+	if (tb[ETHTOOL_A_PREEMPT_ACTIVE]) {
+		int active = mnl_attr_get_u8(tb[ETHTOOL_A_PREEMPT_ACTIVE]);
+
+		printf("\tactive: %s\n", active ? "active" : "not active");
+	}
+	if (tb[ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED]) {
+		uint32_t queues = mnl_attr_get_u32(
+			tb[ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED]);
+
+		printf("\tsupported queues: %#x\n", queues);
+
+	}
+	if (tb[ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE]) {
+		uint32_t queues = mnl_attr_get_u32(
+			tb[ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE]);
+
+		printf("\tsupported queues: %#x\n", queues);
+
+	}
+	if (tb[ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE]) {
+		uint32_t min_frag_size = mnl_attr_get_u32(
+			tb[ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE]);
+
+		printf("\tminimum fragment size: %d\n", min_frag_size);
+	}
+	return MNL_CB_OK;
+}
+
+int nl_get_preempt(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx = ctx->nlctx;
+	struct nl_socket *nlsk = nlctx->ethnl_socket;
+	int ret;
+
+	ret = preempt_get_prep_request(nlsk);
+	if (ret < 0)
+		return ret;
+	return nlsock_send_get_request(nlsk, preempt_get_reply_cb);
+}
+
+static const struct lookup_entry_u8 fp_values[] = {
+	{ .arg = "off",		.val = 0 },
+	{ .arg = "on",		.val = 1 },
+	{}
+};
+
+static const struct param_parser set_preempt_params[] = {
+	{
+		.arg		= "fp",
+		.group		= ETHTOOL_MSG_PREEMPT_SET,
+		.type		= ETHTOOL_A_PREEMPT_ACTIVE,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= fp_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "preemptible-queues-mask",
+		.group		= ETHTOOL_MSG_PREEMPT_SET,
+		.type		= ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "min-frag-size",
+		.group		= ETHTOOL_MSG_PREEMPT_SET,
+		.type		= ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{}
+};
+
+int nl_set_preempt(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx = ctx->nlctx;
+	int ret;
+
+	nlctx->cmd = "--set-frame-preemption";
+	nlctx->argp = ctx->argp;
+	nlctx->argc = ctx->argc;
+	nlctx->devname = ctx->devname;
+
+	ret = nl_parser(nlctx, set_preempt_params, NULL, PARSER_GROUP_MSG);
+	if (ret < 0)
+		return 1;
+
+	if (ret == 0)
+		return 0;
+	return nlctx->exit_code ?: 75;
+}