]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
Merge branch 'rdma-object-ids' into next
authorDavid Ahern <dsahern@gmail.com>
Sun, 24 Feb 2019 15:13:21 +0000 (07:13 -0800)
committerDavid Ahern <dsahern@gmail.com>
Sun, 24 Feb 2019 15:13:21 +0000 (07:13 -0800)
Leon Romanovsky says:

====================

This series adds ability to present and query all known to rdmatool
object by their respective, unique IDs (e.g. pdn. mrn, cqn e.t.c).
All objects which have "parent" object has this information too.

====================

Signed-off-by: David Ahern <dsahern@gmail.com>
14 files changed:
rdma/Makefile
rdma/dev.c
rdma/include/uapi/rdma/rdma_netlink.h
rdma/link.c
rdma/rdma.c
rdma/rdma.h
rdma/res-cmid.c [new file with mode: 0644]
rdma/res-cq.c [new file with mode: 0644]
rdma/res-mr.c [new file with mode: 0644]
rdma/res-pd.c [new file with mode: 0644]
rdma/res-qp.c [new file with mode: 0644]
rdma/res.c
rdma/res.h [new file with mode: 0644]
rdma/utils.c

index 0498994fc23339a8494752e10631ee09d8556199..6a4242341a62f3e622677acc9879dde3549cd996 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 include ../config.mk
 
 TARGETS :=
@@ -6,7 +6,8 @@ TARGETS :=
 ifeq ($(HAVE_MNL),y)
 CFLAGS += -I./include/uapi/
 
-RDMA_OBJ = rdma.o utils.o dev.o link.o res.o
+RDMA_OBJ = rdma.o utils.o dev.o link.o res.o res-pd.o res-mr.o res-cq.o \
+          res-cmid.o res-qp.o
 
 TARGETS += rdma
 endif
index 60ff4b31e3204cb32fa16c0642b84ffa9bf0af00..954e00153e3db8d5a451fd1019ff2145281638f0 100644 (file)
@@ -1,11 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
  * dev.c       RDMA tool
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
  * Authors:     Leon Romanovsky <leonro@mellanox.com>
  */
 
index 04c80cebef49fd657ea02c34033d6b520fb33117..5027c6274ded5a2ec60f4d88b24e2669d4b0b632 100644 (file)
@@ -5,8 +5,7 @@
 #include <linux/types.h>
 
 enum {
-       RDMA_NL_RDMA_CM = 1,
-       RDMA_NL_IWCM,
+       RDMA_NL_IWCM = 2,
        RDMA_NL_RSVD,
        RDMA_NL_LS,     /* RDMA Local Services */
        RDMA_NL_NLDEV,  /* RDMA device interface */
@@ -14,8 +13,7 @@ enum {
 };
 
 enum {
-       RDMA_NL_GROUP_CM = 1,
-       RDMA_NL_GROUP_IWPM,
+       RDMA_NL_GROUP_IWPM = 2,
        RDMA_NL_GROUP_LS,
        RDMA_NL_NUM_GROUPS
 };
@@ -24,15 +22,17 @@ enum {
 #define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1))
 #define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op)
 
-enum {
-       RDMA_NL_RDMA_CM_ID_STATS = 0,
-       RDMA_NL_RDMA_CM_NUM_OPS
-};
+/* The minimum version that the iwpm kernel supports */
+#define IWPM_UABI_VERSION_MIN  3
 
+/* The latest version that the iwpm kernel supports */
+#define IWPM_UABI_VERSION      4
+
+/* iwarp port mapper message flags */
 enum {
-       RDMA_NL_RDMA_CM_ATTR_SRC_ADDR = 1,
-       RDMA_NL_RDMA_CM_ATTR_DST_ADDR,
-       RDMA_NL_RDMA_CM_NUM_ATTR,
+
+       /* Do not map the port for this IWPM request */
+       IWPM_FLAGS_NO_PORT_MAP = (1 << 0),
 };
 
 /* iwarp port mapper op-codes */
@@ -45,6 +45,7 @@ enum {
        RDMA_NL_IWPM_HANDLE_ERR,
        RDMA_NL_IWPM_MAPINFO,
        RDMA_NL_IWPM_MAPINFO_NUM,
+       RDMA_NL_IWPM_HELLO,
        RDMA_NL_IWPM_NUM_OPS
 };
 
@@ -83,20 +84,38 @@ enum {
        IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0,
        IWPM_NLA_MANAGE_MAPPING_SEQ,
        IWPM_NLA_MANAGE_ADDR,
-       IWPM_NLA_MANAGE_MAPPED_LOC_ADDR,
+       IWPM_NLA_MANAGE_FLAGS,
+       IWPM_NLA_MANAGE_MAPPING_MAX
+};
+
+enum {
+       IWPM_NLA_RMANAGE_MAPPING_UNSPEC = 0,
+       IWPM_NLA_RMANAGE_MAPPING_SEQ,
+       IWPM_NLA_RMANAGE_ADDR,
+       IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR,
+       /* The following maintains bisectability of rdma-core */
+       IWPM_NLA_MANAGE_MAPPED_LOC_ADDR = IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR,
        IWPM_NLA_RMANAGE_MAPPING_ERR,
        IWPM_NLA_RMANAGE_MAPPING_MAX
 };
 
-#define IWPM_NLA_MANAGE_MAPPING_MAX 3
-#define IWPM_NLA_QUERY_MAPPING_MAX  4
 #define IWPM_NLA_MAPINFO_SEND_MAX   3
+#define IWPM_NLA_REMOVE_MAPPING_MAX 3
 
 enum {
        IWPM_NLA_QUERY_MAPPING_UNSPEC = 0,
        IWPM_NLA_QUERY_MAPPING_SEQ,
        IWPM_NLA_QUERY_LOCAL_ADDR,
        IWPM_NLA_QUERY_REMOTE_ADDR,
+       IWPM_NLA_QUERY_FLAGS,
+       IWPM_NLA_QUERY_MAPPING_MAX,
+};
+
+enum {
+       IWPM_NLA_RQUERY_MAPPING_UNSPEC = 0,
+       IWPM_NLA_RQUERY_MAPPING_SEQ,
+       IWPM_NLA_RQUERY_LOCAL_ADDR,
+       IWPM_NLA_RQUERY_REMOTE_ADDR,
        IWPM_NLA_RQUERY_MAPPED_LOC_ADDR,
        IWPM_NLA_RQUERY_MAPPED_REM_ADDR,
        IWPM_NLA_RQUERY_MAPPING_ERR,
@@ -114,6 +133,7 @@ enum {
        IWPM_NLA_MAPINFO_UNSPEC = 0,
        IWPM_NLA_MAPINFO_LOCAL_ADDR,
        IWPM_NLA_MAPINFO_MAPPED_ADDR,
+       IWPM_NLA_MAPINFO_FLAGS,
        IWPM_NLA_MAPINFO_MAX
 };
 
@@ -132,6 +152,12 @@ enum {
        IWPM_NLA_ERR_MAX
 };
 
+enum {
+       IWPM_NLA_HELLO_UNSPEC = 0,
+       IWPM_NLA_HELLO_ABI_VERSION,
+       IWPM_NLA_HELLO_MAX
+};
+
 /*
  * Local service operations:
  *   RESOLVE - The client requests the local service to resolve a path.
@@ -430,6 +456,16 @@ enum rdma_nldev_attr {
        RDMA_NLDEV_ATTR_DRIVER_S64,             /* s64 */
        RDMA_NLDEV_ATTR_DRIVER_U64,             /* u64 */
 
+       /*
+        * Indexes to get/set secific entry,
+        * for QP use RDMA_NLDEV_ATTR_RES_LQPN
+        */
+       RDMA_NLDEV_ATTR_RES_PDN,               /* u32 */
+       RDMA_NLDEV_ATTR_RES_CQN,               /* u32 */
+       RDMA_NLDEV_ATTR_RES_MRN,               /* u32 */
+       RDMA_NLDEV_ATTR_RES_CM_IDN,            /* u32 */
+       RDMA_NLDEV_ATTR_RES_CTXN,              /* u32 */
+
        /*
         * Always the end
         */
index c064be627be2c19e116cefba109c412c8aab8268..89e81b84b2ccae8c0401c4ae2e972e57f7022c73 100644 (file)
@@ -1,11 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
  * link.c      RDMA tool
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
  * Authors:     Leon Romanovsky <leonro@mellanox.com>
  */
 
index 010e98371ef098b3d7052bb6725f31a9ec178c7b..676e03c23088316fac634990b52168f1636d7ab0 100644 (file)
@@ -1,11 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
  * rdma.c      RDMA tool
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
  * Authors:     Leon Romanovsky <leonro@mellanox.com>
  */
 
index 547bb5749a39f68e7237f976ee57518f3e7aa21d..1022e9a29291d49896ebf9d103e9c0345792e23b 100644 (file)
@@ -1,11 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
  * rdma.c      RDMA tool
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
  * Authors:     Leon Romanovsky <leonro@mellanox.com>
  */
 #ifndef _RDMA_TOOL_H_
 #define MAX_NUMBER_OF_FILTERS 64
 struct filters {
        const char *name;
-       bool is_number;
+       uint8_t is_number:1;
+       uint8_t is_doit:1;
 };
 
 struct filter_entry {
        struct list_head list;
        char *key;
        char *value;
+       /*
+        * This field menas that we can try to issue .doit calback
+        * on value above. This value can be converted to integer
+        * with simple atoi(). Otherwise "is_doit" will be false.
+        */
+       uint8_t is_doit:1;
 };
 
 struct dev_map {
@@ -106,10 +108,12 @@ struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index);
 /*
  * Filter manipulation
  */
+bool rd_doit_index(struct rd *rd, uint32_t *idx);
 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);
+bool rd_is_filtered_attr(struct rd *rd, const char *key, uint32_t val,
+                        struct nlattr *attr);
+bool rd_is_string_filtered_attr(struct rd *rd, const char *key, const char *val,
+                               struct nlattr *attr);
 /*
  * Netlink
  */
diff --git a/rdma/res-cmid.c b/rdma/res-cmid.c
new file mode 100644 (file)
index 0000000..0b83008
--- /dev/null
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * res-cmid.c  RDMA tool
+ * Authors:     Leon Romanovsky <leonro@mellanox.com>
+ */
+
+#include "res.h"
+#include <inttypes.h>
+
+static void print_qp_type(struct rd *rd, uint32_t val)
+{
+       if (rd->json_output)
+               jsonw_string_field(rd->jw, "qp-type", qp_types_to_str(val));
+       else
+               pr_out("qp-type %s ", qp_types_to_str(val));
+}
+
+static const char *cm_id_state_to_str(uint8_t idx)
+{
+       static const char *const cm_id_states_str[] = {
+               "IDLE",           "ADDR_QUERY",     "ADDR_RESOLVED",
+               "ROUTE_QUERY",    "ROUTE_RESOLVED", "CONNECT",
+               "DISCONNECT",     "ADDR_BOUND",     "LISTEN",
+               "DEVICE_REMOVAL", "DESTROYING"
+       };
+
+       if (idx < ARRAY_SIZE(cm_id_states_str))
+               return cm_id_states_str[idx];
+       return "UNKNOWN";
+}
+
+static const char *cm_id_ps_to_str(uint32_t ps)
+{
+       switch (ps) {
+       case RDMA_PS_IPOIB:
+               return "IPoIB";
+       case RDMA_PS_IB:
+               return "IPoIB";
+       case RDMA_PS_TCP:
+               return "TCP";
+       case RDMA_PS_UDP:
+               return "UDP";
+       default:
+               return "---";
+       }
+}
+
+static void print_cm_id_state(struct rd *rd, uint8_t state)
+{
+       if (rd->json_output) {
+               jsonw_string_field(rd->jw, "state", cm_id_state_to_str(state));
+               return;
+       }
+       pr_out("state %s ", cm_id_state_to_str(state));
+}
+
+static void print_ps(struct rd *rd, uint32_t ps)
+{
+       if (rd->json_output) {
+               jsonw_string_field(rd->jw, "ps", cm_id_ps_to_str(ps));
+               return;
+       }
+       pr_out("ps %s ", cm_id_ps_to_str(ps));
+}
+
+static void print_ipaddr(struct rd *rd, const char *key, char *addrstr,
+                        uint16_t port)
+{
+       if (rd->json_output) {
+               int name_size = INET6_ADDRSTRLEN + strlen(":65535");
+               char json_name[name_size];
+
+               snprintf(json_name, name_size, "%s:%u", addrstr, port);
+               jsonw_string_field(rd->jw, key, json_name);
+               return;
+       }
+       pr_out("%s %s:%u ", key, addrstr, port);
+}
+
+static int ss_ntop(struct nlattr *nla_line, char *addr_str, uint16_t *port)
+{
+       struct __kernel_sockaddr_storage *addr;
+
+       addr = (struct __kernel_sockaddr_storage *)mnl_attr_get_payload(
+               nla_line);
+       switch (addr->ss_family) {
+       case AF_INET: {
+               struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+
+               if (!inet_ntop(AF_INET, (const void *)&sin->sin_addr, addr_str,
+                              INET6_ADDRSTRLEN))
+                       return -EINVAL;
+               *port = ntohs(sin->sin_port);
+               break;
+       }
+       case AF_INET6: {
+               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+               if (!inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
+                              addr_str, INET6_ADDRSTRLEN))
+                       return -EINVAL;
+               *port = ntohs(sin6->sin6_port);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+static int res_cm_id_line(struct rd *rd, const char *name, int idx,
+                      struct nlattr **nla_line)
+{
+       char src_addr_str[INET6_ADDRSTRLEN];
+       char dst_addr_str[INET6_ADDRSTRLEN];
+       uint16_t src_port, dst_port;
+       uint32_t port = 0, pid = 0;
+       uint8_t type = 0, state;
+       uint32_t lqpn = 0, ps;
+       uint32_t cm_idn = 0;
+       char *comm = NULL;
+
+       if (!nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
+           !nla_line[RDMA_NLDEV_ATTR_RES_PS] ||
+           (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
+            !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
+               return MNL_CB_ERROR;
+       }
+
+       if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
+               port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
+
+       if (port && port != rd->port_idx)
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
+               lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
+
+       if (rd_is_filtered_attr(rd, "lqpn", lqpn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_LQPN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
+               type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
+       if (rd_is_string_filtered_attr(rd, "qp-type", qp_types_to_str(type),
+                                      nla_line[RDMA_NLDEV_ATTR_RES_TYPE]))
+               goto out;
+
+       ps = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PS]);
+       if (rd_is_string_filtered_attr(rd, "ps", cm_id_ps_to_str(ps),
+                                      nla_line[RDMA_NLDEV_ATTR_RES_PS]))
+               goto out;
+
+       state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
+       if (rd_is_string_filtered_attr(rd, "state", cm_id_state_to_str(state),
+                                      nla_line[RDMA_NLDEV_ATTR_RES_STATE]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
+               if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR],
+                           src_addr_str, &src_port))
+                       goto out;
+       if (rd_is_string_filtered_attr(rd, "src-addr", src_addr_str,
+                                      nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR]))
+               goto out;
+       if (rd_is_filtered_attr(rd, "src-port", src_port,
+                               nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
+               if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR],
+                           dst_addr_str, &dst_port))
+                       goto out;
+       if (rd_is_string_filtered_attr(rd, "dst-addr", dst_addr_str,
+                                      nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR]))
+               goto out;
+       if (rd_is_filtered_attr(rd, "dst-port", dst_port,
+                               nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
+               pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+               comm = get_task_name(pid);
+       }
+
+       if (rd_is_filtered_attr(rd, "pid", pid,
+                               nla_line[RDMA_NLDEV_ATTR_RES_PID]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_CM_IDN])
+               cm_idn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CM_IDN]);
+       if (rd_is_filtered_attr(rd, "cm-idn", cm_idn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_CM_IDN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) {
+               /* discard const from mnl_attr_get_str */
+               comm = (char *)mnl_attr_get_str(
+                       nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
+       }
+
+       if (rd->json_output)
+               jsonw_start_array(rd->jw);
+
+       print_link(rd, idx, name, port, nla_line);
+       res_print_uint(rd, "cm-idn", cm_idn,
+                      nla_line[RDMA_NLDEV_ATTR_RES_CM_IDN]);
+       res_print_uint(rd, "lqpn", lqpn, nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
+       if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
+               print_qp_type(rd, type);
+       print_cm_id_state(rd, state);
+       print_ps(rd, ps);
+       res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+       print_comm(rd, comm, nla_line);
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
+               print_ipaddr(rd, "src-addr", src_addr_str, src_port);
+       if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
+               print_ipaddr(rd, "dst-addr", dst_addr_str, dst_port);
+
+       print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
+       newline(rd);
+
+out:   if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
+               free(comm);
+       return MNL_CB_OK;
+}
+
+int res_cm_id_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct rd *rd = data;
+       const char *name;
+       int idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+
+       return res_cm_id_line(rd, name, idx, tb);
+}
+
+int res_cm_id_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct nlattr *nla_table, *nla_entry;
+       struct rd *rd = data;
+       int ret = MNL_CB_OK;
+       const char *name;
+       int idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
+           !tb[RDMA_NLDEV_ATTR_RES_CM_ID])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+       nla_table = tb[RDMA_NLDEV_ATTR_RES_CM_ID];
+
+       mnl_attr_for_each_nested(nla_entry, nla_table) {
+               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
+
+               ret = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+
+               ret = res_cm_id_line(rd, name, idx, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+       }
+       return ret;
+}
diff --git a/rdma/res-cq.c b/rdma/res-cq.c
new file mode 100644 (file)
index 0000000..5afb97c
--- /dev/null
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * res-cq.c    RDMA tool
+ * Authors:     Leon Romanovsky <leonro@mellanox.com>
+ */
+
+#include "res.h"
+#include <inttypes.h>
+
+static const char *poll_ctx_to_str(uint8_t idx)
+{
+       static const char * const cm_id_states_str[] = {
+               "DIRECT", "SOFTIRQ", "WORKQUEUE", "UNBOUND_WORKQUEUE"};
+
+       if (idx < ARRAY_SIZE(cm_id_states_str))
+               return cm_id_states_str[idx];
+       return "UNKNOWN";
+}
+
+static void print_poll_ctx(struct rd *rd, uint8_t poll_ctx, struct nlattr *attr)
+{
+       if (!attr)
+               return;
+
+       if (rd->json_output) {
+               jsonw_string_field(rd->jw, "poll-ctx",
+                                  poll_ctx_to_str(poll_ctx));
+               return;
+       }
+       pr_out("poll-ctx %s ", poll_ctx_to_str(poll_ctx));
+}
+
+static int res_cq_line(struct rd *rd, const char *name, int idx,
+                      struct nlattr **nla_line)
+{
+       char *comm = NULL;
+       uint32_t pid = 0;
+       uint8_t poll_ctx = 0;
+       uint32_t ctxn = 0;
+       uint32_t cqn = 0;
+       uint64_t users;
+       uint32_t cqe;
+
+       if (!nla_line[RDMA_NLDEV_ATTR_RES_CQE] ||
+           !nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
+           (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
+            !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
+               return MNL_CB_ERROR;
+       }
+
+       cqe = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQE]);
+
+       users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
+       if (rd_is_filtered_attr(rd, "users", users,
+                               nla_line[RDMA_NLDEV_ATTR_RES_USECNT]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX])
+               poll_ctx =
+                       mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]);
+       if (rd_is_string_filtered_attr(rd, "poll-ctx",
+                                      poll_ctx_to_str(poll_ctx),
+                                      nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
+               pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+               comm = get_task_name(pid);
+       }
+
+       if (rd_is_filtered_attr(rd, "pid", pid,
+                               nla_line[RDMA_NLDEV_ATTR_RES_PID]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_CQN])
+               cqn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQN]);
+       if (rd_is_filtered_attr(rd, "cqn", cqn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_CQN]))
+               goto out;
+       if (nla_line[RDMA_NLDEV_ATTR_RES_CTXN])
+               ctxn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CTXN]);
+       if (rd_is_filtered_attr(rd, "ctxn", ctxn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_CTXN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
+               /* discard const from mnl_attr_get_str */
+               comm = (char *)mnl_attr_get_str(
+                       nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
+
+       if (rd->json_output)
+               jsonw_start_array(rd->jw);
+
+       print_dev(rd, idx, name);
+       res_print_uint(rd, "cqn", cqn, nla_line[RDMA_NLDEV_ATTR_RES_CQN]);
+       res_print_uint(rd, "cqe", cqe, nla_line[RDMA_NLDEV_ATTR_RES_CQE]);
+       res_print_uint(rd, "users", users,
+                      nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
+       print_poll_ctx(rd, poll_ctx, nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]);
+       res_print_uint(rd, "ctxn", ctxn, nla_line[RDMA_NLDEV_ATTR_RES_CTXN]);
+       res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+       print_comm(rd, comm, nla_line);
+
+       print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
+       newline(rd);
+
+out:   if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
+               free(comm);
+       return MNL_CB_OK;
+}
+
+int res_cq_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct rd *rd = data;
+       const char *name;
+       uint32_t idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+
+       return res_cq_line(rd, name, idx, tb);
+}
+
+int res_cq_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct nlattr *nla_table, *nla_entry;
+       struct rd *rd = data;
+       int ret = MNL_CB_OK;
+       const char *name;
+       uint32_t idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
+           !tb[RDMA_NLDEV_ATTR_RES_CQ])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+       nla_table = tb[RDMA_NLDEV_ATTR_RES_CQ];
+
+       mnl_attr_for_each_nested(nla_entry, nla_table) {
+               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
+
+               ret = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+
+               ret = res_cq_line(rd, name, idx, nla_line);
+
+               if (ret != MNL_CB_OK)
+                       break;
+       }
+       return ret;
+}
diff --git a/rdma/res-mr.c b/rdma/res-mr.c
new file mode 100644 (file)
index 0000000..f4a24dc
--- /dev/null
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * res-mr.c    RDMA tool
+ * Authors:     Leon Romanovsky <leonro@mellanox.com>
+ */
+
+#include "res.h"
+#include <inttypes.h>
+
+static int res_mr_line(struct rd *rd, const char *name, int idx,
+                      struct nlattr **nla_line)
+{
+       uint32_t rkey = 0, lkey = 0;
+       uint64_t iova = 0, mrlen;
+       char *comm = NULL;
+       uint32_t pdn = 0;
+       uint32_t mrn = 0;
+       uint32_t pid = 0;
+
+       if (!nla_line[RDMA_NLDEV_ATTR_RES_MRLEN] ||
+           (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
+            !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
+               return MNL_CB_ERROR;
+       }
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
+               rkey = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RKEY]);
+       if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
+               lkey = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LKEY]);
+       if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
+               iova = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_IOVA]);
+
+       mrlen = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]);
+       if (rd_is_filtered_attr(rd, "mrlen", mrlen,
+                               nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
+               pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+               comm = get_task_name(pid);
+       }
+
+       if (rd_is_filtered_attr(rd, "pid", pid,
+                               nla_line[RDMA_NLDEV_ATTR_RES_PID]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_MRN])
+               mrn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_MRN]);
+       if (rd_is_filtered_attr(rd, "mrn", mrn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_MRN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PDN])
+               pdn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
+       if (rd_is_filtered_attr(rd, "pdn", pdn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_PDN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
+               /* discard const from mnl_attr_get_str */
+               comm = (char *)mnl_attr_get_str(
+                       nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
+
+       if (rd->json_output)
+               jsonw_start_array(rd->jw);
+
+       print_dev(rd, idx, name);
+       res_print_uint(rd, "mrn", mrn, nla_line[RDMA_NLDEV_ATTR_RES_MRN]);
+       print_key(rd, "rkey", rkey, nla_line[RDMA_NLDEV_ATTR_RES_RKEY]);
+       print_key(rd, "lkey", lkey, nla_line[RDMA_NLDEV_ATTR_RES_LKEY]);
+       print_key(rd, "iova", iova, nla_line[RDMA_NLDEV_ATTR_RES_IOVA]);
+       res_print_uint(rd, "mrlen", mrlen, nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]);
+       res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
+       res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+       print_comm(rd, comm, nla_line);
+
+       print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
+       newline(rd);
+
+out:
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
+               free(comm);
+       return MNL_CB_OK;
+}
+
+int res_mr_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct rd *rd = data;
+       const char *name;
+       uint32_t idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+
+       return res_mr_line(rd, name, idx, tb);
+}
+
+int res_mr_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct nlattr *nla_table, *nla_entry;
+       struct rd *rd = data;
+       int ret = MNL_CB_OK;
+       const char *name;
+       uint32_t idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
+           !tb[RDMA_NLDEV_ATTR_RES_MR])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+       nla_table = tb[RDMA_NLDEV_ATTR_RES_MR];
+
+       mnl_attr_for_each_nested(nla_entry, nla_table) {
+               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
+
+               ret = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+
+               ret = res_mr_line(rd, name, idx, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+       }
+       return ret;
+}
diff --git a/rdma/res-pd.c b/rdma/res-pd.c
new file mode 100644 (file)
index 0000000..07c836e
--- /dev/null
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * res-pd.c    RDMA tool
+ * Authors:     Leon Romanovsky <leonro@mellanox.com>
+ */
+
+#include "res.h"
+#include <inttypes.h>
+
+static int res_pd_line(struct rd *rd, const char *name, int idx,
+                      struct nlattr **nla_line)
+{
+       uint32_t local_dma_lkey = 0, unsafe_global_rkey = 0;
+       char *comm = NULL;
+       uint32_t ctxn = 0;
+       uint32_t pid = 0;
+       uint32_t pdn = 0;
+       uint64_t users;
+
+       if (!nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
+           (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
+            !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
+               return MNL_CB_ERROR;
+       }
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY])
+               local_dma_lkey = mnl_attr_get_u32(
+                       nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]);
+
+       users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
+       if (rd_is_filtered_attr(rd, "users", users,
+                               nla_line[RDMA_NLDEV_ATTR_RES_USECNT]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY])
+               unsafe_global_rkey = mnl_attr_get_u32(
+                       nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]);
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
+               pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+               comm = get_task_name(pid);
+       }
+
+       if (rd_is_filtered_attr(rd, "pid", pid,
+                               nla_line[RDMA_NLDEV_ATTR_RES_PID]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_CTXN])
+               ctxn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CTXN]);
+
+       if (rd_is_filtered_attr(rd, "ctxn", ctxn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_CTXN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PDN])
+               pdn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
+       if (rd_is_filtered_attr(rd, "pdn", pdn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_PDN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
+               /* discard const from mnl_attr_get_str */
+               comm = (char *)mnl_attr_get_str(
+                       nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
+
+       if (rd->json_output)
+               jsonw_start_array(rd->jw);
+
+       print_dev(rd, idx, name);
+       res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
+       print_key(rd, "local_dma_lkey", local_dma_lkey,
+                 nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]);
+       res_print_uint(rd, "users", users,
+                      nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
+       print_key(rd, "unsafe_global_rkey", unsafe_global_rkey,
+                 nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]);
+       res_print_uint(rd, "ctxn", ctxn, nla_line[RDMA_NLDEV_ATTR_RES_CTXN]);
+       res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+       print_comm(rd, comm, nla_line);
+
+       print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
+       newline(rd);
+
+out:   if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
+               free(comm);
+       return MNL_CB_OK;
+}
+
+int res_pd_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct rd *rd = data;
+       const char *name;
+       uint32_t idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+
+       return res_pd_line(rd, name, idx, tb);
+}
+
+int res_pd_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct nlattr *nla_table, *nla_entry;
+       struct rd *rd = data;
+       int ret = MNL_CB_OK;
+       const char *name;
+       uint32_t idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
+           !tb[RDMA_NLDEV_ATTR_RES_PD])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+       nla_table = tb[RDMA_NLDEV_ATTR_RES_PD];
+
+       mnl_attr_for_each_nested(nla_entry, nla_table) {
+               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
+
+               ret = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+
+               ret = res_pd_line(rd, name, idx, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+       }
+       return ret;
+}
diff --git a/rdma/res-qp.c b/rdma/res-qp.c
new file mode 100644 (file)
index 0000000..954e465
--- /dev/null
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * res-qp.c    RDMA tool
+ * Authors:     Leon Romanovsky <leonro@mellanox.com>
+ */
+
+#include "res.h"
+#include <inttypes.h>
+
+static const char *path_mig_to_str(uint8_t idx)
+{
+       static const char *const path_mig_str[] = { "MIGRATED", "REARM",
+                                                   "ARMED" };
+
+       if (idx < ARRAY_SIZE(path_mig_str))
+               return path_mig_str[idx];
+       return "UNKNOWN";
+}
+
+static const char *qp_states_to_str(uint8_t idx)
+{
+       static const char *const qp_states_str[] = { "RESET", "INIT", "RTR",
+                                                    "RTS",   "SQD",  "SQE",
+                                                    "ERR" };
+
+       if (idx < ARRAY_SIZE(qp_states_str))
+               return qp_states_str[idx];
+       return "UNKNOWN";
+}
+
+static void print_rqpn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
+{
+       if (!nla_line[RDMA_NLDEV_ATTR_RES_RQPN])
+               return;
+
+       if (rd->json_output)
+               jsonw_uint_field(rd->jw, "rqpn", val);
+       else
+               pr_out("rqpn %u ", val);
+}
+
+static void print_type(struct rd *rd, uint32_t val)
+{
+       if (rd->json_output)
+               jsonw_string_field(rd->jw, "type", qp_types_to_str(val));
+       else
+               pr_out("type %s ", qp_types_to_str(val));
+}
+
+static void print_state(struct rd *rd, uint32_t val)
+{
+       if (rd->json_output)
+               jsonw_string_field(rd->jw, "state", qp_states_to_str(val));
+       else
+               pr_out("state %s ", qp_states_to_str(val));
+}
+
+static void print_rqpsn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
+{
+       if (!nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN])
+               return;
+
+       if (rd->json_output)
+               jsonw_uint_field(rd->jw, "rq-psn", val);
+       else
+               pr_out("rq-psn %u ", val);
+}
+
+static void print_pathmig(struct rd *rd, uint32_t val, struct nlattr **nla_line)
+{
+       if (!nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE])
+               return;
+
+       if (rd->json_output)
+               jsonw_string_field(rd->jw, "path-mig-state",
+                                  path_mig_to_str(val));
+       else
+               pr_out("path-mig-state %s ", path_mig_to_str(val));
+}
+
+static int res_qp_line(struct rd *rd, const char *name, int idx,
+                      struct nlattr **nla_line)
+{
+       uint32_t lqpn, rqpn = 0, rq_psn = 0, sq_psn;
+       uint8_t type, state, path_mig_state = 0;
+       uint32_t port = 0, pid = 0;
+       uint32_t pdn = 0;
+       char *comm = NULL;
+
+       if (!nla_line[RDMA_NLDEV_ATTR_RES_LQPN] ||
+           !nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN] ||
+           !nla_line[RDMA_NLDEV_ATTR_RES_TYPE] ||
+           !nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
+           (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
+            !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
+               return MNL_CB_ERROR;
+       }
+
+       if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
+               port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
+
+       if (port != rd->port_idx)
+               goto out;
+
+       lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
+       if (rd_is_filtered_attr(rd, "lqpn", lqpn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_LQPN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PDN])
+               pdn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
+       if (rd_is_filtered_attr(rd, "pdn", pdn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_PDN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_RQPN])
+               rqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQPN]);
+       if (rd_is_filtered_attr(rd, "rqpn", rqpn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_RQPN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN])
+               rq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]);
+       if (rd_is_filtered_attr(rd, "rq-psn", rq_psn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]))
+               goto out;
+
+       sq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]);
+       if (rd_is_filtered_attr(rd, "sq-psn", sq_psn,
+                               nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE])
+               path_mig_state = mnl_attr_get_u8(
+                       nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]);
+       if (rd_is_string_filtered_attr(
+                   rd, "path-mig-state", path_mig_to_str(path_mig_state),
+                   nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]))
+               goto out;
+
+       type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
+       if (rd_is_string_filtered_attr(rd, "type", qp_types_to_str(type),
+                                      nla_line[RDMA_NLDEV_ATTR_RES_TYPE]))
+               goto out;
+
+       state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
+       if (rd_is_string_filtered_attr(rd, "state", qp_states_to_str(state),
+                                      nla_line[RDMA_NLDEV_ATTR_RES_STATE]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
+               pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+               comm = get_task_name(pid);
+       }
+
+       if (rd_is_filtered_attr(rd, "pid", pid,
+                               nla_line[RDMA_NLDEV_ATTR_RES_PID]))
+               goto out;
+
+       if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
+               /* discard const from mnl_attr_get_str */
+               comm = (char *)mnl_attr_get_str(
+                       nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
+
+       if (rd->json_output)
+               jsonw_start_array(rd->jw);
+
+       print_link(rd, idx, name, port, nla_line);
+
+       res_print_uint(rd, "lqpn", lqpn, nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
+       print_rqpn(rd, rqpn, nla_line);
+
+       print_type(rd, type);
+       print_state(rd, state);
+
+       print_rqpsn(rd, rq_psn, nla_line);
+       res_print_uint(rd, "sq-psn", sq_psn,
+                      nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]);
+
+       print_pathmig(rd, path_mig_state, nla_line);
+       res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
+       res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
+       print_comm(rd, comm, nla_line);
+
+       print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
+       newline(rd);
+out:
+       if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
+               free(comm);
+       return MNL_CB_OK;
+}
+
+int res_qp_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct rd *rd = data;
+       const char *name;
+       uint32_t idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+
+       return res_qp_line(rd, name, idx, tb);
+}
+
+int res_qp_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct nlattr *nla_table, *nla_entry;
+       struct rd *rd = data;
+       int ret = MNL_CB_OK;
+       const char *name;
+       uint32_t idx;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
+           !tb[RDMA_NLDEV_ATTR_RES_QP])
+               return MNL_CB_ERROR;
+
+       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
+       idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+       nla_table = tb[RDMA_NLDEV_ATTR_RES_QP];
+
+       mnl_attr_for_each_nested(nla_entry, nla_table) {
+               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
+
+               ret = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+
+               ret = res_qp_line(rd, name, idx, nla_line);
+               if (ret != MNL_CB_OK)
+                       break;
+       }
+       return ret;
+}
index 6b0f5fe35f74063af758241a8069829292bc5cca..ef863f142eca1c8da9f63eacf1e4973ba0d60f73 100644 (file)
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
  * res.c       RDMA tool
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
  * Authors:     Leon Romanovsky <leonro@mellanox.com>
  */
 
-#include "rdma.h"
+#include "res.h"
 #include <inttypes.h>
 
 static int res_help(struct rd *rd)
@@ -40,7 +35,6 @@ static int res_print_summary(struct rd *rd, struct nlattr **tb)
 
        mnl_attr_for_each_nested(nla_entry, nla_table) {
                struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
-               char json_name[32];
 
                err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
                if (err != MNL_CB_OK)
@@ -53,16 +47,18 @@ static int res_print_summary(struct rd *rd, struct nlattr **tb)
 
                name = mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]);
                curr = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
-               if (rd->json_output) {
-                       snprintf(json_name, 32, "%s", name);
-                       jsonw_lluint_field(rd->jw, json_name, curr);
-               } else {
-                       pr_out("%s %"PRId64 " ", name, curr);
-               }
+               res_print_uint(
+                       rd, name, curr,
+                       nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
        }
        return 0;
 }
 
+static int res_no_args_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
+{
+       return MNL_CB_OK;
+}
+
 static int res_no_args_parse_cb(const struct nlmsghdr *nlh, void *data)
 {
        struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
@@ -92,21 +88,21 @@ static int res_no_args_parse_cb(const struct nlmsghdr *nlh, void *data)
        return MNL_CB_OK;
 }
 
-static int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback)
+int _res_send_idx_msg(struct rd *rd, uint32_t command, mnl_cb_t callback,
+                     uint32_t idx, uint32_t id)
 {
        uint32_t flags = NLM_F_REQUEST | NLM_F_ACK;
        uint32_t seq;
        int ret;
 
-       if (command != RDMA_NLDEV_CMD_RES_GET)
-               flags |= NLM_F_DUMP;
-
        rd_prepare_msg(rd, command, &seq, flags);
        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
        if (rd->port_idx)
                mnl_attr_put_u32(rd->nlh,
                                 RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
 
+       mnl_attr_put_u32(rd->nlh, id, idx);
+
        ret = rd_send_msg(rd);
        if (ret)
                return ret;
@@ -119,49 +115,34 @@ static int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback)
        return ret;
 }
 
-#define RES_FUNC(name, command, valid_filters, strict_port) \
-       static int _##name(struct rd *rd)\
-       { \
-               return _res_send_msg(rd, command, name##_parse_cb); \
-       } \
-       static int name(struct rd *rd) \
-       {\
-               int ret = rd_build_filter(rd, valid_filters); \
-               if (ret) \
-                       return ret; \
-               if ((uintptr_t)valid_filters != (uintptr_t)NULL) { \
-                       ret = rd_set_arg_to_devname(rd); \
-                       if (ret) \
-                               return ret;\
-               } \
-               if (strict_port) \
-                       return rd_exec_dev(rd, _##name); \
-               else \
-                       return rd_exec_link(rd, _##name, strict_port); \
-       }
-
-static const char *path_mig_to_str(uint8_t idx)
+int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback)
 {
-       static const char * const path_mig_str[] = { "MIGRATED",
-                                                    "REARM", "ARMED" };
+       uint32_t flags = NLM_F_REQUEST | NLM_F_ACK;
+       uint32_t seq;
+       int ret;
 
-       if (idx < ARRAY_SIZE(path_mig_str))
-               return path_mig_str[idx];
-       return "UNKNOWN";
-}
+       if (command != RDMA_NLDEV_CMD_RES_GET)
+               flags |= NLM_F_DUMP;
 
-static const char *qp_states_to_str(uint8_t idx)
-{
-       static const char * const qp_states_str[] = { "RESET", "INIT",
-                                                     "RTR", "RTS", "SQD",
-                                                     "SQE", "ERR" };
+       rd_prepare_msg(rd, command, &seq, flags);
+       mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
+       if (rd->port_idx)
+               mnl_attr_put_u32(rd->nlh,
+                                RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
 
-       if (idx < ARRAY_SIZE(qp_states_str))
-               return qp_states_str[idx];
-       return "UNKNOWN";
+       ret = rd_send_msg(rd);
+       if (ret)
+               return ret;
+
+       if (rd->json_output)
+               jsonw_start_object(rd->jw);
+       ret = rd_recv_msg(rd, callback, rd, seq);
+       if (rd->json_output)
+               jsonw_end_object(rd->jw);
+       return ret;
 }
 
-static const char *qp_types_to_str(uint8_t idx)
+const char *qp_types_to_str(uint8_t idx)
 {
        static const char * const qp_types_str[] = { "SMI", "GSI", "RC",
                                                     "UC", "UD", "RAW_IPV6",
@@ -174,86 +155,7 @@ static const char *qp_types_to_str(uint8_t idx)
        return "UNKNOWN";
 }
 
-static void print_lqpn(struct rd *rd, uint32_t val)
-{
-       if (rd->json_output)
-               jsonw_uint_field(rd->jw, "lqpn", val);
-       else
-               pr_out("lqpn %u ", val);
-}
-
-static void print_rqpn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
-{
-       if (!nla_line[RDMA_NLDEV_ATTR_RES_RQPN])
-               return;
-
-       if (rd->json_output)
-               jsonw_uint_field(rd->jw, "rqpn", val);
-       else
-               pr_out("rqpn %u ", val);
-}
-
-static void print_type(struct rd *rd, uint32_t val)
-{
-       if (rd->json_output)
-               jsonw_string_field(rd->jw, "type",
-                                  qp_types_to_str(val));
-       else
-               pr_out("type %s ", qp_types_to_str(val));
-}
-
-static void print_state(struct rd *rd, uint32_t val)
-{
-       if (rd->json_output)
-               jsonw_string_field(rd->jw, "state",
-                                  qp_states_to_str(val));
-       else
-               pr_out("state %s ", qp_states_to_str(val));
-}
-
-static void print_rqpsn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
-{
-       if (!nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN])
-               return;
-
-       if (rd->json_output)
-               jsonw_uint_field(rd->jw, "rq-psn", val);
-       else
-               pr_out("rq-psn %u ", val);
-}
-
-static void print_sqpsn(struct rd *rd, uint32_t val)
-{
-       if (rd->json_output)
-               jsonw_uint_field(rd->jw, "sq-psn", val);
-       else
-               pr_out("sq-psn %u ", val);
-}
-
-static void print_pathmig(struct rd *rd, uint32_t val,
-                         struct nlattr **nla_line)
-{
-       if (!nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE])
-               return;
-
-       if (rd->json_output)
-               jsonw_string_field(rd->jw,
-                                  "path-mig-state",
-                                  path_mig_to_str(val));
-       else
-               pr_out("path-mig-state %s ", path_mig_to_str(val));
-}
-
-static void print_pid(struct rd *rd, uint32_t val)
-{
-       if (rd->json_output)
-               jsonw_uint_field(rd->jw, "pid", val);
-       else
-               pr_out("pid %u ", val);
-}
-
-static void print_comm(struct rd *rd, const char *str,
-                      struct nlattr **nla_line)
+void print_comm(struct rd *rd, const char *str, struct nlattr **nla_line)
 {
        char tmp[18];
 
@@ -271,7 +173,7 @@ static void print_comm(struct rd *rd, const char *str,
        pr_out("comm %s ", tmp);
 }
 
-static void print_dev(struct rd *rd, uint32_t idx, const char *name)
+void print_dev(struct rd *rd, uint32_t idx, const char *name)
 {
        if (rd->json_output) {
                jsonw_uint_field(rd->jw, "ifindex", idx);
@@ -281,8 +183,8 @@ static void print_dev(struct rd *rd, uint32_t idx, const char *name)
        }
 }
 
-static void print_link(struct rd *rd, uint32_t idx, const char *name,
-                      uint32_t port, struct nlattr **nla_line)
+void print_link(struct rd *rd, uint32_t idx, const char *name, uint32_t port,
+               struct nlattr **nla_line)
 {
        if (rd->json_output) {
                jsonw_uint_field(rd->jw, "ifindex", idx);
@@ -299,7 +201,7 @@ static void print_link(struct rd *rd, uint32_t idx, const char *name,
        }
 }
 
-static char *get_task_name(uint32_t pid)
+char *get_task_name(uint32_t pid)
 {
        char *comm;
        FILE *f;
@@ -320,761 +222,31 @@ static char *get_task_name(uint32_t pid)
        return comm;
 }
 
-static int res_qp_parse_cb(const struct nlmsghdr *nlh, void *data)
-{
-       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
-       struct nlattr *nla_table, *nla_entry;
-       struct rd *rd = data;
-       const char *name;
-       uint32_t idx;
-
-       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
-       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
-           !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
-           !tb[RDMA_NLDEV_ATTR_RES_QP])
-               return MNL_CB_ERROR;
-
-       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
-       idx =  mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
-       nla_table = tb[RDMA_NLDEV_ATTR_RES_QP];
-
-       mnl_attr_for_each_nested(nla_entry, nla_table) {
-               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
-               uint32_t lqpn, rqpn = 0, rq_psn = 0, sq_psn;
-               uint8_t type, state, path_mig_state = 0;
-               uint32_t port = 0, pid = 0;
-               char *comm = NULL;
-               int err;
-
-               err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
-               if (err != MNL_CB_OK)
-                       return MNL_CB_ERROR;
-
-               if (!nla_line[RDMA_NLDEV_ATTR_RES_LQPN] ||
-                   !nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN] ||
-                   !nla_line[RDMA_NLDEV_ATTR_RES_TYPE] ||
-                   !nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
-                   (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
-                    !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
-                       return MNL_CB_ERROR;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
-                       port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
-
-               if (port != rd->port_idx)
-                       continue;
-
-               lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
-               if (rd_check_is_filtered(rd, "lqpn", lqpn))
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_RQPN]) {
-                       rqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQPN]);
-                       if (rd_check_is_filtered(rd, "rqpn", rqpn))
-                               continue;
-               } else {
-                       if (rd_check_is_key_exist(rd, "rqpn"))
-                               continue;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]) {
-                       rq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]);
-                       if (rd_check_is_filtered(rd, "rq-psn", rq_psn))
-                               continue;
-               } else {
-                       if (rd_check_is_key_exist(rd, "rq-psn"))
-                               continue;
-               }
-
-               sq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]);
-               if (rd_check_is_filtered(rd, "sq-psn", sq_psn))
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]) {
-                       path_mig_state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]);
-                       if (rd_check_is_string_filtered(rd, "path-mig-state", path_mig_to_str(path_mig_state)))
-                               continue;
-               } else {
-                       if (rd_check_is_key_exist(rd, "path-mig-state"))
-                               continue;
-               }
-
-               type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
-               if (rd_check_is_string_filtered(rd, "type", qp_types_to_str(type)))
-                       continue;
-
-               state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
-               if (rd_check_is_string_filtered(rd, "state", qp_states_to_str(state)))
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
-                       pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
-                       comm = get_task_name(pid);
-               }
-
-               if (rd_check_is_filtered(rd, "pid", pid)) {
-                       free(comm);
-                       continue;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
-                       /* discard const from mnl_attr_get_str */
-                       comm = (char *)mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
-
-               if (rd->json_output)
-                       jsonw_start_array(rd->jw);
-
-               print_link(rd, idx, name, port, nla_line);
-
-               print_lqpn(rd, lqpn);
-               print_rqpn(rd, rqpn, nla_line);
-
-               print_type(rd, type);
-               print_state(rd, state);
-
-               print_rqpsn(rd, rq_psn, nla_line);
-               print_sqpsn(rd, sq_psn);
-
-               print_pathmig(rd, path_mig_state, nla_line);
-               print_pid(rd, pid);
-               print_comm(rd, comm, nla_line);
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
-                       free(comm);
-
-               print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
-               newline(rd);
-       }
-       return MNL_CB_OK;
-}
-
-static void print_qp_type(struct rd *rd, uint32_t val)
-{
-       if (rd->json_output)
-               jsonw_string_field(rd->jw, "qp-type",
-                                  qp_types_to_str(val));
-       else
-               pr_out("qp-type %s ", qp_types_to_str(val));
-}
-
-static const char *cm_id_state_to_str(uint8_t idx)
-{
-       static const char * const cm_id_states_str[] = {
-               "IDLE", "ADDR_QUERY", "ADDR_RESOLVED", "ROUTE_QUERY",
-               "ROUTE_RESOLVED", "CONNECT", "DISCONNECT", "ADDR_BOUND",
-               "LISTEN", "DEVICE_REMOVAL", "DESTROYING" };
-
-       if (idx < ARRAY_SIZE(cm_id_states_str))
-               return cm_id_states_str[idx];
-       return "UNKNOWN";
-}
-
-static const char *cm_id_ps_to_str(uint32_t ps)
-{
-       switch (ps) {
-       case RDMA_PS_IPOIB:
-               return "IPoIB";
-       case RDMA_PS_IB:
-               return "IPoIB";
-       case RDMA_PS_TCP:
-               return "TCP";
-       case RDMA_PS_UDP:
-               return "UDP";
-       default:
-               return "---";
-       }
-}
-
-static void print_cm_id_state(struct rd *rd, uint8_t state)
-{
-       if (rd->json_output) {
-               jsonw_string_field(rd->jw, "state", cm_id_state_to_str(state));
-               return;
-       }
-       pr_out("state %s ", cm_id_state_to_str(state));
-}
-
-static void print_ps(struct rd *rd, uint32_t ps)
-{
-       if (rd->json_output) {
-               jsonw_string_field(rd->jw, "ps", cm_id_ps_to_str(ps));
-               return;
-       }
-       pr_out("ps %s ", cm_id_ps_to_str(ps));
-}
-
-static void print_ipaddr(struct rd *rd, const char *key, char *addrstr,
-                        uint16_t port)
-{
-       if (rd->json_output) {
-               int name_size = INET6_ADDRSTRLEN+strlen(":65535");
-               char json_name[name_size];
-
-               snprintf(json_name, name_size, "%s:%u", addrstr, port);
-               jsonw_string_field(rd->jw, key, json_name);
-               return;
-       }
-       pr_out("%s %s:%u ", key, addrstr, port);
-}
-
-static int ss_ntop(struct nlattr *nla_line, char *addr_str, uint16_t *port)
-{
-       struct __kernel_sockaddr_storage *addr;
-
-       addr = (struct __kernel_sockaddr_storage *)
-                                               mnl_attr_get_payload(nla_line);
-       switch (addr->ss_family) {
-       case AF_INET: {
-               struct sockaddr_in *sin = (struct sockaddr_in *)addr;
-
-               if (!inet_ntop(AF_INET, (const void *)&sin->sin_addr, addr_str,
-                              INET6_ADDRSTRLEN))
-                       return -EINVAL;
-               *port = ntohs(sin->sin_port);
-               break;
-       }
-       case AF_INET6: {
-               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
-
-               if (!inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
-                              addr_str, INET6_ADDRSTRLEN))
-                       return -EINVAL;
-               *port = ntohs(sin6->sin6_port);
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int res_cm_id_parse_cb(const struct nlmsghdr *nlh, void *data)
-{
-       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
-       struct nlattr *nla_table, *nla_entry;
-       struct rd *rd = data;
-       const char *name;
-       int idx;
-
-       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
-       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
-           !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
-           !tb[RDMA_NLDEV_ATTR_RES_CM_ID])
-               return MNL_CB_ERROR;
-
-       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
-       idx =  mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
-       nla_table = tb[RDMA_NLDEV_ATTR_RES_CM_ID];
-       mnl_attr_for_each_nested(nla_entry, nla_table) {
-               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
-               char src_addr_str[INET6_ADDRSTRLEN];
-               char dst_addr_str[INET6_ADDRSTRLEN];
-               uint16_t src_port, dst_port;
-               uint32_t port = 0, pid = 0;
-               uint8_t type = 0, state;
-               uint32_t lqpn = 0, ps;
-               char *comm = NULL;
-               int err;
-
-               err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
-               if (err != MNL_CB_OK)
-                       return -EINVAL;
-
-               if (!nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
-                   !nla_line[RDMA_NLDEV_ATTR_RES_PS] ||
-                   (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
-                    !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
-                       return MNL_CB_ERROR;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
-                       port = mnl_attr_get_u32(
-                                       nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
-
-               if (port && port != rd->port_idx)
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN]) {
-                       lqpn = mnl_attr_get_u32(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
-                       if (rd_check_is_filtered(rd, "lqpn", lqpn))
-                               continue;
-               }
-               if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE]) {
-                       type = mnl_attr_get_u8(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
-                       if (rd_check_is_string_filtered(rd, "qp-type",
-                                                       qp_types_to_str(type)))
-                               continue;
-               }
-
-               ps = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PS]);
-               if (rd_check_is_string_filtered(rd, "ps", cm_id_ps_to_str(ps)))
-                       continue;
-
-               state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
-               if (rd_check_is_string_filtered(rd, "state",
-                                               cm_id_state_to_str(state)))
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR]) {
-                       if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR],
-                                   src_addr_str, &src_port))
-                               continue;
-                       if (rd_check_is_string_filtered(rd, "src-addr",
-                                                       src_addr_str))
-                               continue;
-                       if (rd_check_is_filtered(rd, "src-port", src_port))
-                               continue;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR]) {
-                       if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR],
-                                   dst_addr_str, &dst_port))
-                               continue;
-                       if (rd_check_is_string_filtered(rd, "dst-addr",
-                                                       dst_addr_str))
-                               continue;
-                       if (rd_check_is_filtered(rd, "dst-port", dst_port))
-                               continue;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
-                       pid = mnl_attr_get_u32(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_PID]);
-                       comm = get_task_name(pid);
-               }
-
-               if (rd_check_is_filtered(rd, "pid", pid)) {
-                       free(comm);
-                       continue;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) {
-                       /* discard const from mnl_attr_get_str */
-                       comm = (char *)mnl_attr_get_str(
-                               nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
-               }
-
-               if (rd->json_output)
-                       jsonw_start_array(rd->jw);
-
-               print_link(rd, idx, name, port, nla_line);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
-                       print_lqpn(rd, lqpn);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
-                       print_qp_type(rd, type);
-               print_cm_id_state(rd, state);
-               print_ps(rd, ps);
-               print_pid(rd, pid);
-               print_comm(rd, comm, nla_line);
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
-                       print_ipaddr(rd, "src-addr", src_addr_str, src_port);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
-                       print_ipaddr(rd, "dst-addr", dst_addr_str, dst_port);
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
-                       free(comm);
-
-               print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
-               newline(rd);
-       }
-       return MNL_CB_OK;
-}
-
-static void print_cqe(struct rd *rd, uint32_t val)
-{
-       if (rd->json_output)
-               jsonw_uint_field(rd->jw, "cqe", val);
-       else
-               pr_out("cqe %u ", val);
-}
-
-static void print_users(struct rd *rd, uint64_t val)
-{
-       if (rd->json_output)
-               jsonw_uint_field(rd->jw, "users", val);
-       else
-               pr_out("users %" PRIu64 " ", val);
-}
-
-static const char *poll_ctx_to_str(uint8_t idx)
-{
-       static const char * const cm_id_states_str[] = {
-               "DIRECT", "SOFTIRQ", "WORKQUEUE", "UNBOUND_WORKQUEUE"};
-
-       if (idx < ARRAY_SIZE(cm_id_states_str))
-               return cm_id_states_str[idx];
-       return "UNKNOWN";
-}
-
-static void print_poll_ctx(struct rd *rd, uint8_t poll_ctx)
+void print_key(struct rd *rd, const char *name, uint64_t val,
+              struct nlattr *nlattr)
 {
-       if (rd->json_output) {
-               jsonw_string_field(rd->jw, "poll-ctx",
-                                  poll_ctx_to_str(poll_ctx));
+       if (!nlattr)
                return;
-       }
-       pr_out("poll-ctx %s ", poll_ctx_to_str(poll_ctx));
-}
-
-static int res_cq_parse_cb(const struct nlmsghdr *nlh, void *data)
-{
-       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
-       struct nlattr *nla_table, *nla_entry;
-       struct rd *rd = data;
-       const char *name;
-       uint32_t idx;
-
-       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
-       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
-           !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
-           !tb[RDMA_NLDEV_ATTR_RES_CQ])
-               return MNL_CB_ERROR;
-
-       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
-       idx =  mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
-       nla_table = tb[RDMA_NLDEV_ATTR_RES_CQ];
-
-       mnl_attr_for_each_nested(nla_entry, nla_table) {
-               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
-               char *comm = NULL;
-               uint32_t pid = 0;
-               uint8_t poll_ctx = 0;
-               uint64_t users;
-               uint32_t cqe;
-               int err;
-
-               err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
-               if (err != MNL_CB_OK)
-                       return MNL_CB_ERROR;
-
-               if (!nla_line[RDMA_NLDEV_ATTR_RES_CQE] ||
-                   !nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
-                   (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
-                    !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
-                       return MNL_CB_ERROR;
-               }
-
-               cqe = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQE]);
-
-               users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
-               if (rd_check_is_filtered(rd, "users", users))
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]) {
-                       poll_ctx = mnl_attr_get_u8(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]);
-                       if (rd_check_is_string_filtered(rd, "poll-ctx",
-                                               poll_ctx_to_str(poll_ctx)))
-                               continue;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
-                       pid = mnl_attr_get_u32(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_PID]);
-                       comm = get_task_name(pid);
-               }
-
-               if (rd_check_is_filtered(rd, "pid", pid)) {
-                       free(comm);
-                       continue;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
-                       /* discard const from mnl_attr_get_str */
-                       comm = (char *)mnl_attr_get_str(
-                               nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
-
-               if (rd->json_output)
-                       jsonw_start_array(rd->jw);
-
-               print_dev(rd, idx, name);
-               print_cqe(rd, cqe);
-               print_users(rd, users);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX])
-                       print_poll_ctx(rd, poll_ctx);
-               print_pid(rd, pid);
-               print_comm(rd, comm, nla_line);
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
-                       free(comm);
 
-               print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
-               newline(rd);
-       }
-       return MNL_CB_OK;
-}
-
-static void print_key(struct rd *rd, const char *name, uint32_t val)
-{
        if (rd->json_output)
                jsonw_xint_field(rd->jw, name, val);
        else
-               pr_out("%s 0x%x ", name, val);
+               pr_out("%s 0x%" PRIx64 " ", name, val);
 }
 
-static void print_iova(struct rd *rd, uint64_t val)
+void res_print_uint(struct rd *rd, const char *name, uint64_t val,
+                   struct nlattr *nlattr)
 {
-       if (rd->json_output)
-               jsonw_xint_field(rd->jw, "iova", val);
-       else
-               pr_out("iova 0x%" PRIx64 " ", val);
-}
+       if (!nlattr)
+               return;
 
-static void print_mrlen(struct rd *rd, uint64_t val)
-{
        if (rd->json_output)
-               jsonw_uint_field(rd->jw, "mrlen", val);
+               jsonw_u64_field(rd->jw, name, val);
        else
-               pr_out("mrlen %" PRIu64 " ", val);
-}
-
-static int res_mr_parse_cb(const struct nlmsghdr *nlh, void *data)
-{
-       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
-       struct nlattr *nla_table, *nla_entry;
-       struct rd *rd = data;
-       const char *name;
-       uint32_t idx;
-
-       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
-       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
-           !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
-           !tb[RDMA_NLDEV_ATTR_RES_MR])
-               return MNL_CB_ERROR;
-
-       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
-       idx =  mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
-       nla_table = tb[RDMA_NLDEV_ATTR_RES_MR];
-
-       mnl_attr_for_each_nested(nla_entry, nla_table) {
-               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
-               uint32_t rkey = 0, lkey = 0;
-               uint64_t iova = 0, mrlen;
-               char *comm = NULL;
-               uint32_t pid = 0;
-               int err;
-
-               err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
-               if (err != MNL_CB_OK)
-                       return MNL_CB_ERROR;
-
-               if (!nla_line[RDMA_NLDEV_ATTR_RES_MRLEN] ||
-                   (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
-                    !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
-                       return MNL_CB_ERROR;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
-                       rkey = mnl_attr_get_u32(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_RKEY]);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
-                       lkey = mnl_attr_get_u32(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_LKEY]);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
-                       iova = mnl_attr_get_u64(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_IOVA]);
-
-               mrlen = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]);
-               if (rd_check_is_filtered(rd, "mrlen", mrlen))
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
-                       pid = mnl_attr_get_u32(
-                                       nla_line[RDMA_NLDEV_ATTR_RES_PID]);
-                       comm = get_task_name(pid);
-               }
-
-               if (rd_check_is_filtered(rd, "pid", pid)) {
-                       free(comm);
-                       continue;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
-                       /* discard const from mnl_attr_get_str */
-                       comm = (char *)mnl_attr_get_str(
-                               nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
-
-               if (rd->json_output)
-                       jsonw_start_array(rd->jw);
-
-               print_dev(rd, idx, name);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
-                       print_key(rd, "rkey", rkey);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
-                       print_key(rd, "lkey", lkey);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
-                       print_iova(rd, iova);
-               print_mrlen(rd, mrlen);
-               print_pid(rd, pid);
-               print_comm(rd, comm, nla_line);
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
-                       free(comm);
-
-               print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
-               newline(rd);
-       }
-       return MNL_CB_OK;
+               pr_out("%s %" PRIu64 " ", name, val);
 }
 
-static int res_pd_parse_cb(const struct nlmsghdr *nlh, void *data)
-{
-       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
-       struct nlattr *nla_table, *nla_entry;
-       struct rd *rd = data;
-       const char *name;
-       uint32_t idx;
-
-       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
-       if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
-           !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
-           !tb[RDMA_NLDEV_ATTR_RES_PD])
-               return MNL_CB_ERROR;
-
-       name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
-       idx =  mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
-       nla_table = tb[RDMA_NLDEV_ATTR_RES_PD];
-
-       mnl_attr_for_each_nested(nla_entry, nla_table) {
-               uint32_t local_dma_lkey = 0, unsafe_global_rkey = 0;
-               struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
-               char *comm = NULL;
-               uint32_t pid = 0;
-               uint64_t users;
-               int err;
-
-               err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
-               if (err != MNL_CB_OK)
-                       return MNL_CB_ERROR;
-
-               if (!nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
-                   (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
-                    !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
-                       return MNL_CB_ERROR;
-               }
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY])
-                       local_dma_lkey = mnl_attr_get_u32(
-                               nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]);
-
-               users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
-               if (rd_check_is_filtered(rd, "users", users))
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY])
-                       unsafe_global_rkey = mnl_attr_get_u32(
-                             nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]);
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
-                       pid = mnl_attr_get_u32(
-                               nla_line[RDMA_NLDEV_ATTR_RES_PID]);
-                       comm = get_task_name(pid);
-               }
-
-               if (rd_check_is_filtered(rd, "pid", pid))
-                       continue;
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
-                       /* discard const from mnl_attr_get_str */
-                       comm = (char *)mnl_attr_get_str(
-                               nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
-
-               if (rd->json_output)
-                       jsonw_start_array(rd->jw);
-
-               print_dev(rd, idx, name);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY])
-                       print_key(rd, "local_dma_lkey", local_dma_lkey);
-               print_users(rd, users);
-               if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY])
-                       print_key(rd, "unsafe_global_rkey", unsafe_global_rkey);
-               print_pid(rd, pid);
-               print_comm(rd, comm, nla_line);
-
-               if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
-                       free(comm);
-
-               print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
-               newline(rd);
-       }
-       return MNL_CB_OK;
-}
-
-RES_FUNC(res_no_args,  RDMA_NLDEV_CMD_RES_GET, NULL, true);
-
-static const struct
-filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {{ .name = "link",
-                                                  .is_number = false },
-                                                  { .name = "lqpn",
-                                                  .is_number = true },
-                                                  { .name = "rqpn",
-                                                  .is_number = true },
-                                                  { .name = "pid",
-                                                  .is_number = true },
-                                                  { .name = "sq-psn",
-                                                  .is_number = true },
-                                                  { .name = "rq-psn",
-                                                  .is_number = true },
-                                                  { .name = "type",
-                                                  .is_number = false },
-                                                  { .name = "path-mig-state",
-                                                  .is_number = false },
-                                                  { .name = "state",
-                                                  .is_number = false } };
-
-RES_FUNC(res_qp,       RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false);
-
-static const
-struct filters cm_id_valid_filters[MAX_NUMBER_OF_FILTERS] = {
-       { .name = "link", .is_number = false },
-       { .name = "lqpn", .is_number = true },
-       { .name = "qp-type", .is_number = false },
-       { .name = "state", .is_number = false },
-       { .name = "ps", .is_number = false },
-       { .name = "dev-type", .is_number = false },
-       { .name = "transport-type", .is_number = false },
-       { .name = "pid", .is_number = true },
-       { .name = "src-addr", .is_number = false },
-       { .name = "src-port", .is_number = true },
-       { .name = "dst-addr", .is_number = false },
-       { .name = "dst-port", .is_number = true }
-};
-
-RES_FUNC(res_cm_id, RDMA_NLDEV_CMD_RES_CM_ID_GET, cm_id_valid_filters, false);
-
-static const
-struct filters cq_valid_filters[MAX_NUMBER_OF_FILTERS] = {
-       { .name = "dev", .is_number = false },
-       { .name = "users", .is_number = true },
-       { .name = "poll-ctx", .is_number = false },
-       { .name = "pid", .is_number = true }
-};
-
-RES_FUNC(res_cq, RDMA_NLDEV_CMD_RES_CQ_GET, cq_valid_filters, true);
-
-static const
-struct filters mr_valid_filters[MAX_NUMBER_OF_FILTERS] = {
-       { .name = "dev", .is_number = false },
-       { .name = "rkey", .is_number = true },
-       { .name = "lkey", .is_number = true },
-       { .name = "mrlen", .is_number = true },
-       { .name = "pid", .is_number = true }
-};
-
-RES_FUNC(res_mr, RDMA_NLDEV_CMD_RES_MR_GET, mr_valid_filters, true);
-
-static const
-struct filters pd_valid_filters[MAX_NUMBER_OF_FILTERS] = {
-       { .name = "dev", .is_number = false },
-       { .name = "users", .is_number = true },
-       { .name = "pid", .is_number = true }
-};
-
-RES_FUNC(res_pd, RDMA_NLDEV_CMD_RES_PD_GET, pd_valid_filters, true);
+RES_FUNC(res_no_args,  RDMA_NLDEV_CMD_RES_GET, NULL, true, 0);
 
 static int res_show(struct rd *rd)
 {
diff --git a/rdma/res.h b/rdma/res.h
new file mode 100644 (file)
index 0000000..b4a7e55
--- /dev/null
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/*
+ * res.h       RDMA tool
+ * Authors:     Leon Romanovsky <leonro@mellanox.com>
+ */
+#ifndef _RDMA_TOOL_RES_H_
+#define _RDMA_TOOL_RES_H_
+
+#include "rdma.h"
+
+int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback);
+int _res_send_idx_msg(struct rd *rd, uint32_t command, mnl_cb_t callback,
+                     uint32_t idx, uint32_t id);
+
+int res_pd_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_pd_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_mr_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_mr_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_cq_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_cq_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_cm_id_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_cm_id_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_qp_parse_cb(const struct nlmsghdr *nlh, void *data);
+int res_qp_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
+
+#define RES_FUNC(name, command, valid_filters, strict_port, id)                        \
+       static inline int _##name(struct rd *rd)                                       \
+       {                                                                              \
+               uint32_t idx;                                                          \
+               int ret;                                                               \
+               if (id) {                                                              \
+                       ret = rd_doit_index(rd, &idx);                                 \
+                       if (ret) {                                                     \
+                               ret = _res_send_idx_msg(rd, command,                   \
+                                                       name##_idx_parse_cb,           \
+                                                       idx, id);                      \
+                               if (!ret)                                              \
+                                       return ret;                                    \
+                               /* Fallback for old systems without .doit callbacks */ \
+                       }                                                              \
+               }                                                                      \
+               return _res_send_msg(rd, command, name##_parse_cb);                    \
+       }                                                                              \
+       static inline int name(struct rd *rd)                                          \
+       {                                                                              \
+               int ret = rd_build_filter(rd, valid_filters);                          \
+               if (ret)                                                               \
+                       return ret;                                                    \
+               if ((uintptr_t)valid_filters != (uintptr_t)NULL) {                     \
+                       ret = rd_set_arg_to_devname(rd);                               \
+                       if (ret)                                                       \
+                               return ret;                                            \
+               }                                                                      \
+               if (strict_port)                                                       \
+                       return rd_exec_dev(rd, _##name);                               \
+               else                                                                   \
+                       return rd_exec_link(rd, _##name, strict_port);                 \
+       }
+
+static const
+struct filters pd_valid_filters[MAX_NUMBER_OF_FILTERS] = {
+       { .name = "dev", .is_number = false },
+       { .name = "users", .is_number = true },
+       { .name = "pid", .is_number = true },
+       { .name = "ctxn", .is_number = true },
+       { .name = "pdn", .is_number = true, .is_doit = true },
+       { .name = "ctxn", .is_number = true }
+};
+
+RES_FUNC(res_pd, RDMA_NLDEV_CMD_RES_PD_GET, pd_valid_filters, true,
+        RDMA_NLDEV_ATTR_RES_PDN);
+
+static const
+struct filters mr_valid_filters[MAX_NUMBER_OF_FILTERS] = {
+       { .name = "dev", .is_number = false },
+       { .name = "rkey", .is_number = true },
+       { .name = "lkey", .is_number = true },
+       { .name = "mrlen", .is_number = true },
+       { .name = "pid", .is_number = true },
+       { .name = "mrn", .is_number = true, .is_doit = true },
+       { .name = "pdn", .is_number = true }
+};
+
+RES_FUNC(res_mr, RDMA_NLDEV_CMD_RES_MR_GET, mr_valid_filters, true,
+        RDMA_NLDEV_ATTR_RES_MRN);
+
+static const
+struct filters cq_valid_filters[MAX_NUMBER_OF_FILTERS] = {
+       { .name = "dev", .is_number = false },
+       { .name = "users", .is_number = true },
+       { .name = "poll-ctx", .is_number = false },
+       { .name = "pid", .is_number = true },
+       { .name = "cqn", .is_number = true, .is_doit = true },
+       { .name = "ctxn", .is_number = true }
+};
+
+RES_FUNC(res_cq, RDMA_NLDEV_CMD_RES_CQ_GET, cq_valid_filters, true,
+        RDMA_NLDEV_ATTR_RES_CQN);
+
+static const
+struct filters cm_id_valid_filters[MAX_NUMBER_OF_FILTERS] = {
+       { .name = "link", .is_number = false },
+       { .name = "lqpn", .is_number = true },
+       { .name = "qp-type", .is_number = false },
+       { .name = "state", .is_number = false },
+       { .name = "ps", .is_number = false },
+       { .name = "dev-type", .is_number = false },
+       { .name = "transport-type", .is_number = false },
+       { .name = "pid", .is_number = true },
+       { .name = "src-addr", .is_number = false },
+       { .name = "src-port", .is_number = true },
+       { .name = "dst-addr", .is_number = false },
+       { .name = "dst-port", .is_number = true },
+       { .name = "cm-idn", .is_number = true, .is_doit = true }
+};
+
+RES_FUNC(res_cm_id, RDMA_NLDEV_CMD_RES_CM_ID_GET, cm_id_valid_filters, false,
+        RDMA_NLDEV_ATTR_RES_CM_IDN);
+
+static const struct
+filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {
+       { .name = "link", .is_number = false },
+       { .name = "lqpn", .is_number = true, .is_doit = true },
+       { .name = "rqpn", .is_number = true },
+       { .name = "pid",  .is_number = true },
+       { .name = "sq-psn", .is_number = true },
+       { .name = "rq-psn", .is_number = true },
+       { .name = "type", .is_number = false },
+       { .name = "path-mig-state", .is_number = false },
+       { .name = "state", .is_number = false },
+       { .name = "pdn", .is_number = true },
+};
+
+RES_FUNC(res_qp, RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false,
+        RDMA_NLDEV_ATTR_RES_LQPN);
+
+char *get_task_name(uint32_t pid);
+void print_dev(struct rd *rd, uint32_t idx, const char *name);
+void print_link(struct rd *rd, uint32_t idx, const char *name, uint32_t port,
+               struct nlattr **nla_line);
+void print_key(struct rd *rd, const char *name, uint64_t val,
+              struct nlattr *nlattr);
+void res_print_uint(struct rd *rd, const char *name, uint64_t val,
+                   struct nlattr *nlattr);
+void print_comm(struct rd *rd, const char *str, struct nlattr **nla_line);
+const char *qp_types_to_str(uint8_t idx);
+
+#endif /* _RDMA_TOOL_RES_H_ */
index 069d44fece1015d602f6941d4b2a3820caea56c7..6bc14cd5c961b5cb7b0c965246389408f0cd3df8 100644 (file)
@@ -1,11 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
  * utils.c     RDMA tool
- *
- *              This program is free software; you can redistribute it and/or
- *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
- *
  * Authors:     Leon Romanovsky <leonro@mellanox.com>
  */
 
@@ -126,6 +121,7 @@ static int add_filter(struct rd *rd, char *key, char *value,
        struct filter_entry *fe;
        bool key_found = false;
        int idx = 0;
+       char *endp;
        int ret;
 
        fe = calloc(1, sizeof(*fe));
@@ -168,6 +164,11 @@ static int add_filter(struct rd *rd, char *key, char *value,
                goto err_alloc;
        }
 
+       errno = 0;
+       strtol(fe->value, &endp, 10);
+       if (valid_filters[idx].is_doit && !errno && *endp == '\0')
+               fe->is_doit = true;
+
        for (idx = 0; idx < strlen(fe->value); idx++)
                fe->value[idx] = tolower(fe->value[idx]);
 
@@ -182,6 +183,20 @@ err:
        return ret;
 }
 
+bool rd_doit_index(struct rd *rd, uint32_t *idx)
+{
+       struct filter_entry *fe;
+
+       list_for_each_entry(fe, &rd->filter_list, list) {
+               if (fe->is_doit) {
+                       *idx = atoi(fe->value);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 int rd_build_filter(struct rd *rd, const struct filters valid_filters[])
 {
        int ret = 0;
@@ -218,7 +233,7 @@ out:
        return ret;
 }
 
-bool rd_check_is_key_exist(struct rd *rd, const char *key)
+static bool rd_check_is_key_exist(struct rd *rd, const char *key)
 {
        struct filter_entry *fe;
 
@@ -234,8 +249,8 @@ bool rd_check_is_key_exist(struct rd *rd, const char *key)
  * 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)
+static bool rd_check_is_string_filtered(struct rd *rd, const char *key,
+                                       const char *val)
 {
        bool key_is_filtered = false;
        struct filter_entry *fe;
@@ -285,7 +300,7 @@ out:
  * 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)
+static bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val)
 {
        bool key_is_filtered = false;
        struct filter_entry *fe;
@@ -334,6 +349,24 @@ out:
        return key_is_filtered;
 }
 
+bool rd_is_filtered_attr(struct rd *rd, const char *key, uint32_t val,
+                        struct nlattr *attr)
+{
+       if (!attr)
+               return rd_check_is_key_exist(rd, key);
+
+       return rd_check_is_filtered(rd, key, val);
+}
+
+bool rd_is_string_filtered_attr(struct rd *rd, const char *key, const char *val,
+                               struct nlattr *attr)
+{
+       if (!attr)
+               rd_check_is_key_exist(rd, key);
+
+       return rd_check_is_string_filtered(rd, key, val);
+}
+
 static void filters_cleanup(struct rd *rd)
 {
        struct filter_entry *fe, *tmp;