[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <980e7809d287030917a3cdaf73cbd325cd62fd0e.1583513281.git.mkubecek@suse.cz>
Date: Fri, 6 Mar 2020 18:05:05 +0100 (CET)
From: Michal Kubecek <mkubecek@...e.cz>
To: John Linville <linville@...driver.com>, netdev@...r.kernel.org
Cc: Andrew Lunn <andrew@...n.ch>,
Florian Fainelli <f.fainelli@...il.com>
Subject: [PATCH ethtool v3 13/25] netlink: add bitset helpers
Add basic functions for work with arbitrary length bitsets used in ethtool
netlink interface.
The most important function is walk_bitset() which iterates through bits of
a bitset (passed as pointer to the nest attribute) and calls provided
callback for each bit.
v2:
- add bitset_is_compact() helper
Signed-off-by: Michal Kubecek <mkubecek@...e.cz>
---
Makefile.am | 2 +-
netlink/bitset.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++
netlink/bitset.h | 26 ++++++
3 files changed, 245 insertions(+), 1 deletion(-)
create mode 100644 netlink/bitset.c
create mode 100644 netlink/bitset.h
diff --git a/Makefile.am b/Makefile.am
index e6abd3f79cd7..616c45007fbd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,7 +28,7 @@ ethtool_SOURCES += \
netlink/netlink.c netlink/netlink.h netlink/extapi.h \
netlink/msgbuff.c netlink/msgbuff.h netlink/nlsock.c \
netlink/nlsock.h netlink/strset.c netlink/strset.h \
- netlink/monitor.c \
+ netlink/monitor.c netlink/bitset.c netlink/bitset.h \
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/netlink/bitset.c b/netlink/bitset.c
new file mode 100644
index 000000000000..ed109ec1d2c0
--- /dev/null
+++ b/netlink/bitset.c
@@ -0,0 +1,218 @@
+/*
+ * bitset.h - netlink bitset helpers
+ *
+ * Functions for easier handling of ethtool netlink bitset attributes.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "../common.h"
+#include "netlink.h"
+#include "bitset.h"
+
+uint32_t bitset_get_count(const struct nlattr *bitset, int *retptr)
+{
+ const struct nlattr *attr;
+
+ mnl_attr_for_each_nested(attr, bitset) {
+ if (mnl_attr_get_type(attr) != ETHTOOL_A_BITSET_SIZE)
+ continue;
+ *retptr = 0;
+ return mnl_attr_get_u32(attr);
+ }
+
+ *retptr = -EFAULT;
+ return 0;
+}
+
+bool bitset_is_compact(const struct nlattr *bitset)
+{
+ const struct nlattr *attr;
+
+ mnl_attr_for_each_nested(attr, bitset) {
+ switch(mnl_attr_get_type(attr)) {
+ case ETHTOOL_A_BITSET_BITS:
+ return 0;
+ case ETHTOOL_A_BITSET_VALUE:
+ case ETHTOOL_A_BITSET_MASK:
+ return 1;
+ }
+ }
+
+ return false;
+}
+
+bool bitset_get_bit(const struct nlattr *bitset, bool mask, unsigned int idx,
+ int *retptr)
+{
+ const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {};
+ DECLARE_ATTR_TB_INFO(bitset_tb);
+ const struct nlattr *bits;
+ const struct nlattr *bit;
+ int ret;
+
+ *retptr = 0;
+ ret = mnl_attr_parse_nested(bitset, attr_cb, &bitset_tb_info);
+ if (ret < 0)
+ goto err;
+
+ bits = mask ? bitset_tb[ETHTOOL_A_BITSET_MASK] :
+ bitset_tb[ETHTOOL_A_BITSET_VALUE];
+ if (bits) {
+ const uint32_t *bitmap =
+ (const uint32_t *)mnl_attr_get_payload(bits);
+
+ if (idx >= 8 * mnl_attr_get_payload_len(bits))
+ return false;
+ return bitmap[idx / 32] & (1U << (idx % 32));
+ }
+
+ bits = bitset_tb[ETHTOOL_A_BITSET_BITS];
+ if (!bits)
+ goto err;
+ mnl_attr_for_each_nested(bit, bits) {
+ const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {};
+ DECLARE_ATTR_TB_INFO(tb);
+ unsigned int my_idx;
+
+ if (mnl_attr_get_type(bit) != ETHTOOL_A_BITSET_BITS_BIT)
+ continue;
+ ret = mnl_attr_parse_nested(bit, attr_cb, &tb_info);
+ if (ret < 0)
+ goto err;
+ ret = -EFAULT;
+ if (!tb[ETHTOOL_A_BITSET_BIT_INDEX])
+ goto err;
+
+ my_idx = mnl_attr_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);
+ if (my_idx == idx)
+ return mask || tb[ETHTOOL_A_BITSET_BIT_VALUE];
+ }
+
+ return false;
+err:
+ fprintf(stderr, "malformed netlink message (bitset)\n");
+ *retptr = ret;
+ return false;
+}
+
+bool bitset_is_empty(const struct nlattr *bitset, bool mask, int *retptr)
+{
+ const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {};
+ DECLARE_ATTR_TB_INFO(bitset_tb);
+ const struct nlattr *bits;
+ const struct nlattr *bit;
+ int ret;
+
+ *retptr = 0;
+ ret = mnl_attr_parse_nested(bitset, attr_cb, &bitset_tb_info);
+ if (ret < 0)
+ goto err;
+
+ bits = mask ? bitset_tb[ETHTOOL_A_BITSET_MASK] :
+ bitset_tb[ETHTOOL_A_BITSET_VALUE];
+ if (bits) {
+ const uint32_t *bitmap =
+ (const uint32_t *)mnl_attr_get_payload(bits);
+ unsigned int n = mnl_attr_get_payload_len(bits);
+ unsigned int i;
+
+ ret = -EFAULT;
+ if (n % 4)
+ goto err;
+ for (i = 0; i < n / 4; i++)
+ if (bitmap[i])
+ return false;
+ return true;
+ }
+
+ bits = bitset_tb[ETHTOOL_A_BITSET_BITS];
+ if (!bits)
+ goto err;
+ mnl_attr_for_each_nested(bit, bits) {
+ const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {};
+ DECLARE_ATTR_TB_INFO(tb);
+
+ if (mnl_attr_get_type(bit) != ETHTOOL_A_BITSET_BITS_BIT)
+ continue;
+ if (mask || bitset_tb[ETHTOOL_A_BITSET_NOMASK])
+ return false;
+
+ ret = mnl_attr_parse_nested(bit, attr_cb, &tb_info);
+ if (ret < 0)
+ goto err;
+ if (tb[ETHTOOL_A_BITSET_BIT_VALUE])
+ return false;
+ }
+
+ return true;
+err:
+ fprintf(stderr, "malformed netlink message (bitset)\n");
+ *retptr = ret;
+ return true;
+}
+
+int walk_bitset(const struct nlattr *bitset, const struct stringset *labels,
+ bitset_walk_callback cb, void *data)
+{
+ const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {};
+ DECLARE_ATTR_TB_INFO(bitset_tb);
+ const struct nlattr *bits;
+ const struct nlattr *bit;
+ bool is_list;
+ int ret;
+
+ ret = mnl_attr_parse_nested(bitset, attr_cb, &bitset_tb_info);
+ if (ret < 0)
+ return ret;
+ is_list = bitset_tb[ETHTOOL_A_BITSET_NOMASK];
+
+ bits = bitset_tb[ETHTOOL_A_BITSET_VALUE];
+ if (bits) {
+ const struct nlattr *mask = bitset_tb[ETHTOOL_A_BITSET_MASK];
+ unsigned int count, nwords, idx;
+ uint32_t *val_bm;
+ uint32_t *mask_bm;
+
+ if (!bitset_tb[ETHTOOL_A_BITSET_SIZE])
+ return -EFAULT;
+ count = mnl_attr_get_u32(bitset_tb[ETHTOOL_A_BITSET_SIZE]);
+ nwords = (count + 31) / 32;
+ if ((mnl_attr_get_payload_len(bits) / 4 < nwords) ||
+ (mask && mnl_attr_get_payload_len(mask) / 4 < nwords))
+ return -EFAULT;
+
+ val_bm = mnl_attr_get_payload(bits);
+ mask_bm = mask ? mnl_attr_get_payload(mask) : NULL;
+ for (idx = 0; idx < count; idx++)
+ if (!mask_bm || (mask_bm[idx / 32] & (1 << (idx % 32))))
+ cb(idx, get_string(labels, idx),
+ val_bm[idx / 32] & (1 << (idx % 32)), data);
+ return 0;
+ }
+
+ bits = bitset_tb[ETHTOOL_A_BITSET_BITS];
+ if (!bits)
+ return -EFAULT;
+ mnl_attr_for_each_nested(bit, bits) {
+ const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {};
+ DECLARE_ATTR_TB_INFO(tb);
+ const char *name;
+ unsigned int idx;
+
+ if (mnl_attr_get_type(bit) != ETHTOOL_A_BITSET_BITS_BIT)
+ continue;
+
+ ret = mnl_attr_parse_nested(bit, attr_cb, &tb_info);
+ if (ret < 0 || !tb[ETHTOOL_A_BITSET_BIT_INDEX] ||
+ !tb[ETHTOOL_A_BITSET_BIT_NAME])
+ return -EFAULT;
+
+ idx = mnl_attr_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);
+ name = mnl_attr_get_str(tb[ETHTOOL_A_BITSET_BIT_NAME]);
+ cb(idx, name, is_list || tb[ETHTOOL_A_BITSET_BIT_VALUE], data);
+ }
+
+ return 0;
+}
diff --git a/netlink/bitset.h b/netlink/bitset.h
new file mode 100644
index 000000000000..4b587d2c8a04
--- /dev/null
+++ b/netlink/bitset.h
@@ -0,0 +1,26 @@
+/*
+ * bitset.h - netlink bitset helpers
+ *
+ * Declarations of helpers for handling ethtool netlink bitsets.
+ */
+
+#ifndef ETHTOOL_NETLINK_BITSET_H__
+#define ETHTOOL_NETLINK_BITSET_H__
+
+#include <libmnl/libmnl.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <linux/ethtool_netlink.h>
+#include "strset.h"
+
+typedef void (*bitset_walk_callback)(unsigned int, const char *, bool, void *);
+
+uint32_t bitset_get_count(const struct nlattr *bitset, int *retptr);
+bool bitset_get_bit(const struct nlattr *bitset, bool mask, unsigned int idx,
+ int *retptr);
+bool bitset_is_compact(const struct nlattr *bitset);
+bool bitset_is_empty(const struct nlattr *bitset, bool mask, int *retptr);
+int walk_bitset(const struct nlattr *bitset, const struct stringset *labels,
+ bitset_walk_callback cb, void *data);
+
+#endif /* ETHTOOL_NETLINK_BITSET_H__ */
--
2.25.1
Powered by blists - more mailing lists