1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* monitor.c RDMA tool
* Authors: Chiara Meiohas <cmeiohas@nvidia.com>
*/
#include "rdma.h"
#include "utils.h"
static int mon_is_supported_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
uint8_t *is_sup = data;
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
if (tb[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE])
*is_sup = mnl_attr_get_u8(tb[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE]);
return MNL_CB_OK;
}
static int mon_is_supported(struct rd *rd, uint8_t *is_sup)
{
uint32_t seq;
int ret;
*is_sup = 0;
rd_prepare_msg(rd, RDMA_NLDEV_CMD_SYS_GET,
&seq, (NLM_F_REQUEST | NLM_F_ACK));
ret = rd_send_msg(rd);
if (ret)
return ret;
return rd_recv_msg(rd, mon_is_supported_cb, is_sup, seq);
}
static void mon_print_event_type(struct nlattr **tb)
{
const char *const event_types_str[] = {
[RDMA_REGISTER_EVENT] = "[REGISTER]",
[RDMA_UNREGISTER_EVENT] = "[UNREGISTER]",
[RDMA_NETDEV_ATTACH_EVENT] = "[NETDEV_ATTACH]",
[RDMA_NETDEV_DETACH_EVENT] = "[NETDEV_DETACH]",
[RDMA_RENAME_EVENT] = "[RENAME]",
[RDMA_NETDEV_RENAME_EVENT] = "[NETDEV_RENAME]",
};
enum rdma_nl_notify_event_type etype;
char unknown_type[32];
if (!tb[RDMA_NLDEV_ATTR_EVENT_TYPE])
return;
etype = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_EVENT_TYPE]);
if (etype < ARRAY_SIZE(event_types_str) && event_types_str[etype]) {
print_string(PRINT_ANY, "event_type", "%s\t",
event_types_str[etype]);
} else {
snprintf(unknown_type, sizeof(unknown_type), "[UNKNOWN 0x%02x]",
etype);
print_string(PRINT_ANY, "event_type", "%s\t", unknown_type);
}
}
static int mon_print_dev(struct nlattr **tb)
{
const char *name;
uint32_t idx;
if (tb[RDMA_NLDEV_ATTR_DEV_INDEX]) {
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
print_uint(PRINT_ANY, "rdma_index", "dev %u", idx);
}
if(tb[RDMA_NLDEV_ATTR_DEV_NAME]) {
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
print_string(PRINT_ANY, "rdma_dev", " %s", name);
}
return 0;
}
static void mon_print_port_idx(struct nlattr **tb)
{
uint32_t port;
if (tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
print_uint(PRINT_ANY, "port", " port %u", port);
}
}
static void mon_print_netdev(struct nlattr **tb)
{
uint32_t netdev_idx;
const char *name;
if (tb[RDMA_NLDEV_ATTR_NDEV_INDEX]) {
netdev_idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_NDEV_INDEX]);
print_uint(PRINT_ANY, "netdev_idx", " netdev %u", netdev_idx);
}
if(tb[RDMA_NLDEV_ATTR_NDEV_NAME]) {
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_NDEV_NAME]);
print_string(PRINT_ANY, "netdev_name", " %s", name);
}
}
static int mon_show_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX + 1] = {};
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
if (!tb[RDMA_NLDEV_ATTR_EVENT_TYPE])
return MNL_CB_ERROR;
open_json_object(NULL);
mon_print_event_type(tb);
mon_print_dev(tb);
mon_print_port_idx(tb);
mon_print_netdev(tb);
close_json_object();
newline();
fflush(stdout);
return MNL_CB_OK;
}
static int mon_show(struct rd* rd)
{
unsigned int groups = 0;
uint8_t is_sup = 0;
int one = 1;
char *buf;
int err;
err = mon_is_supported(rd, &is_sup);
if (err) {
pr_err("Failed to check if RDMA monitoring is supported\n");
return err;
}
if (!is_sup) {
pr_err("RDMA monitoring is not supported by the kernel\n");
return -ENOENT;
}
buf = malloc(MNL_SOCKET_BUFFER_SIZE);
if (!buf) {
pr_err("Buffer allocation failed\n");
return -ENOMEM;
}
rd->nl = mnl_socket_open(NETLINK_RDMA);
if (!rd->nl) {
pr_err("Failed to open NETLINK_RDMA socket. Error: %s\n",
strerror(errno));
err = -ENODEV;
goto err_free;
}
mnl_socket_setsockopt(rd->nl, NETLINK_CAP_ACK, &one, sizeof(one));
mnl_socket_setsockopt(rd->nl, NETLINK_EXT_ACK, &one, sizeof(one));
groups |= nl_mgrp(RDMA_NL_GROUP_NOTIFY);
err = mnl_add_nl_group(rd->nl, groups);
if (err < 0) {
pr_err("Failed to add NETLINK_RDMA multicast group. Error: %s\n",
strerror(errno));
goto err_close;
}
new_json_obj(json);
err = mnlu_socket_recv_run(rd->nl, 0, buf, MNL_SOCKET_BUFFER_SIZE,
mon_show_cb, rd);
if (err) {
pr_err("Failed to listen to rdma socket\n");
goto err_free_json;
}
return 0;
err_free_json:
delete_json_obj();
err_close:
mnl_socket_close(rd->nl);
err_free:
free(buf);
return err;
}
static int mon_help(struct rd *rd)
{
pr_out("Usage: rdma monitor [ -j ]\n");
return 0;
}
int cmd_mon(struct rd *rd)
{
const struct rd_cmd cmds[] = {
{ NULL, mon_show },
{ "help", mon_help },
{ 0 }
};
return rd_exec_cmd(rd, cmds, "mon command");
}
|