aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Kubecek <mkubecek@suse.cz>2020-05-29 01:21:57 +0200
committerMichal Kubecek <mkubecek@suse.cz>2020-06-07 19:11:06 +0200
commit99a46916838dd379f7f554fa83a96079221bd0db (patch)
tree8e57c3f371371ac42ef4546bb0e48710e9bddd38
parent068a0bbc8cbd7dc4cb77066b946820aaf520fcf8 (diff)
downloadethtool-99a46916838dd379f7f554fa83a96079221bd0db.tar.gz
netlink: add netlink handler for sprivflags (--set-priv-flags)
Implement "ethtool --set-priv-flags <dev> ..." subcommand to set device private flags using ETHTOOL_MSG_PRIVFLAGS_SET netlink message. These are traditionally set using ETHTOOL_SPFLAGS ioctl request. Unlike ioctl implementation, netlink does not retrieve private flag names first so that names provided on command line are validated by kernel rather than by parser. Unrecognized names are therefore interpreted as a failed request rather than a parser error. Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
-rw-r--r--ethtool.c1
-rw-r--r--netlink/extapi.h2
-rw-r--r--netlink/privflags.c51
3 files changed, 53 insertions, 1 deletions
diff --git a/ethtool.c b/ethtool.c
index 843c710..81472ad 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5383,6 +5383,7 @@ static const struct option args[] = {
{
.opts = "--set-priv-flags",
.func = do_sprivflags,
+ .nlfunc = nl_sprivflags,
.help = "Set private flags",
.xhelp = " FLAG on|off ...\n"
},
diff --git a/netlink/extapi.h b/netlink/extapi.h
index 1bbe3fc..ec5d086 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -23,6 +23,7 @@ int nl_permaddr(struct cmd_context *ctx);
int nl_gfeatures(struct cmd_context *ctx);
int nl_sfeatures(struct cmd_context *ctx);
int nl_gprivflags(struct cmd_context *ctx);
+int nl_sprivflags(struct cmd_context *ctx);
int nl_monitor(struct cmd_context *ctx);
void nl_monitor_usage(void);
@@ -50,6 +51,7 @@ static inline void nl_monitor_usage(void)
#define nl_gfeatures NULL
#define nl_sfeatures NULL
#define nl_gprivflags NULL
+#define nl_sprivflags NULL
#endif /* ETHTOOL_ENABLE_NETLINK */
diff --git a/netlink/privflags.c b/netlink/privflags.c
index b552c21..a06cd6d 100644
--- a/netlink/privflags.c
+++ b/netlink/privflags.c
@@ -1,7 +1,8 @@
/*
* privflags.c - netlink implementation of private flags commands
*
- * Implementation of "ethtool --show-priv-flags <dev>"
+ * Implementation of "ethtool --show-priv-flags <dev>" and
+ * "ethtool --set-priv-flags <dev> ..."
*/
#include <errno.h>
@@ -13,6 +14,7 @@
#include "netlink.h"
#include "strset.h"
#include "bitset.h"
+#include "parser.h"
/* PRIVFLAGS_GET */
@@ -107,3 +109,50 @@ int nl_gprivflags(struct cmd_context *ctx)
return ret;
return nlsock_send_get_request(nlsk, privflags_reply_cb);
}
+
+/* PRIVFLAGS_SET */
+
+static const struct bitset_parser_data privflags_parser_data = {
+ .force_hex = false,
+ .no_mask = false,
+};
+
+int nl_sprivflags(struct cmd_context *ctx)
+{
+ struct nl_context *nlctx = ctx->nlctx;
+ struct nl_msg_buff *msgbuff;
+ struct nl_socket *nlsk;
+ int ret;
+
+ if (netlink_cmd_check(ctx, ETHTOOL_MSG_PRIVFLAGS_SET, false))
+ return -EOPNOTSUPP;
+
+ nlctx->cmd = "--set-priv-flags";
+ nlctx->argp = ctx->argp;
+ nlctx->argc = ctx->argc;
+ nlctx->devname = ctx->devname;
+ nlsk = nlctx->ethnl_socket;
+ msgbuff = &nlsk->msgbuff;
+
+ ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_PRIVFLAGS_SET,
+ NLM_F_REQUEST | NLM_F_ACK);
+ if (ret < 0)
+ return 2;
+ if (ethnla_fill_header(msgbuff, ETHTOOL_A_PRIVFLAGS_HEADER,
+ ctx->devname, 0))
+ return -EMSGSIZE;
+
+ ret = nl_parse_bitset(nlctx, ETHTOOL_A_PRIVFLAGS_FLAGS,
+ &privflags_parser_data, msgbuff, NULL);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = nlsock_sendmsg(nlsk, NULL);
+ if (ret < 0)
+ return 2;
+ ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
+ if (ret == 0)
+ return 0;
+ else
+ return nlctx->exit_code ?: 1;
+}