1
2
3
4
5
6
7#include <fcntl.h>
8#include "rdma.h"
9
10static int dev_help(struct rd *rd)
11{
12 pr_out("Usage: %s dev show [DEV]\n", rd->filename);
13 pr_out(" %s dev set [DEV] name DEVNAME\n", rd->filename);
14 pr_out(" %s dev set [DEV] netns NSNAME\n", rd->filename);
15 pr_out(" %s dev set [DEV] adaptive-moderation [on|off]\n", rd->filename);
16 return 0;
17}
18
19static const char *dev_caps_to_str(uint32_t idx)
20{
21#define RDMA_DEV_FLAGS_LOW(x) \
22 x(RESIZE_MAX_WR, 0) \
23 x(BAD_PKEY_CNTR, 1) \
24 x(BAD_QKEY_CNTR, 2) \
25 x(RAW_MULTI, 3) \
26 x(AUTO_PATH_MIG, 4) \
27 x(CHANGE_PHY_PORT, 5) \
28 x(UD_AV_PORT_ENFORCE_PORT_ENFORCE, 6) \
29 x(CURR_QP_STATE_MOD, 7) \
30 x(SHUTDOWN_PORT, 8) \
31 x(INIT_TYPE, 9) \
32 x(PORT_ACTIVE_EVENT, 10) \
33 x(SYS_IMAGE_GUID, 11) \
34 x(RC_RNR_NAK_GEN, 12) \
35 x(SRQ_RESIZE, 13) \
36 x(N_NOTIFY_CQ, 14) \
37 x(LOCAL_DMA_LKEY, 15) \
38 x(MEM_WINDOW, 17) \
39 x(UD_IP_CSUM, 18) \
40 x(UD_TSO, 19) \
41 x(XRC, 20) \
42 x(MEM_MGT_EXTENSIONS, 21) \
43 x(BLOCK_MULTICAST_LOOPBACK, 22) \
44 x(MEM_WINDOW_TYPE_2A, 23) \
45 x(MEM_WINDOW_TYPE_2B, 24) \
46 x(RC_IP_CSUM, 25) \
47 x(RAW_IP_CSUM, 26) \
48 x(CROSS_CHANNEL, 27) \
49 x(MANAGED_FLOW_STEERING, 29) \
50 x(SIGNATURE_HANDOVER, 30) \
51 x(ON_DEMAND_PAGING, 31)
52
53#define RDMA_DEV_FLAGS_HIGH(x) \
54 x(SG_GAPS_REG, 0) \
55 x(VIRTUAL_FUNCTION, 1) \
56 x(RAW_SCATTER_FCS, 2) \
57 x(RDMA_NETDEV_OPA_VNIC, 3) \
58 x(PCI_WRITE_END_PADDING, 4)
59
60
61
62
63
64
65 enum { RDMA_DEV_FLAGS_LOW(RDMA_BITMAP_ENUM) };
66 enum { RDMA_DEV_FLAGS_HIGH(RDMA_BITMAP_ENUM) };
67
68 static const char * const
69 rdma_dev_names_low[] = { RDMA_DEV_FLAGS_LOW(RDMA_BITMAP_NAMES) };
70 static const char * const
71 rdma_dev_names_high[] = { RDMA_DEV_FLAGS_HIGH(RDMA_BITMAP_NAMES) };
72 uint32_t high_idx;
73 #undef RDMA_DEV_FLAGS_LOW
74 #undef RDMA_DEV_FLAGS_HIGH
75
76 if (idx < ARRAY_SIZE(rdma_dev_names_low) && rdma_dev_names_low[idx])
77 return rdma_dev_names_low[idx];
78
79 high_idx = idx - ARRAY_SIZE(rdma_dev_names_low);
80 if (high_idx < ARRAY_SIZE(rdma_dev_names_high) &&
81 rdma_dev_names_high[high_idx])
82 return rdma_dev_names_high[high_idx];
83
84 return "UNKNOWN";
85}
86
87static void dev_print_caps(struct rd *rd, struct nlattr **tb)
88{
89 uint64_t caps;
90 uint32_t idx;
91
92 if (!tb[RDMA_NLDEV_ATTR_CAP_FLAGS])
93 return;
94
95 caps = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_CAP_FLAGS]);
96
97 print_color_string(PRINT_FP, COLOR_NONE, NULL, "\n caps: <", NULL);
98 open_json_array(PRINT_JSON, "caps");
99 for (idx = 0; caps; idx++) {
100 if (caps & 0x1)
101 print_color_string(PRINT_ANY, COLOR_NONE, NULL,
102 caps >> 0x1 ? "%s, " : "%s",
103 dev_caps_to_str(idx));
104 caps >>= 0x1;
105 }
106 close_json_array(PRINT_ANY, ">");
107}
108
109static void dev_print_fw(struct rd *rd, struct nlattr **tb)
110{
111 const char *str;
112 if (!tb[RDMA_NLDEV_ATTR_FW_VERSION])
113 return;
114
115 str = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_FW_VERSION]);
116 print_color_string(PRINT_ANY, COLOR_NONE, "fw", "fw %s ", str);
117}
118
119static void dev_print_node_guid(struct rd *rd, struct nlattr **tb)
120{
121 uint64_t node_guid;
122 uint16_t vp[4];
123 char str[32];
124
125 if (!tb[RDMA_NLDEV_ATTR_NODE_GUID])
126 return;
127
128 node_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_NODE_GUID]);
129 memcpy(vp, &node_guid, sizeof(uint64_t));
130 snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
131 print_color_string(PRINT_ANY, COLOR_NONE, "node_guid", "node_guid %s ",
132 str);
133}
134
135static 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 print_color_string(PRINT_ANY, COLOR_NONE, "sys_image_guid",
148 "sys_image_guid %s ", str);
149}
150
151static void dev_print_dim_setting(struct rd *rd, struct nlattr **tb)
152{
153 uint8_t dim_setting;
154
155 if (!tb[RDMA_NLDEV_ATTR_DEV_DIM])
156 return;
157
158 dim_setting = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_DIM]);
159 if (dim_setting > 1)
160 return;
161
162 print_on_off(PRINT_ANY, "adaptive-moderation", "adaptive-moderation %s ", dim_setting);
163
164}
165
166static const char *node_type_to_str(uint8_t node_type)
167{
168 static const char * const node_type_str[] = { "unknown", "ca",
169 "switch", "router",
170 "rnic", "usnic",
171 "usnic_udp",
172 "unspecified" };
173 if (node_type < ARRAY_SIZE(node_type_str))
174 return node_type_str[node_type];
175 return "unknown";
176}
177
178static void dev_print_node_type(struct rd *rd, struct nlattr **tb)
179{
180 const char *node_str;
181 uint8_t node_type;
182
183 if (!tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE])
184 return;
185
186 node_type = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE]);
187 node_str = node_type_to_str(node_type);
188 print_color_string(PRINT_ANY, COLOR_NONE, "node_type", "node_type %s ",
189 node_str);
190}
191
192static int dev_parse_cb(const struct nlmsghdr *nlh, void *data)
193{
194 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
195 struct rd *rd = data;
196 const char *name;
197 uint32_t idx;
198
199 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
200 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
201 return MNL_CB_ERROR;
202 open_json_object(NULL);
203 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
204 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
205 print_color_uint(PRINT_ANY, COLOR_NONE, "ifindex", "%u: ", idx);
206 print_color_string(PRINT_ANY, COLOR_NONE, "ifname", "%s: ", name);
207
208 dev_print_node_type(rd, tb);
209 dev_print_fw(rd, tb);
210 dev_print_node_guid(rd, tb);
211 dev_print_sys_image_guid(rd, tb);
212 if (rd->show_details) {
213 dev_print_dim_setting(rd, tb);
214 dev_print_caps(rd, tb);
215 }
216
217 newline(rd);
218 return MNL_CB_OK;
219}
220
221static int dev_no_args(struct rd *rd)
222{
223 uint32_t seq;
224 int ret;
225
226 rd_prepare_msg(rd, RDMA_NLDEV_CMD_GET,
227 &seq, (NLM_F_REQUEST | NLM_F_ACK));
228 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
229 ret = rd_send_msg(rd);
230 if (ret)
231 return ret;
232
233 ret = rd_recv_msg(rd, dev_parse_cb, rd, seq);
234 return ret;
235}
236
237static int dev_one_show(struct rd *rd)
238{
239 const struct rd_cmd cmds[] = {
240 { NULL, dev_no_args},
241 { 0 }
242 };
243
244 return rd_exec_cmd(rd, cmds, "parameter");
245}
246
247static int dev_set_name(struct rd *rd)
248{
249 uint32_t seq;
250
251 if (rd_no_arg(rd)) {
252 pr_err("Please provide device new name.\n");
253 return -EINVAL;
254 }
255
256 rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET,
257 &seq, (NLM_F_REQUEST | NLM_F_ACK));
258 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
259 mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd_argv(rd));
260
261 return rd_sendrecv_msg(rd, seq);
262}
263
264static int dev_set_netns(struct rd *rd)
265{
266 char *netns_path;
267 uint32_t seq;
268 int netns;
269 int ret;
270
271 if (rd_no_arg(rd)) {
272 pr_err("Please provide device name.\n");
273 return -EINVAL;
274 }
275
276 if (asprintf(&netns_path, "%s/%s", NETNS_RUN_DIR, rd_argv(rd)) < 0)
277 return -ENOMEM;
278
279 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
280 if (netns < 0) {
281 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
282 rd_argv(rd), strerror(errno));
283 ret = -EINVAL;
284 goto done;
285 }
286
287 rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET,
288 &seq, (NLM_F_REQUEST | NLM_F_ACK));
289 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
290 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_NET_NS_FD, netns);
291 ret = rd_sendrecv_msg(rd, seq);
292 close(netns);
293done:
294 free(netns_path);
295 return ret;
296}
297
298static int dev_set_dim_sendmsg(struct rd *rd, uint8_t dim_setting)
299{
300 uint32_t seq;
301
302 rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET, &seq,
303 (NLM_F_REQUEST | NLM_F_ACK));
304 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
305 mnl_attr_put_u8(rd->nlh, RDMA_NLDEV_ATTR_DEV_DIM, dim_setting);
306
307 return rd_sendrecv_msg(rd, seq);
308}
309
310static int dev_set_dim_off(struct rd *rd)
311{
312 return dev_set_dim_sendmsg(rd, 0);
313}
314
315static int dev_set_dim_on(struct rd *rd)
316{
317 return dev_set_dim_sendmsg(rd, 1);
318}
319
320static int dev_set_dim(struct rd *rd)
321{
322 const struct rd_cmd cmds[] = {
323 { NULL, dev_help},
324 { "on", dev_set_dim_on},
325 { "off", dev_set_dim_off},
326 { 0 }
327 };
328
329 return rd_exec_cmd(rd, cmds, "parameter");
330}
331
332static int dev_one_set(struct rd *rd)
333{
334 const struct rd_cmd cmds[] = {
335 { NULL, dev_help},
336 { "name", dev_set_name},
337 { "netns", dev_set_netns},
338 { "adaptive-moderation", dev_set_dim},
339 { 0 }
340 };
341
342 return rd_exec_cmd(rd, cmds, "parameter");
343}
344
345static int dev_show(struct rd *rd)
346{
347 return rd_exec_dev(rd, dev_one_show);
348}
349
350static int dev_set(struct rd *rd)
351{
352 return rd_exec_require_dev(rd, dev_one_set);
353}
354
355int cmd_dev(struct rd *rd)
356{
357 const struct rd_cmd cmds[] = {
358 { NULL, dev_show },
359 { "show", dev_show },
360 { "list", dev_show },
361 { "set", dev_set },
362 { "help", dev_help },
363 { 0 }
364 };
365
366 return rd_exec_cmd(rd, cmds, "dev command");
367}
368