diff options
Diffstat (limited to 'rdma/res-srq.c')
-rw-r--r-- | rdma/res-srq.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/rdma/res-srq.c b/rdma/res-srq.c new file mode 100644 index 0000000..8ab2538 --- /dev/null +++ b/rdma/res-srq.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* + * res-srq.c RDMA tool + * Authors: Neta Ostrovsky <netao@nvidia.com> + */ + +#include "res.h" +#include <inttypes.h> + +#define MAX_QP_STR_LEN 256 + +static const char *srq_types_to_str(uint8_t idx) +{ + static const char *const srq_types_str[] = { "BASIC", + "XRC", + "TM" }; + + if (idx < ARRAY_SIZE(srq_types_str)) + return srq_types_str[idx]; + return "UNKNOWN"; +} + +static void print_type(uint32_t val) +{ + print_string(PRINT_ANY, "type", "type %s ", srq_types_to_str(val)); +} + +static void print_qps(char *qp_str) +{ + char *qpn; + + if (!strlen(qp_str)) + return; + + open_json_array(PRINT_ANY, "lqpn"); + print_string(PRINT_FP, NULL, " ", NULL); + qpn = strtok(qp_str, ","); + while (qpn) { + print_string(PRINT_ANY, NULL, "%s", qpn); + qpn = strtok(NULL, ","); + if (qpn) + print_string(PRINT_FP, NULL, ",", NULL); + } + print_string(PRINT_FP, NULL, " ", NULL); + close_json_array(PRINT_JSON, NULL); +} + +static int filter_srq_range_qps(struct rd *rd, struct nlattr **qp_line, + uint32_t min_range, uint32_t max_range, + char **delimiter, char *qp_str) +{ + uint32_t qpn = 0, tmp_min_range = 0, tmp_max_range = 0; + char tmp[16] = {}; + + for (qpn = min_range; qpn <= max_range; qpn++) { + if (rd_is_filtered_attr(rd, "lqpn", qpn, + qp_line[RDMA_NLDEV_ATTR_MIN_RANGE])) { + /* The QPs range contains a LQPN that is filtered */ + if (!tmp_min_range) + /* There are no QPs previous to + * the filtered one + */ + continue; + if (!tmp_max_range) + snprintf(tmp, sizeof(tmp), "%s%d", *delimiter, + tmp_min_range); + else + snprintf(tmp, sizeof(tmp), "%s%d-%d", + *delimiter, tmp_min_range, + tmp_max_range); + + strncat(qp_str, tmp, + MAX_QP_STR_LEN - strlen(qp_str) - 1); + + memset(tmp, 0, strlen(tmp)); + *delimiter = ","; + tmp_min_range = 0; + tmp_max_range = 0; + continue; + } + if (!tmp_min_range) + tmp_min_range = qpn; + else + tmp_max_range = qpn; + } + + if (!tmp_min_range) + return 0; + if (!tmp_max_range) + snprintf(tmp, sizeof(tmp), "%s%d", *delimiter, tmp_min_range); + else + snprintf(tmp, sizeof(tmp), "%s%d-%d", *delimiter, + tmp_min_range, tmp_max_range); + + strncat(qp_str, tmp, MAX_QP_STR_LEN - strlen(qp_str) - 1); + *delimiter = ","; + return 0; +} + +static int get_srq_qps(struct rd *rd, struct nlattr *qp_table, char *qp_str) +{ + uint32_t qpn = 0, min_range = 0, max_range = 0; + struct nlattr *nla_entry; + struct filter_entry *fe; + char *delimiter = ""; + char tmp[16] = {}; + + if (!qp_table) + return MNL_CB_ERROR; + + /* If there are no QPs associated with the SRQ, return */ + if (!(mnl_attr_get_payload_len(qp_table))) { + list_for_each_entry(fe, &rd->filter_list, list) { + if (!strcmpx(fe->key, "lqpn")) + /* We found the key - + * user requested to filter by LQPN + */ + return -EINVAL; + } + return MNL_CB_OK; + } + + mnl_attr_for_each_nested(nla_entry, qp_table) { + struct nlattr *qp_line[RDMA_NLDEV_ATTR_MAX] = {}; + + if (mnl_attr_parse_nested(nla_entry, rd_attr_cb, qp_line) != + MNL_CB_OK) + goto out; + + if (qp_line[RDMA_NLDEV_ATTR_RES_LQPN]) { + qpn = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_RES_LQPN]); + if (rd_is_filtered_attr(rd, "lqpn", qpn, + qp_line[RDMA_NLDEV_ATTR_RES_LQPN])) + continue; + snprintf(tmp, sizeof(tmp), "%s%d", delimiter, qpn); + strncat(qp_str, tmp, + MAX_QP_STR_LEN - strlen(qp_str) - 1); + delimiter = ","; + } else if (qp_line[RDMA_NLDEV_ATTR_MIN_RANGE] && + qp_line[RDMA_NLDEV_ATTR_MAX_RANGE]) { + min_range = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_MIN_RANGE]); + max_range = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_MAX_RANGE]); + + if (filter_srq_range_qps(rd, qp_line, min_range, + max_range, &delimiter, + qp_str)) + goto out; + } else { + goto out; + } + } + + if (!strlen(qp_str)) + /* Check if there are no QPs to display after filter */ + goto out; + + return MNL_CB_OK; + +out: + memset(qp_str, 0, strlen(qp_str)); + return -EINVAL; +} + +static int res_srq_line_raw(struct rd *rd, const char *name, int idx, + struct nlattr **nla_line) +{ + if (!nla_line[RDMA_NLDEV_ATTR_RES_RAW]) + return MNL_CB_ERROR; + + open_json_object(NULL); + print_dev(idx, name); + print_raw_data(rd, nla_line); + close_json_object(); + newline(); + + return MNL_CB_OK; +} + +static int res_srq_line(struct rd *rd, const char *name, int idx, + struct nlattr **nla_line) +{ + uint32_t srqn = 0, pid = 0, pdn = 0, cqn = 0; + char qp_str[MAX_QP_STR_LEN] = {}; + char *comm = NULL; + uint8_t type = 0; + SPRINT_BUF(b); + + if (!nla_line[RDMA_NLDEV_ATTR_RES_SRQN]) + return MNL_CB_ERROR; + + if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) { + pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]); + if (!get_task_name(pid, b, sizeof(b))) + comm = b; + } else 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_is_filtered_attr(rd, "pid", pid, + nla_line[RDMA_NLDEV_ATTR_RES_PID])) + goto out; + + if (nla_line[RDMA_NLDEV_ATTR_RES_SRQN]) + srqn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_SRQN]); + if (rd_is_filtered_attr(rd, "srqn", srqn, + nla_line[RDMA_NLDEV_ATTR_RES_SRQN])) + 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, "type", srq_types_to_str(type), + nla_line[RDMA_NLDEV_ATTR_RES_TYPE])) + 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_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 (get_srq_qps(rd, nla_line[RDMA_NLDEV_ATTR_RES_QP], qp_str) != + MNL_CB_OK) + goto out; + + open_json_object(NULL); + print_dev(idx, name); + res_print_u32("srqn", srqn, nla_line[RDMA_NLDEV_ATTR_RES_SRQN]); + print_type(type); + print_qps(qp_str); + res_print_u32("pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]); + res_print_u32("cqn", cqn, nla_line[RDMA_NLDEV_ATTR_RES_CQN]); + res_print_u32("pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]); + print_comm(comm, nla_line); + + print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]); + close_json_object(); + newline(); + +out: + return MNL_CB_OK; +} + +int res_srq_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 (rd->show_raw) ? res_srq_line_raw(rd, name, idx, tb) : + res_srq_line(rd, name, idx, tb); +} + +int res_srq_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_SRQ]) + 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_SRQ]; + + 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 = (rd->show_raw) ? res_srq_line_raw(rd, name, idx, nla_line) : + res_srq_line(rd, name, idx, nla_line); + if (ret != MNL_CB_OK) + break; + } + return ret; +} |