mirror_iproute2/rdma/res-cmid.c
Mark Zhang e28133316d rdma: Add "PID" criteria support for statistic counter auto mode
With this new criteria, QPs have different PIDs will be bound to
different counters in auto mode. This can be used in combination with
other criteria like "type". Examples:

$ rdma statistic qp set link mlx5_2/1 auto pid on
$ rdma statistic qp set link mlx5_2/1 auto type,pid on
$ rdma statistic qp set link mlx5_2/1 auto off
$ rdma statistic qp show link mlx5_0 qp-type UD

Signed-off-by: Mark Zhang <markz@mellanox.com>
Reviewed-by: Ido Kalir <idok@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2020-08-06 16:26:04 +00:00

255 lines
7.0 KiB
C

// 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 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)
{
print_color_string(PRINT_ANY, COLOR_NONE, "state", "state %s ",
cm_id_state_to_str(state));
}
static void print_ps(struct rd *rd, uint32_t ps)
{
print_color_string(PRINT_ANY, COLOR_NONE, "ps", "ps %s ",
cm_id_ps_to_str(ps));
}
static void print_ipaddr(struct rd *rd, const char *key, char *addrstr,
uint16_t port)
{
int name_size = INET6_ADDRSTRLEN + strlen(":65535");
char json_name[name_size];
snprintf(json_name, name_size, "%s:%u", addrstr, port);
print_color_string(PRINT_ANY, COLOR_NONE, key, key, json_name);
print_color_string(PRINT_FP, COLOR_NONE, NULL, " %s:", addrstr);
print_color_uint(PRINT_FP, COLOR_NONE, NULL, "%u ", 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])
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]);
}
open_json_object(NULL);
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;
}