1 /*
2 * dev.c RDMA tool
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Leon Romanovsky <leonro@mellanox.com>
10 */
11
12 #include "rdma.h"
13
dev_help(struct rd * rd)14 static int dev_help(struct rd *rd)
15 {
16 pr_out("Usage: %s dev show [DEV]\n", rd->filename);
17 return 0;
18 }
19
dev_caps_to_str(uint32_t idx)20 static const char *dev_caps_to_str(uint32_t idx)
21 {
22 #define RDMA_DEV_FLAGS(x) \
23 x(RESIZE_MAX_WR, 0) \
24 x(BAD_PKEY_CNTR, 1) \
25 x(BAD_QKEY_CNTR, 2) \
26 x(RAW_MULTI, 3) \
27 x(AUTO_PATH_MIG, 4) \
28 x(CHANGE_PHY_PORT, 5) \
29 x(UD_AV_PORT_ENFORCE_PORT_ENFORCE, 6) \
30 x(CURR_QP_STATE_MOD, 7) \
31 x(SHUTDOWN_PORT, 8) \
32 x(INIT_TYPE, 9) \
33 x(PORT_ACTIVE_EVENT, 10) \
34 x(SYS_IMAGE_GUID, 11) \
35 x(RC_RNR_NAK_GEN, 12) \
36 x(SRQ_RESIZE, 13) \
37 x(N_NOTIFY_CQ, 14) \
38 x(LOCAL_DMA_LKEY, 15) \
39 x(MEM_WINDOW, 17) \
40 x(UD_IP_CSUM, 18) \
41 x(UD_TSO, 19) \
42 x(XRC, 20) \
43 x(MEM_MGT_EXTENSIONS, 21) \
44 x(BLOCK_MULTICAST_LOOPBACK, 22) \
45 x(MEM_WINDOW_TYPE_2A, 23) \
46 x(MEM_WINDOW_TYPE_2B, 24) \
47 x(RC_IP_CSUM, 25) \
48 x(RAW_IP_CSUM, 26) \
49 x(CROSS_CHANNEL, 27) \
50 x(MANAGED_FLOW_STEERING, 29) \
51 x(SIGNATURE_HANDOVER, 30) \
52 x(ON_DEMAND_PAGING, 31) \
53 x(SG_GAPS_REG, 32) \
54 x(VIRTUAL_FUNCTION, 33) \
55 x(RAW_SCATTER_FCS, 34) \
56 x(RDMA_NETDEV_OPA_VNIC, 35)
57
58 enum { RDMA_DEV_FLAGS(RDMA_BITMAP_ENUM) };
59
60 static const char * const
61 rdma_dev_names[] = { RDMA_DEV_FLAGS(RDMA_BITMAP_NAMES) };
62 #undef RDMA_DEV_FLAGS
63
64 if (idx < ARRAY_SIZE(rdma_dev_names) && rdma_dev_names[idx])
65 return rdma_dev_names[idx];
66 return "UNKNOWN";
67 }
68
dev_print_caps(struct rd * rd,struct nlattr ** tb)69 static void dev_print_caps(struct rd *rd, struct nlattr **tb)
70 {
71 uint64_t caps;
72 uint32_t idx;
73
74 if (!tb[RDMA_NLDEV_ATTR_CAP_FLAGS])
75 return;
76
77 caps = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_CAP_FLAGS]);
78
79 if (rd->json_output) {
80 jsonw_name(rd->jw, "caps");
81 jsonw_start_array(rd->jw);
82 } else {
83 pr_out("\n caps: <");
84 }
85 for (idx = 0; caps; idx++) {
86 if (caps & 0x1) {
87 if (rd->json_output) {
88 jsonw_string(rd->jw, dev_caps_to_str(idx));
89 } else {
90 pr_out("%s", dev_caps_to_str(idx));
91 if (caps >> 0x1)
92 pr_out(", ");
93 }
94 }
95 caps >>= 0x1;
96 }
97
98 if (rd->json_output)
99 jsonw_end_array(rd->jw);
100 else
101 pr_out(">");
102 }
103
dev_print_fw(struct rd * rd,struct nlattr ** tb)104 static void dev_print_fw(struct rd *rd, struct nlattr **tb)
105 {
106 const char *str;
107 if (!tb[RDMA_NLDEV_ATTR_FW_VERSION])
108 return;
109
110 str = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_FW_VERSION]);
111 if (rd->json_output)
112 jsonw_string_field(rd->jw, "fw", str);
113 else
114 pr_out("fw %s ", str);
115 }
116
dev_print_node_guid(struct rd * rd,struct nlattr ** tb)117 static void dev_print_node_guid(struct rd *rd, struct nlattr **tb)
118 {
119 uint64_t node_guid;
120 uint16_t vp[4];
121 char str[32];
122
123 if (!tb[RDMA_NLDEV_ATTR_NODE_GUID])
124 return;
125
126 node_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_NODE_GUID]);
127 memcpy(vp, &node_guid, sizeof(uint64_t));
128 snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
129 if (rd->json_output)
130 jsonw_string_field(rd->jw, "node_guid", str);
131 else
132 pr_out("node_guid %s ", str);
133 }
134
dev_print_sys_image_guid(struct rd * rd,struct nlattr ** tb)135 static void dev_print_sys_image_guid(struct rd *rd, struct nlattr **tb)
136 {
137 uint64_t sys_image_guid;
138 uint16_t vp[4];
139 char str[32];
140
141 if (!tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID])
142 return;
143
144 sys_image_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID]);
145 memcpy(vp, &sys_image_guid, sizeof(uint64_t));
146 snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
147 if (rd->json_output)
148 jsonw_string_field(rd->jw, "sys_image_guid", str);
149 else
150 pr_out("sys_image_guid %s ", str);
151 }
152
node_type_to_str(uint8_t node_type)153 static const char *node_type_to_str(uint8_t node_type)
154 {
155 static const char * const node_type_str[] = { "unknown", "ca",
156 "switch", "router",
157 "rnic", "usnic",
158 "usnic_dp" };
159 if (node_type < ARRAY_SIZE(node_type_str))
160 return node_type_str[node_type];
161 return "unknown";
162 }
163
dev_print_node_type(struct rd * rd,struct nlattr ** tb)164 static void dev_print_node_type(struct rd *rd, struct nlattr **tb)
165 {
166 const char *node_str;
167 uint8_t node_type;
168
169 if (!tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE])
170 return;
171
172 node_type = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE]);
173 node_str = node_type_to_str(node_type);
174 if (rd->json_output)
175 jsonw_string_field(rd->jw, "node_type", node_str);
176 else
177 pr_out("node_type %s ", node_str);
178 }
179
dev_parse_cb(const struct nlmsghdr * nlh,void * data)180 static int dev_parse_cb(const struct nlmsghdr *nlh, void *data)
181 {
182 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
183 struct rd *rd = data;
184 const char *name;
185 uint32_t idx;
186
187 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
188 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
189 return MNL_CB_ERROR;
190
191 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
192 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
193 if (rd->json_output) {
194 jsonw_uint_field(rd->jw, "ifindex", idx);
195 jsonw_string_field(rd->jw, "ifname", name);
196 } else {
197 pr_out("%u: %s: ", idx, name);
198 }
199
200 dev_print_node_type(rd, tb);
201 dev_print_fw(rd, tb);
202 dev_print_node_guid(rd, tb);
203 dev_print_sys_image_guid(rd, tb);
204 if (rd->show_details)
205 dev_print_caps(rd, tb);
206
207 if (!rd->json_output)
208 pr_out("\n");
209 return MNL_CB_OK;
210 }
211
dev_no_args(struct rd * rd)212 static int dev_no_args(struct rd *rd)
213 {
214 uint32_t seq;
215 int ret;
216
217 rd_prepare_msg(rd, RDMA_NLDEV_CMD_GET,
218 &seq, (NLM_F_REQUEST | NLM_F_ACK));
219 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
220 ret = rd_send_msg(rd);
221 if (ret)
222 return ret;
223
224 if (rd->json_output)
225 jsonw_start_object(rd->jw);
226 ret = rd_recv_msg(rd, dev_parse_cb, rd, seq);
227 if (rd->json_output)
228 jsonw_end_object(rd->jw);
229 return ret;
230 }
231
dev_one_show(struct rd * rd)232 static int dev_one_show(struct rd *rd)
233 {
234 const struct rd_cmd cmds[] = {
235 { NULL, dev_no_args},
236 { 0 }
237 };
238
239 return rd_exec_cmd(rd, cmds, "parameter");
240 }
241
dev_show(struct rd * rd)242 static int dev_show(struct rd *rd)
243 {
244 struct dev_map *dev_map;
245 int ret = 0;
246
247 if (rd->json_output)
248 jsonw_start_array(rd->jw);
249 if (rd_no_arg(rd)) {
250 list_for_each_entry(dev_map, &rd->dev_map_list, list) {
251 rd->dev_idx = dev_map->idx;
252 ret = dev_one_show(rd);
253 if (ret)
254 goto out;
255 }
256 } else {
257 dev_map = dev_map_lookup(rd, false);
258 if (!dev_map) {
259 pr_err("Wrong device name\n");
260 ret = -ENOENT;
261 goto out;
262 }
263 rd_arg_inc(rd);
264 rd->dev_idx = dev_map->idx;
265 ret = dev_one_show(rd);
266 }
267 out:
268 if (rd->json_output)
269 jsonw_end_array(rd->jw);
270 return ret;
271 }
272
cmd_dev(struct rd * rd)273 int cmd_dev(struct rd *rd)
274 {
275 const struct rd_cmd cmds[] = {
276 { NULL, dev_show },
277 { "show", dev_show },
278 { "list", dev_show },
279 { "help", dev_help },
280 { 0 }
281 };
282
283 return rd_exec_cmd(rd, cmds, "dev command");
284 }
285