From: Leon Romanovsky <leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
To: David Ahern <dsahern-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: RDMA mailing list
<linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
Steve Wise
<swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org>,
Leon Romanovsky <leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
netdev <netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
Stephen Hemminger
<stephen-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ@public.gmane.org>,
Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Subject: [PATCH iproute2-next 03/10] rdma: Add filtering infrastructure
Date: Wed, 31 Jan 2018 10:11:49 +0200 [thread overview]
Message-ID: <20180131081156.19607-4-leon@kernel.org> (raw)
In-Reply-To: <20180131081156.19607-1-leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
From: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
This patch adds general infrastructure to RDMAtool to handle various
filtering options needed for the downstream resource tracking patches.
The infrastructure is generic and stores filters in list of key<->value
entries. There are three types of filters:
1. Numeric - the values are intended to be digits combined with '-' to
mark range and ',' to mark multiple entries, e.g. pid 1-100,234,400-401
is perfectly legit filter to limit process ids.
2. String - the values are consist from strings and "," as a denominator.
3. Link - special case to allow '/' in string to provide link name, e.g.
link mlx4_1/2.
Signed-off-by: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
rdma/rdma.c | 1 +
rdma/rdma.h | 20 ++++++
rdma/utils.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 250 insertions(+)
diff --git a/rdma/rdma.c b/rdma/rdma.c
index 0e8fd688..a21ba440 100644
--- a/rdma/rdma.c
+++ b/rdma/rdma.c
@@ -47,6 +47,7 @@ static int rd_init(struct rd *rd, int argc, char **argv, char *filename)
rd->argc = argc;
rd->argv = argv;
INIT_LIST_HEAD(&rd->dev_map_list);
+ INIT_LIST_HEAD(&rd->filter_list);
if (rd->json_output) {
rd->jw = jsonw_new(stdout);
diff --git a/rdma/rdma.h b/rdma/rdma.h
index 1b66ae04..8e60ce26 100644
--- a/rdma/rdma.h
+++ b/rdma/rdma.h
@@ -29,6 +29,18 @@
#define RDMA_BITMAP_ENUM(name, bit_no) RDMA_BITMAP_##name = BIT(bit_no),
#define RDMA_BITMAP_NAMES(name, bit_no) [bit_no] = #name,
+#define MAX_NUMBER_OF_FILTERS 64
+struct filters {
+ char name[32];
+ bool is_number;
+};
+
+struct filter_entry {
+ struct list_head list;
+ char *key;
+ char *value;
+};
+
struct dev_map {
struct list_head list;
char *dev_name;
@@ -50,6 +62,7 @@ struct rd {
json_writer_t *jw;
bool json_output;
bool pretty_output;
+ struct list_head filter_list;
};
struct rd_cmd {
@@ -81,6 +94,13 @@ int rd_argc(struct rd *rd);
*/
struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index);
+/*
+ * Filter manipulation
+ */
+int rd_build_filter(struct rd *rd, const struct filters valid_filters[]);
+bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val);
+bool rd_check_is_string_filtered(struct rd *rd, const char *key, const char *val);
+bool rd_check_is_key_exist(struct rd *rd, const char *key);
/*
* Netlink
*/
diff --git a/rdma/utils.c b/rdma/utils.c
index af2b374d..157699c0 100644
--- a/rdma/utils.c
+++ b/rdma/utils.c
@@ -114,6 +114,234 @@ static void dev_map_cleanup(struct rd *rd)
}
}
+static int add_filter(struct rd *rd, char *key, char *value,
+ const struct filters valid_filters[])
+{
+ char cset[] = "1234567890,-";
+ struct filter_entry *fe;
+ bool key_found = false;
+ int idx = 0;
+ int ret;
+
+ fe = calloc(1, sizeof(*fe));
+ if (!fe)
+ return -ENOMEM;
+
+ while (idx < MAX_NUMBER_OF_FILTERS && valid_filters[idx].name) {
+ if (!strcmpx(key, valid_filters[idx].name)) {
+ key_found = true;
+ break;
+ }
+ idx++;
+ }
+ if (!key_found) {
+ pr_err("Unsupported filter option: %s\n", key);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Check the filter validity, not optimal, but works
+ *
+ * Actually, there are three types of filters
+ * numeric - for example PID or QPN
+ * string - for example states
+ * link - user requested to filter on specific link
+ * e.g. mlx5_1/1, mlx5_1/-, mlx5_1 ...
+ */
+ if (valid_filters[idx].is_number &&
+ strspn(value, cset) != strlen(value)) {
+ pr_err("%s filter accepts \"%s\" characters only\n", key, cset);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ fe->key = strdup(key);
+ fe->value = strdup(value);
+ if (!fe->key || !fe->value) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ for (idx = 0; idx < strlen(fe->value); idx++)
+ fe->value[idx] = tolower(fe->value[idx]);
+
+ list_add_tail(&fe->list, &rd->filter_list);
+ return 0;
+
+err_alloc:
+ free(fe->value);
+ free(fe->key);
+err:
+ free(fe);
+ return ret;
+}
+
+int rd_build_filter(struct rd *rd, const struct filters valid_filters[])
+{
+ int ret = 0;
+ int idx = 0;
+
+ if (!valid_filters || !rd_argc(rd))
+ goto out;
+
+ if (rd_argc(rd) == 1) {
+ pr_err("No filter data was supplied to filter option %s\n", rd_argv(rd));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (rd_argc(rd) % 2) {
+ pr_err("There is filter option without data\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ while (idx != rd_argc(rd)) {
+ /*
+ * We can do micro-optimization and skip "dev"
+ * and "link" filters, but it is not worth of it.
+ */
+ ret = add_filter(rd, *(rd->argv + idx),
+ *(rd->argv + idx + 1), valid_filters);
+ if (ret)
+ goto out;
+ idx += 2;
+ }
+
+out:
+ return ret;
+}
+
+bool rd_check_is_key_exist(struct rd *rd, const char *key)
+{
+ struct filter_entry *fe;
+
+ list_for_each_entry(fe, &rd->filter_list, list) {
+ if (!strcmpx(fe->key, key))
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Check if string entry is filtered:
+ * * key doesn't exist -> user didn't request -> not filtered
+ */
+bool rd_check_is_string_filtered(struct rd *rd,
+ const char *key, const char *val)
+{
+ bool key_is_filtered = false;
+ struct filter_entry *fe;
+ char *p = NULL;
+ char *str;
+
+ list_for_each_entry(fe, &rd->filter_list, list) {
+ if (!strcmpx(fe->key, key)) {
+ /* We found the key */
+ p = strdup(fe->value);
+ key_is_filtered = true;
+ if (!p) {
+ /*
+ * Something extremely wrong if we fail
+ * to allocate small amount of bytes.
+ */
+ pr_err("Found key, but failed to allocate memory to store value\n");
+ return key_is_filtered;
+ }
+
+ /*
+ * Need to check if value in range
+ * It can come in the following formats
+ * and their permutations:
+ * str
+ * str1,str2
+ */
+ str = strtok(p, ",");
+ while (str) {
+ if (strlen(str) == strlen(val) &&
+ !strcasecmp(str, val)) {
+ key_is_filtered = false;
+ goto out;
+ }
+ str = strtok(NULL, ",");
+ }
+ goto out;
+ }
+ }
+
+out:
+ free(p);
+ return key_is_filtered;
+}
+
+/*
+ * Check if key is filtered:
+ * key doesn't exist -> user didn't request -> not filtered
+ */
+bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val)
+{
+ bool key_is_filtered = false;
+ struct filter_entry *fe;
+
+ list_for_each_entry(fe, &rd->filter_list, list) {
+ uint32_t left_val = 0, fe_value = 0;
+ bool range_check = false;
+ char *p = fe->value;
+
+ if (!strcmpx(fe->key, key)) {
+ /* We found the key */
+ key_is_filtered = true;
+ /*
+ * Need to check if value in range
+ * It can come in the following formats
+ * (and their permutations):
+ * numb
+ * numb1,numb2
+ * ,numb1,numb2
+ * numb1-numb2
+ * numb1,numb2-numb3,numb4-numb5
+ */
+ while (*p) {
+ if (isdigit(*p)) {
+ fe_value = strtol(p, &p, 10);
+ if (fe_value == val ||
+ (range_check && left_val < val &&
+ val < fe_value)) {
+ key_is_filtered = false;
+ goto out;
+ }
+ range_check = false;
+ } else {
+ if (*p == '-') {
+ left_val = fe_value;
+ range_check = true;
+ }
+ p++;
+ }
+ }
+ goto out;
+ }
+ }
+
+out:
+ return key_is_filtered;
+}
+
+static void filters_cleanup(struct rd *rd)
+{
+ struct filter_entry *fe, *tmp;
+
+ list_for_each_entry_safe(fe, tmp,
+ &rd->filter_list, list) {
+ list_del(&fe->list);
+ free(fe->key);
+ free(fe->value);
+ free(fe);
+ }
+}
+
static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
[RDMA_NLDEV_ATTR_DEV_INDEX] = MNL_TYPE_U32,
[RDMA_NLDEV_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
@@ -181,6 +409,7 @@ void rd_free(struct rd *rd)
return;
free(rd->buff);
dev_map_cleanup(rd);
+ filters_cleanup(rd);
}
int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port)
--
2.16.1
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2018-01-31 8:11 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-31 8:11 [PATCH iproute2-next 00/10] RDMA resource tracking Leon Romanovsky
2018-01-31 8:11 ` [PATCH iproute2-next 01/10] rdma: Add option to provide "-" sign for the port number Leon Romanovsky
2018-01-31 8:11 ` [PATCH iproute2-next 02/10] rdma: Make visible the number of arguments Leon Romanovsky
2018-01-31 8:11 ` [PATCH iproute2-next 04/10] rdma: Set pointer to device name position Leon Romanovsky
2018-01-31 8:11 ` [PATCH iproute2-next 05/10] rdma: Allow external usage of compare string routine Leon Romanovsky
2018-01-31 8:11 ` [PATCH iproute2-next 06/10] rdma: Update kernel header file Leon Romanovsky
[not found] ` <20180131081156.19607-1-leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2018-01-31 8:11 ` Leon Romanovsky [this message]
2018-01-31 8:11 ` [PATCH iproute2-next 07/10] rdma: Add resource tracking summary Leon Romanovsky
2018-01-31 8:11 ` [PATCH iproute2-next 08/10] rdma: Add QP resource tracking information Leon Romanovsky
[not found] ` <20180131081156.19607-9-leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2018-02-01 20:05 ` Steve Wise
2018-02-05 13:22 ` Leon Romanovsky
[not found] ` <20180205132231.GD2567-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2018-02-05 14:00 ` Leon Romanovsky
[not found] ` <20180205140037.GF2567-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2018-02-05 16:21 ` David Ahern
2018-01-31 8:17 ` [PATCH iproute2-next 00/10] RDMA resource tracking Leon Romanovsky
2018-02-06 1:25 ` Stephen Hemminger
2018-02-06 7:29 ` Leon Romanovsky
2018-01-31 8:11 ` [PATCH iproute2-next 09/10] rdma: Document " Leon Romanovsky
2018-01-31 8:11 ` [PATCH iproute2-next 10/10] rdma: Check return value of strdup call Leon Romanovsky
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=20180131081156.19607-4-leon@kernel.org \
--to=leon-dgejt+ai2ygdnm+yrofe0a@public.gmane.org \
--cc=dsahern-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
--cc=leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org \
--cc=linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=stephen-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ@public.gmane.org \
--cc=swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.