Merge branch 'rdma-resource-tracking' into next

Leon Romanovsky  says:

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

This is the user space part of already accepted to the kernel series
that extends RDMA netlink interface to return uverbs context and SRQ
information.

The accepted kernel series can be seen here:
https://lore.kernel.org/linux-rdma/20210422133459.GA2390260@nvidia.com/

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

Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
David Ahern 2021-04-28 15:37:32 +00:00
commit e5f1505e53
8 changed files with 445 additions and 3 deletions

View File

@ -13,7 +13,7 @@ rdma-resource \- rdma resource configuration
.ti -8
.IR RESOURCE " := { "
.BR cm_id " | " cq " | " mr " | " pd " | " qp " }"
.BR cm_id " | " cq " | " mr " | " pd " | " qp " | " ctx " | " srq " }"
.sp
.ti -8
@ -103,6 +103,16 @@ rdma resource show cq pid 30489
Show CQs belonging to pid 30489
.RE
.PP
rdma resource show ctx ctxn 1
.RS 4
Show contexts that have index equal to 1.
.RE
.PP
rdma resource show srq lqpn 5-7
.RS 4
Show SRQs that the QPs with lqpn 5-7 are associated with.
.RE
.PP
.SH SEE ALSO
.BR rdma (8),

View File

@ -7,7 +7,7 @@ ifeq ($(HAVE_MNL),y)
CFLAGS += -I./include/uapi/
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 sys.o stat.o stat-mr.o
res-cmid.o res-qp.o sys.o stat.o stat-mr.o res-ctx.o res-srq.o
TARGETS += rdma
endif

View File

@ -293,6 +293,10 @@ enum rdma_nldev_command {
RDMA_NLDEV_CMD_RES_MR_GET_RAW,
RDMA_NLDEV_CMD_RES_CTX_GET, /* can dump */
RDMA_NLDEV_CMD_RES_SRQ_GET, /* can dump */
RDMA_NLDEV_NUM_OPS
};
@ -533,6 +537,15 @@ enum rdma_nldev_attr {
RDMA_NLDEV_ATTR_RES_RAW, /* binary */
RDMA_NLDEV_ATTR_RES_CTX, /* nested table */
RDMA_NLDEV_ATTR_RES_CTX_ENTRY, /* nested table */
RDMA_NLDEV_ATTR_RES_SRQ, /* nested table */
RDMA_NLDEV_ATTR_RES_SRQ_ENTRY, /* nested table */
RDMA_NLDEV_ATTR_RES_SRQN, /* u32 */
RDMA_NLDEV_ATTR_MIN_RANGE, /* u32 */
RDMA_NLDEV_ATTR_MAX_RANGE, /* u32 */
/*
* Always the end
*/

103
rdma/res-ctx.c Normal file
View File

@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* res-ctx.c RDMA tool
* Authors: Neta Ostrovsky <netao@nvidia.com>
*/
#include "res.h"
#include <inttypes.h>
static int res_ctx_line(struct rd *rd, const char *name, int idx,
struct nlattr **nla_line)
{
char *comm = NULL;
uint32_t ctxn = 0;
uint32_t pid = 0;
if (!nla_line[RDMA_NLDEV_ATTR_RES_CTXN])
return MNL_CB_ERROR;
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_KERN_NAME])
/* discard const from mnl_attr_get_str */
comm = (char *)mnl_attr_get_str(
nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
open_json_object(NULL);
print_dev(rd, idx, name);
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_ctx_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_ctx_line(rd, name, idx, tb);
}
int res_ctx_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_CTX])
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_CTX];
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_ctx_line(rd, name, idx, nla_line);
if (ret != MNL_CB_OK)
break;
}
return ret;
}

274
rdma/res-srq.c Normal file
View File

@ -0,0 +1,274 @@
// 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(struct rd *rd, uint32_t val)
{
print_color_string(PRINT_ANY, COLOR_NONE, "type", "type %s ",
srq_types_to_str(val));
}
static void print_qps(const char *str)
{
if (!strlen(str))
return;
print_color_string(PRINT_ANY, COLOR_NONE, "lqpn", "lqpn %s ", str);
}
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);
if (strlen(qp_str) + strlen(tmp) >= MAX_QP_STR_LEN)
return -EINVAL;
strncat(qp_str, tmp, sizeof(tmp) - 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);
if (strlen(qp_str) + strlen(tmp) >= MAX_QP_STR_LEN)
return -EINVAL;
strncat(qp_str, tmp, sizeof(tmp) - 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);
if (strlen(qp_str) + strlen(tmp) >= MAX_QP_STR_LEN)
goto out;
strncat(qp_str, tmp, sizeof(tmp) - 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(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;
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]);
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_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;
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]);
open_json_object(NULL);
print_dev(rd, idx, name);
res_print_uint(rd, "srqn", srqn, nla_line[RDMA_NLDEV_ATTR_RES_SRQN]);
print_type(rd, type);
print_qps(qp_str);
res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
res_print_uint(rd, "cqn", cqn, nla_line[RDMA_NLDEV_ATTR_RES_CQN]);
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_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 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 = res_srq_line(rd, name, idx, nla_line);
if (ret != MNL_CB_OK)
break;
}
return ret;
}

View File

@ -11,7 +11,7 @@ static int res_help(struct rd *rd)
{
pr_out("Usage: %s resource\n", rd->filename);
pr_out(" resource show [DEV]\n");
pr_out(" resource show [qp|cm_id|pd|mr|cq]\n");
pr_out(" resource show [qp|cm_id|pd|mr|cq|ctx|srq]\n");
pr_out(" resource show qp link [DEV/PORT]\n");
pr_out(" resource show qp link [DEV/PORT] [FILTER-NAME FILTER-VALUE]\n");
pr_out(" resource show cm_id link [DEV/PORT]\n");
@ -22,6 +22,10 @@ static int res_help(struct rd *rd)
pr_out(" resource show pd dev [DEV] [FILTER-NAME FILTER-VALUE]\n");
pr_out(" resource show mr dev [DEV]\n");
pr_out(" resource show mr dev [DEV] [FILTER-NAME FILTER-VALUE]\n");
pr_out(" resource show ctx dev [DEV]\n");
pr_out(" resource show ctx dev [DEV] [FILTER-NAME FILTER-VALUE]\n");
pr_out(" resource show srq dev [DEV]\n");
pr_out(" resource show srq dev [DEV] [FILTER-NAME FILTER-VALUE]\n");
return 0;
}
@ -224,6 +228,8 @@ static int res_show(struct rd *rd)
{ "cq", res_cq },
{ "mr", res_mr },
{ "pd", res_pd },
{ "ctx", res_ctx },
{ "srq", res_srq },
{ 0 }
};

View File

@ -22,6 +22,10 @@ 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);
int res_ctx_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_ctx_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_srq_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_srq_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
static inline uint32_t res_get_command(uint32_t command, struct rd *rd)
{
@ -155,6 +159,30 @@ filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {
RES_FUNC(res_qp, RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false,
RDMA_NLDEV_ATTR_RES_LQPN);
static const
struct filters ctx_valid_filters[MAX_NUMBER_OF_FILTERS] = {
{ .name = "dev", .is_number = false },
{ .name = "pid", .is_number = true },
{ .name = "ctxn", .is_number = true, .is_doit = true },
};
RES_FUNC(res_ctx, RDMA_NLDEV_CMD_RES_CTX_GET, ctx_valid_filters, true,
RDMA_NLDEV_ATTR_RES_CTXN);
static const
struct filters srq_valid_filters[MAX_NUMBER_OF_FILTERS] = {
{ .name = "dev", .is_number = false },
{ .name = "pid", .is_number = true },
{ .name = "srqn", .is_number = true, .is_doit = true },
{ .name = "type", .is_number = false },
{ .name = "pdn", .is_number = true },
{ .name = "cqn", .is_number = true },
{ .name = "lqpn", .is_number = true },
};
RES_FUNC(res_srq, RDMA_NLDEV_CMD_RES_SRQ_GET, srq_valid_filters, true,
RDMA_NLDEV_ATTR_RES_SRQN);
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);

View File

@ -435,6 +435,14 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
[RDMA_NLDEV_ATTR_RES_LKEY] = MNL_TYPE_U32,
[RDMA_NLDEV_ATTR_RES_IOVA] = MNL_TYPE_U64,
[RDMA_NLDEV_ATTR_RES_MRLEN] = MNL_TYPE_U64,
[RDMA_NLDEV_ATTR_RES_CTX] = MNL_TYPE_NESTED,
[RDMA_NLDEV_ATTR_RES_CTX_ENTRY] = MNL_TYPE_NESTED,
[RDMA_NLDEV_ATTR_RES_CTXN] = MNL_TYPE_U32,
[RDMA_NLDEV_ATTR_RES_SRQ] = MNL_TYPE_NESTED,
[RDMA_NLDEV_ATTR_RES_SRQ_ENTRY] = MNL_TYPE_NESTED,
[RDMA_NLDEV_ATTR_RES_SRQN] = MNL_TYPE_U32,
[RDMA_NLDEV_ATTR_MIN_RANGE] = MNL_TYPE_U32,
[RDMA_NLDEV_ATTR_MAX_RANGE] = MNL_TYPE_U32,
[RDMA_NLDEV_ATTR_NDEV_INDEX] = MNL_TYPE_U32,
[RDMA_NLDEV_ATTR_NDEV_NAME] = MNL_TYPE_NUL_STRING,
[RDMA_NLDEV_ATTR_DRIVER] = MNL_TYPE_NESTED,