summaryrefslogtreecommitdiffstats
path: root/rdma/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'rdma/dev.c')
-rw-r--r--rdma/dev.c381
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");
+}