linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michal Kubecek <mkubecek@suse.cz>
To: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org,
	"John W. Linville" <linville@tuxdriver.com>
Subject: [RFC PATCH ethtool v2 04/23] netlink: add support for string sets
Date: Mon, 30 Jul 2018 14:56:04 +0200 (CEST)	[thread overview]
Message-ID: <1ef092fff9b6e691163d11735dc9d807f485f2ec.1532954671.git.mkubecek@suse.cz> (raw)
In-Reply-To: <cover.1532954671.git.mkubecek@suse.cz>

Add infrastructure for querying kernel string sets (analog to ioct commands
ETHTOOL_GSSET_INFO and ETHTOOL_GSTRINGS).

Let notification monitor request string sets on start so that it can
resolve bit indices to names when processing bitsets in compact format.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Makefile.am      |   1 +
 netlink/strset.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++
 netlink/strset.h |  16 +++
 3 files changed, 282 insertions(+)
 create mode 100644 netlink/strset.c
 create mode 100644 netlink/strset.h

diff --git a/Makefile.am b/Makefile.am
index bdb4f4df2b0f..6a4d7083919e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,6 +22,7 @@ endif
 if ETHTOOL_ENABLE_NETLINK
 ethtool_SOURCES += \
 		  netlink/netlink.c netlink/netlink.h netlink/extapi.h \
+		  netlink/strset.c netlink/strset.h \
 		  uapi/linux/ethtool_netlink.h \
 		  uapi/linux/netlink.h uapi/linux/genetlink.h
 ethtool_CFLAGS += @MNL_CFLAGS@
diff --git a/netlink/strset.c b/netlink/strset.c
new file mode 100644
index 000000000000..9ea456748531
--- /dev/null
+++ b/netlink/strset.c
@@ -0,0 +1,265 @@
+#include <errno.h>
+#include <string.h>
+
+#include "../internal.h"
+#include "netlink.h"
+
+struct stringset {
+	const char		**strings;
+	void			*raw_data;
+	unsigned int		count;
+};
+
+struct perdev_strings {
+	char			devname[IFNAMSIZ];
+	struct stringset	strings[ETH_SS_MAX + 1];
+	struct perdev_strings	*next;
+};
+
+/* universal string sets */
+static struct stringset global_strings[ETH_SS_MAX + 1];
+/* linked list of string sets related to network devices */
+static struct perdev_strings *device_strings;
+
+static void drop_stringset(struct stringset *set)
+{
+	free(set->strings);
+	free(set->raw_data);
+	set->count = 0;
+}
+
+static int import_stringset(struct stringset *dest, const struct nlattr *nest)
+{
+	const struct nlattr *tb_stringset[ETHA_STRINGSET_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb_stringset);
+	const struct nlattr *string;
+	unsigned int size;
+	unsigned int count;
+	unsigned int idx;
+	int ret;
+
+	ret = mnl_attr_parse_nested(nest, attr_cb, &tb_stringset_info);
+	if (ret < 0)
+		return ret;
+	if (!tb_stringset[ETHA_STRINGSET_ID] ||
+	    !tb_stringset[ETHA_STRINGSET_COUNT] ||
+	    !tb_stringset[ETHA_STRINGSET_STRINGS])
+		return -EFAULT;
+	idx = mnl_attr_get_u32(tb_stringset[ETHA_STRINGSET_ID]);
+	if (idx > ETH_SS_MAX)
+		return 0;
+	count = mnl_attr_get_u32(tb_stringset[ETHA_STRINGSET_COUNT]);
+	if (count == 0)
+		return 0;
+
+	size = mnl_attr_get_len(tb_stringset[ETHA_STRINGSET_STRINGS]);
+	ret = -ENOMEM;
+	dest[idx].raw_data = malloc(size);
+	if (!dest[idx].raw_data)
+		goto err;
+	memcpy(dest[idx].raw_data, tb_stringset[ETHA_STRINGSET_STRINGS], size);
+	dest[idx].strings = malloc(count * sizeof(dest[idx].strings[0]));
+	if (!dest[idx].strings)
+		goto err;
+	dest[idx].count = count;
+
+	nest = dest[idx].raw_data;
+	mnl_attr_for_each_nested(string, nest) {
+		const struct nlattr *tb[ETHA_STRING_MAX + 1] = {};
+		DECLARE_ATTR_TB_INFO(tb);
+		unsigned int i;
+
+		if (mnl_attr_get_type(string) != ETHA_STRINGS_STRING)
+			continue;
+		ret = mnl_attr_parse_nested(string, attr_cb, &tb_info);
+		if (ret < 0)
+			goto err;
+		ret = -EFAULT;
+		if (!tb[ETHA_STRING_INDEX] || !tb[ETHA_STRING_VALUE])
+			goto err;
+
+		i = mnl_attr_get_u32(tb[ETHA_STRING_INDEX]);
+		if (i >= count)
+			goto err;
+		dest[idx].strings[i] =
+			mnl_attr_get_payload(tb[ETHA_STRING_VALUE]);
+	}
+
+	return 0;
+err:
+	drop_stringset(&dest[idx]);
+	return ret;
+}
+
+static const char *stringset_names[] = {
+	[ETH_SS_TEST] = "test",
+	[ETH_SS_STATS] = "stats",
+	[ETH_SS_PRIV_FLAGS] = "priv-flags",
+	[ETH_SS_NTUPLE_FILTERS] = "ntuple-filters",
+	[ETH_SS_FEATURES] = "features",
+	[ETH_SS_RSS_HASH_FUNCS] = "rss-hash-funcs",
+	[ETH_SS_TUNABLES] = "tunables",
+	[ETH_SS_PHY_STATS] = "phy-stats",
+	[ETH_SS_PHY_TUNABLES] = "phy-tunables",
+	[ETH_SS_LINK_MODES] = "link-modes",
+};
+
+void debug_stringsets(const struct stringset *sets)
+{
+	unsigned int i;
+
+	for (i = 0; i <= ETH_SS_MAX; i++) {
+		if (sets[i].count > 0) {
+			printf("    set %s, count %u\n", stringset_names[i],
+			       sets[i].count);
+		}
+	}
+}
+
+void debug_strings()
+{
+	struct perdev_strings *pd;
+
+	fputs("global strings:\n", stdout);
+	debug_stringsets(global_strings);
+
+	for (pd = device_strings; pd; pd = pd->next) {
+		printf("strings for %s:\n", pd->devname);
+		debug_stringsets(pd->strings);
+	}
+}
+
+static int strset_reply_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct nlattr *tb[ETHA_STRSET_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	struct nl_context *nlctx = data;
+	struct stringset *dest;
+	struct nlattr *attr;
+	unsigned int i;
+	int ret;
+
+	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
+	if (ret < 0)
+		return ret;
+	nlctx->devname = get_dev_name(tb[ETHA_STRSET_DEV]);
+	if (!dev_ok(nlctx))
+		return MNL_CB_OK;
+
+	if (nlctx->devname) {
+		struct perdev_strings *perdev = device_strings;
+
+		while (perdev && strcmp(perdev->devname, nlctx->devname))
+			perdev = perdev->next;
+		if (perdev) {
+			for (i = 0; i <= ETH_SS_MAX; i++)
+				drop_stringset(&perdev->strings[i]);
+		} else {
+			perdev = calloc(sizeof(*perdev), 1);
+			if (!perdev)
+				return -ENOMEM;
+			strncpy(perdev->devname, nlctx->devname, IFNAMSIZ);
+			perdev->devname[IFNAMSIZ - 1] = '\0';
+			perdev->next = device_strings;
+			device_strings = perdev;
+		}
+		dest = perdev->strings;
+	} else {
+		for (i = 0; i <= ETH_SS_MAX; i++)
+			drop_stringset(&global_strings[i]);
+		dest = global_strings;
+	}
+
+	mnl_attr_for_each(attr, nlhdr, GENL_HDRLEN) {
+		if (mnl_attr_get_type(attr) == ETHA_STRSET_STRINGSET)
+			import_stringset(dest, attr);
+	}
+
+	return MNL_CB_OK;
+}
+
+/* interface */
+
+const struct stringset *global_stringset(unsigned int type)
+{
+	if (type > ETH_SS_MAX)
+		return NULL;
+	return &global_strings[type];
+}
+
+const struct stringset *perdev_stringset(const char *dev, unsigned int type)
+{
+	const struct perdev_strings *p;
+
+	if (type > ETH_SS_MAX)
+		return NULL;
+	for (p = device_strings; p; p = p->next)
+		if (!strcmp(p->devname, dev))
+			return &p->strings[type];
+
+	return NULL;
+}
+
+unsigned int get_count(const struct stringset *set)
+{
+	return set->count;
+}
+
+const char *get_string(const struct stringset *set, unsigned int idx)
+{
+	if (idx > set->count)
+		return NULL;
+	return set->strings[idx];
+}
+
+int load_global_strings(struct nl_context *nlctx)
+{
+	int ret;
+
+	ret = msg_init(nlctx, ETHNL_CMD_GET_STRSET, NLM_F_REQUEST | NLM_F_ACK);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_send_get_request(nlctx, strset_reply_cb);
+	return ret;
+}
+
+int load_perdev_strings(struct nl_context *nlctx, const char *dev)
+{
+	int ret;
+
+	ret = msg_init(nlctx, ETHNL_CMD_GET_STRSET,
+		       NLM_F_REQUEST | NLM_F_ACK | (dev ? 0 : NLM_F_DUMP));
+	if (ret < 0)
+		return ret;
+	if (dev) {
+		if (ethnla_put_dev(nlctx, ETHA_STRSET_DEV, dev))
+			return -EMSGSIZE;
+	}
+	ret = ethnl_send_get_request(nlctx, strset_reply_cb);
+	return ret;
+}
+
+void free_perdev_strings(const char *devname)
+{
+	struct perdev_strings **p = &device_strings;
+	unsigned int i;
+
+	p = &device_strings;
+	while (*p) {
+		struct perdev_strings *perdev = *p;
+
+		if (devname && strcmp(perdev->devname, devname)) {
+			p = &((*p)->next);
+			continue;
+		}
+		*p = perdev->next;
+		for (i = 0; i <= ETH_SS_MAX; i++)
+			drop_stringset(&perdev->strings[i]);
+		free(perdev);
+	}
+
+	if (!devname) {
+		for (i = 0; i <= ETH_SS_MAX; i++)
+			drop_stringset(&global_strings[i]);
+	}
+}
diff --git a/netlink/strset.h b/netlink/strset.h
new file mode 100644
index 000000000000..81ddf33a5d15
--- /dev/null
+++ b/netlink/strset.h
@@ -0,0 +1,16 @@
+#ifndef ETHTOOL_NETLINK_STRSET_H__
+#define ETHTOOL_NETLINK_STRSET_H__
+
+struct stringset;
+
+const struct stringset *global_stringset(unsigned int type);
+const struct stringset *perdev_stringset(const char *dev, unsigned int type);
+
+unsigned int get_count(const struct stringset *set);
+const char *get_string(const struct stringset *set, unsigned int idx);
+
+int load_global_strings(struct nl_context *nlctx);
+int load_perdev_strings(struct nl_context *nlctx, const char *dev);
+void free_perdev_strings(const char *devname);
+
+#endif /* ETHTOOL_NETLINK_STRSET_H__ */
-- 
2.18.0


  parent reply	other threads:[~2018-07-30 12:58 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-30 12:55 [RFC PATCH ethtool v2 00/23] ethtool netlink interface (userspace side) (WiP) Michal Kubecek
2018-07-30 12:55 ` [RFC PATCH ethtool v2 01/23] move UAPI header copies to a separate directory Michal Kubecek
2018-07-30 12:55 ` [RFC PATCH ethtool v2 02/23] update UAPI header copies Michal Kubecek
2018-07-30 12:55 ` [RFC PATCH ethtool v2 03/23] netlink: add netlink interface Michal Kubecek
2018-07-30 12:56 ` Michal Kubecek [this message]
2018-07-30 12:56 ` [RFC PATCH ethtool v2 05/23] netlink: add notification monitor Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 06/23] netlink: add netlink handler for gdrv (-i) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 07/23] netlink: add netlink handler for gset (no option) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 08/23] netlink: add helpers for command line parsing Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 09/23] netlink: add netlink handler for sset (-s) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 10/23] netlink: add netlink handler for gfeatures (-k) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 11/23] netlink: add netlink handler for sfeatures (-K) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 12/23] netlink: add netlink handler for gcoalesce (-c) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 13/23] netlink: add netlink handler for gring (-g) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 14/23] netlink: add netlink handler for gpause (-a) Michal Kubecek
2018-07-30 12:56 ` [RFC PATCH ethtool v2 15/23] netlink: add netlink handler for gchannels (-l) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 16/23] netlink: add netlink handler for geee (--show-eee) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 17/23] netlink: add netlink handler for gfec (--show-fec) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 18/23] netlink: add netlink handler for scoalesce (-C) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 19/23] netlink: add netlink handler for sring (-G) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 20/23] netlink: add netlink handler for spause (-A) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 21/23] netlink: add netlink handler for schannels (-L) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 22/23] netlink: add netlink handler for seee (--set-eee) Michal Kubecek
2018-07-30 12:57 ` [RFC PATCH ethtool v2 23/23] netlink: add netlink handler for sfec (--set-fec) Michal Kubecek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1ef092fff9b6e691163d11735dc9d807f485f2ec.1532954671.git.mkubecek@suse.cz \
    --to=mkubecek@suse.cz \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linville@tuxdriver.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).