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.go...@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 --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; +} -- 2.26.2