mirror of
				https://git.proxmox.com/git/mirror_iproute2
				synced 2025-10-31 06:51:16 +00:00 
			
		
		
		
	 7087f7c0ce
			
		
	
	
		7087f7c0ce
		
	
	
	
	
		
			
			Fix typo in usnic_udp node type and add a string for the unspecified node type. Signed-off-by: Gal Pressman <galpress@amazon.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
		
			
				
	
	
		
			309 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 | |
| /*
 | |
|  * dev.c	RDMA tool
 | |
|  * Authors:     Leon Romanovsky <leonro@mellanox.com>
 | |
|  */
 | |
| 
 | |
| #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);
 | |
| 	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 rd *rd, 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]);
 | |
| 
 | |
| 	if (rd->json_output) {
 | |
| 		jsonw_name(rd->jw, "caps");
 | |
| 		jsonw_start_array(rd->jw);
 | |
| 	} else {
 | |
| 		pr_out("\n    caps: <");
 | |
| 	}
 | |
| 	for (idx = 0; caps; idx++) {
 | |
| 		if (caps & 0x1) {
 | |
| 			if (rd->json_output) {
 | |
| 				jsonw_string(rd->jw, dev_caps_to_str(idx));
 | |
| 			} else {
 | |
| 				pr_out("%s", dev_caps_to_str(idx));
 | |
| 				if (caps >> 0x1)
 | |
| 					pr_out(", ");
 | |
| 			}
 | |
| 		}
 | |
| 		caps >>= 0x1;
 | |
| 	}
 | |
| 
 | |
| 	if (rd->json_output)
 | |
| 		jsonw_end_array(rd->jw);
 | |
| 	else
 | |
| 		pr_out(">");
 | |
| }
 | |
| 
 | |
| static void dev_print_fw(struct rd *rd, 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]);
 | |
| 	if (rd->json_output)
 | |
| 		jsonw_string_field(rd->jw, "fw", str);
 | |
| 	else
 | |
| 		pr_out("fw %s ", str);
 | |
| }
 | |
| 
 | |
| static void dev_print_node_guid(struct rd *rd, 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]);
 | |
| 	if (rd->json_output)
 | |
| 		jsonw_string_field(rd->jw, "node_guid", str);
 | |
| 	else
 | |
| 		pr_out("node_guid %s ", str);
 | |
| }
 | |
| 
 | |
| static void dev_print_sys_image_guid(struct rd *rd, 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]);
 | |
| 	if (rd->json_output)
 | |
| 		jsonw_string_field(rd->jw, "sys_image_guid", str);
 | |
| 	else
 | |
| 		pr_out("sys_image_guid %s ", str);
 | |
| }
 | |
| 
 | |
| 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 rd *rd, 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);
 | |
| 	if (rd->json_output)
 | |
| 		jsonw_string_field(rd->jw, "node_type", node_str);
 | |
| 	else
 | |
| 		pr_out("node_type %s ", node_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;
 | |
| 
 | |
| 	idx =  mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
 | |
| 	name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
 | |
| 	if (rd->json_output) {
 | |
| 		jsonw_uint_field(rd->jw, "ifindex", idx);
 | |
| 		jsonw_string_field(rd->jw, "ifname", name);
 | |
| 	} else {
 | |
| 		pr_out("%u: %s: ", idx, name);
 | |
| 	}
 | |
| 
 | |
| 	dev_print_node_type(rd, tb);
 | |
| 	dev_print_fw(rd, tb);
 | |
| 	dev_print_node_guid(rd, tb);
 | |
| 	dev_print_sys_image_guid(rd, tb);
 | |
| 	if (rd->show_details)
 | |
| 		dev_print_caps(rd, tb);
 | |
| 
 | |
| 	if (!rd->json_output)
 | |
| 		pr_out("\n");
 | |
| 	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;
 | |
| 
 | |
| 	if (rd->json_output)
 | |
| 		jsonw_start_object(rd->jw);
 | |
| 	ret = rd_recv_msg(rd, dev_parse_cb, rd, seq);
 | |
| 	if (rd->json_output)
 | |
| 		jsonw_end_object(rd->jw);
 | |
| 	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_one_set(struct rd *rd)
 | |
| {
 | |
| 	const struct rd_cmd cmds[] = {
 | |
| 		{ NULL,		dev_help},
 | |
| 		{ "name",	dev_set_name},
 | |
| 		{ 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");
 | |
| }
 |