diff options
Diffstat (limited to 'rdma/dev.c')
-rw-r--r-- | rdma/dev.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/rdma/dev.c b/rdma/dev.c new file mode 100644 index 0000000..f495b71 --- /dev/null +++ b/rdma/dev.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* + * dev.c RDMA tool + * Authors: Leon Romanovsky <leonro@mellanox.com> + */ + +#include <fcntl.h> +#include "rdma.h" + +static int dev_help(struct rd *rd) +{ + pr_out("Usage: %s dev show [DEV]\n", rd->filename); + pr_out(" %s dev set [DEV] name DEVNAME\n", rd->filename); + pr_out(" %s dev set [DEV] netns NSNAME\n", rd->filename); + pr_out(" %s dev set [DEV] adaptive-moderation [on|off]\n", rd->filename); + return 0; +} + +static const char *dev_caps_to_str(uint32_t idx) +{ +#define RDMA_DEV_FLAGS_LOW(x) \ + x(RESIZE_MAX_WR, 0) \ + x(BAD_PKEY_CNTR, 1) \ + x(BAD_QKEY_CNTR, 2) \ + x(RAW_MULTI, 3) \ + x(AUTO_PATH_MIG, 4) \ + x(CHANGE_PHY_PORT, 5) \ + x(UD_AV_PORT_ENFORCE_PORT_ENFORCE, 6) \ + x(CURR_QP_STATE_MOD, 7) \ + x(SHUTDOWN_PORT, 8) \ + x(INIT_TYPE, 9) \ + x(PORT_ACTIVE_EVENT, 10) \ + x(SYS_IMAGE_GUID, 11) \ + x(RC_RNR_NAK_GEN, 12) \ + x(SRQ_RESIZE, 13) \ + x(N_NOTIFY_CQ, 14) \ + x(LOCAL_DMA_LKEY, 15) \ + x(MEM_WINDOW, 17) \ + x(UD_IP_CSUM, 18) \ + x(UD_TSO, 19) \ + x(XRC, 20) \ + x(MEM_MGT_EXTENSIONS, 21) \ + x(BLOCK_MULTICAST_LOOPBACK, 22) \ + x(MEM_WINDOW_TYPE_2A, 23) \ + x(MEM_WINDOW_TYPE_2B, 24) \ + x(RC_IP_CSUM, 25) \ + x(RAW_IP_CSUM, 26) \ + x(CROSS_CHANNEL, 27) \ + x(MANAGED_FLOW_STEERING, 29) \ + x(SIGNATURE_HANDOVER, 30) \ + x(ON_DEMAND_PAGING, 31) + +#define RDMA_DEV_FLAGS_HIGH(x) \ + x(SG_GAPS_REG, 0) \ + x(VIRTUAL_FUNCTION, 1) \ + x(RAW_SCATTER_FCS, 2) \ + x(RDMA_NETDEV_OPA_VNIC, 3) \ + x(PCI_WRITE_END_PADDING, 4) + + /* + * Separation below is needed to allow compilation of rdmatool + * on 32bits systems. On such systems, C-enum is limited to be + * int and can't hold more than 32 bits. + */ + enum { RDMA_DEV_FLAGS_LOW(RDMA_BITMAP_ENUM) }; + enum { RDMA_DEV_FLAGS_HIGH(RDMA_BITMAP_ENUM) }; + + static const char * const + rdma_dev_names_low[] = { RDMA_DEV_FLAGS_LOW(RDMA_BITMAP_NAMES) }; + static const char * const + rdma_dev_names_high[] = { RDMA_DEV_FLAGS_HIGH(RDMA_BITMAP_NAMES) }; + uint32_t high_idx; + #undef RDMA_DEV_FLAGS_LOW + #undef RDMA_DEV_FLAGS_HIGH + + if (idx < ARRAY_SIZE(rdma_dev_names_low) && rdma_dev_names_low[idx]) + return rdma_dev_names_low[idx]; + + high_idx = idx - ARRAY_SIZE(rdma_dev_names_low); + if (high_idx < ARRAY_SIZE(rdma_dev_names_high) && + rdma_dev_names_high[high_idx]) + return rdma_dev_names_high[high_idx]; + + return "UNKNOWN"; +} + +static void dev_print_caps(struct nlattr **tb) +{ + uint64_t caps; + uint32_t idx; + + if (!tb[RDMA_NLDEV_ATTR_CAP_FLAGS]) + return; + + caps = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_CAP_FLAGS]); + + print_string(PRINT_FP, NULL, "%s caps: <", _SL_); + open_json_array(PRINT_JSON, "caps"); + for (idx = 0; caps; idx++) { + if (caps & 0x1) + print_string(PRINT_ANY, NULL, + caps >> 0x1 ? "%s, " : "%s", + dev_caps_to_str(idx)); + caps >>= 0x1; + } + close_json_array(PRINT_ANY, ">"); +} + +static void dev_print_fw(struct nlattr **tb) +{ + const char *str; + + if (!tb[RDMA_NLDEV_ATTR_FW_VERSION]) + return; + + str = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_FW_VERSION]); + print_string(PRINT_ANY, "fw", "fw %s ", str); +} + +static void dev_print_node_guid(struct nlattr **tb) +{ + uint64_t node_guid; + uint16_t vp[4]; + char str[32]; + + if (!tb[RDMA_NLDEV_ATTR_NODE_GUID]) + return; + + node_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_NODE_GUID]); + memcpy(vp, &node_guid, sizeof(uint64_t)); + snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]); + print_string(PRINT_ANY, "node_guid", "node_guid %s ", + str); +} + +static void dev_print_sys_image_guid(struct nlattr **tb) +{ + uint64_t sys_image_guid; + uint16_t vp[4]; + char str[32]; + + if (!tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID]) + return; + + sys_image_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID]); + memcpy(vp, &sys_image_guid, sizeof(uint64_t)); + snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]); + print_string(PRINT_ANY, "sys_image_guid", "sys_image_guid %s ", str); +} + +static void dev_print_dim_setting(struct nlattr **tb) +{ + uint8_t dim_setting; + + if (!tb[RDMA_NLDEV_ATTR_DEV_DIM]) + return; + + dim_setting = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_DIM]); + if (dim_setting > 1) + return; + + print_on_off(PRINT_ANY, "adaptive-moderation", "adaptive-moderation %s ", dim_setting); + +} + +static const char *node_type_to_str(uint8_t node_type) +{ + static const char * const node_type_str[] = { "unknown", "ca", + "switch", "router", + "rnic", "usnic", + "usnic_udp", + "unspecified" }; + if (node_type < ARRAY_SIZE(node_type_str)) + return node_type_str[node_type]; + return "unknown"; +} + +static void dev_print_node_type(struct nlattr **tb) +{ + const char *node_str; + uint8_t node_type; + + if (!tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE]) + return; + + node_type = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE]); + node_str = node_type_to_str(node_type); + print_string(PRINT_ANY, "node_type", "node_type %s ", node_str); +} + +static void dev_print_dev_proto(struct nlattr **tb) +{ + const char *str; + + if (!tb[RDMA_NLDEV_ATTR_DEV_PROTOCOL]) + return; + + str = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_PROTOCOL]); + print_string(PRINT_ANY, "protocol", "protocol %s ", str); +} + +static int dev_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; + + open_json_object(NULL); + idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); + name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]); + print_uint(PRINT_ANY, "ifindex", "%u: ", idx); + print_string(PRINT_ANY, "ifname", "%s: ", name); + + dev_print_node_type(tb); + dev_print_dev_proto(tb); + dev_print_fw(tb); + dev_print_node_guid(tb); + dev_print_sys_image_guid(tb); + if (rd->show_details) { + dev_print_dim_setting(tb); + dev_print_caps(tb); + } + + close_json_object(); + newline(); + + return MNL_CB_OK; +} + +static int dev_no_args(struct rd *rd) +{ + uint32_t seq; + int ret; + + rd_prepare_msg(rd, RDMA_NLDEV_CMD_GET, + &seq, (NLM_F_REQUEST | NLM_F_ACK)); + mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); + ret = rd_send_msg(rd); + if (ret) + return ret; + + ret = rd_recv_msg(rd, dev_parse_cb, rd, seq); + return ret; +} + +static int dev_one_show(struct rd *rd) +{ + const struct rd_cmd cmds[] = { + { NULL, dev_no_args}, + { 0 } + }; + + return rd_exec_cmd(rd, cmds, "parameter"); +} + +static int dev_set_name(struct rd *rd) +{ + uint32_t seq; + + if (rd_no_arg(rd)) { + pr_err("Please provide device new name.\n"); + return -EINVAL; + } + + rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET, + &seq, (NLM_F_REQUEST | NLM_F_ACK)); + mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); + mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd_argv(rd)); + + return rd_sendrecv_msg(rd, seq); +} + +static int dev_set_netns(struct rd *rd) +{ + char *netns_path; + uint32_t seq; + int netns; + int ret; + + if (rd_no_arg(rd)) { + pr_err("Please provide device name.\n"); + return -EINVAL; + } + + if (asprintf(&netns_path, "%s/%s", NETNS_RUN_DIR, rd_argv(rd)) < 0) + return -ENOMEM; + + netns = open(netns_path, O_RDONLY | O_CLOEXEC); + if (netns < 0) { + fprintf(stderr, "Cannot open network namespace \"%s\": %s\n", + rd_argv(rd), strerror(errno)); + ret = -EINVAL; + goto done; + } + + rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET, + &seq, (NLM_F_REQUEST | NLM_F_ACK)); + mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); + mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_NET_NS_FD, netns); + ret = rd_sendrecv_msg(rd, seq); + close(netns); +done: + free(netns_path); + return ret; +} + +static int dev_set_dim_sendmsg(struct rd *rd, uint8_t dim_setting) +{ + uint32_t seq; + + rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET, &seq, + (NLM_F_REQUEST | NLM_F_ACK)); + mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); + mnl_attr_put_u8(rd->nlh, RDMA_NLDEV_ATTR_DEV_DIM, dim_setting); + + return rd_sendrecv_msg(rd, seq); +} + +static int dev_set_dim_off(struct rd *rd) +{ + return dev_set_dim_sendmsg(rd, 0); +} + +static int dev_set_dim_on(struct rd *rd) +{ + return dev_set_dim_sendmsg(rd, 1); +} + +static int dev_set_dim(struct rd *rd) +{ + const struct rd_cmd cmds[] = { + { NULL, dev_help}, + { "on", dev_set_dim_on}, + { "off", dev_set_dim_off}, + { 0 } + }; + + return rd_exec_cmd(rd, cmds, "parameter"); +} + +static int dev_one_set(struct rd *rd) +{ + const struct rd_cmd cmds[] = { + { NULL, dev_help}, + { "name", dev_set_name}, + { "netns", dev_set_netns}, + { "adaptive-moderation", dev_set_dim}, + { 0 } + }; + + return rd_exec_cmd(rd, cmds, "parameter"); +} + +static int dev_show(struct rd *rd) +{ + return rd_exec_dev(rd, dev_one_show); +} + +static int dev_set(struct rd *rd) +{ + return rd_exec_require_dev(rd, dev_one_set); +} + +int cmd_dev(struct rd *rd) +{ + const struct rd_cmd cmds[] = { + { NULL, dev_show }, + { "show", dev_show }, + { "list", dev_show }, + { "set", dev_set }, + { "help", dev_help }, + { 0 } + }; + + return rd_exec_cmd(rd, cmds, "dev command"); +} |