]> git.proxmox.com Git - mirror_iproute2.git/blob - rdma/res.c
rdma: Don't pass garbage to rd_check_is_filtered()
[mirror_iproute2.git] / rdma / res.c
1 /*
2 * res.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 #include <inttypes.h>
14
15 static int res_help(struct rd *rd)
16 {
17 pr_out("Usage: %s resource\n", rd->filename);
18 pr_out(" resource show [DEV]\n");
19 pr_out(" resource show [qp|cm_id]\n");
20 pr_out(" resource show qp link [DEV/PORT]\n");
21 pr_out(" resource show qp link [DEV/PORT] [FILTER-NAME FILTER-VALUE]\n");
22 pr_out(" resource show cm_id link [DEV/PORT]\n");
23 pr_out(" resource show cm_id link [DEV/PORT] [FILTER-NAME FILTER-VALUE]\n");
24 pr_out(" resource show cq link [DEV/PORT]\n");
25 pr_out(" resource show cq link [DEV/PORT] [FILTER-NAME FILTER-VALUE]\n");
26 return 0;
27 }
28
29 static int res_print_summary(struct rd *rd, struct nlattr **tb)
30 {
31 struct nlattr *nla_table = tb[RDMA_NLDEV_ATTR_RES_SUMMARY];
32 struct nlattr *nla_entry;
33 const char *name;
34 uint64_t curr;
35 int err;
36
37 mnl_attr_for_each_nested(nla_entry, nla_table) {
38 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
39 char json_name[32];
40
41 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
42 if (err != MNL_CB_OK)
43 return -EINVAL;
44
45 if (!nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] ||
46 !nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]) {
47 return -EINVAL;
48 }
49
50 name = mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]);
51 curr = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
52 if (rd->json_output) {
53 snprintf(json_name, 32, "%s", name);
54 jsonw_lluint_field(rd->jw, json_name, curr);
55 } else {
56 pr_out("%s %"PRId64 " ", name, curr);
57 }
58 }
59 return 0;
60 }
61
62 static int res_no_args_parse_cb(const struct nlmsghdr *nlh, void *data)
63 {
64 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
65 struct rd *rd = data;
66 const char *name;
67 uint32_t idx;
68
69 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
70 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
71 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
72 !tb[RDMA_NLDEV_ATTR_RES_SUMMARY])
73 return MNL_CB_ERROR;
74
75 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
76 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
77 if (rd->json_output) {
78 jsonw_uint_field(rd->jw, "ifindex", idx);
79 jsonw_string_field(rd->jw, "ifname", name);
80 } else {
81 pr_out("%u: %s: ", idx, name);
82 }
83
84 res_print_summary(rd, tb);
85
86 if (!rd->json_output)
87 pr_out("\n");
88 return MNL_CB_OK;
89 }
90
91 static int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback)
92 {
93 uint32_t flags = NLM_F_REQUEST | NLM_F_ACK;
94 uint32_t seq;
95 int ret;
96
97 if (command != RDMA_NLDEV_CMD_RES_GET)
98 flags |= NLM_F_DUMP;
99
100 rd_prepare_msg(rd, command, &seq, flags);
101 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
102 if (rd->port_idx)
103 mnl_attr_put_u32(rd->nlh,
104 RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
105
106 ret = rd_send_msg(rd);
107 if (ret)
108 return ret;
109
110 if (rd->json_output)
111 jsonw_start_object(rd->jw);
112 ret = rd_recv_msg(rd, callback, rd, seq);
113 if (rd->json_output)
114 jsonw_end_object(rd->jw);
115 return ret;
116 }
117
118 #define RES_FUNC(name, command, valid_filters, strict_port) \
119 static int _##name(struct rd *rd)\
120 { \
121 return _res_send_msg(rd, command, name##_parse_cb); \
122 } \
123 static int name(struct rd *rd) \
124 {\
125 int ret = rd_build_filter(rd, valid_filters); \
126 if (ret) \
127 return ret; \
128 if ((uintptr_t)valid_filters != (uintptr_t)NULL) { \
129 ret = rd_set_arg_to_devname(rd); \
130 if (ret) \
131 return ret;\
132 } \
133 if (strict_port) \
134 return rd_exec_dev(rd, _##name); \
135 else \
136 return rd_exec_link(rd, _##name, strict_port); \
137 }
138
139 static const char *path_mig_to_str(uint8_t idx)
140 {
141 static const char * const path_mig_str[] = { "MIGRATED",
142 "REARM", "ARMED" };
143
144 if (idx < ARRAY_SIZE(path_mig_str))
145 return path_mig_str[idx];
146 return "UNKNOWN";
147 }
148
149 static const char *qp_states_to_str(uint8_t idx)
150 {
151 static const char * const qp_states_str[] = { "RESET", "INIT",
152 "RTR", "RTS", "SQD",
153 "SQE", "ERR" };
154
155 if (idx < ARRAY_SIZE(qp_states_str))
156 return qp_states_str[idx];
157 return "UNKNOWN";
158 }
159
160 static const char *qp_types_to_str(uint8_t idx)
161 {
162 static const char * const qp_types_str[] = { "SMI", "GSI", "RC",
163 "UC", "UD", "RAW_IPV6",
164 "RAW_ETHERTYPE",
165 "UNKNOWN", "RAW_PACKET",
166 "XRC_INI", "XRC_TGT" };
167
168 if (idx < ARRAY_SIZE(qp_types_str))
169 return qp_types_str[idx];
170 return "UNKNOWN";
171 }
172
173 static void print_lqpn(struct rd *rd, uint32_t val)
174 {
175 if (rd->json_output)
176 jsonw_uint_field(rd->jw, "lqpn", val);
177 else
178 pr_out("lqpn %u ", val);
179 }
180
181 static void print_rqpn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
182 {
183 if (!nla_line[RDMA_NLDEV_ATTR_RES_RQPN])
184 return;
185
186 if (rd->json_output)
187 jsonw_uint_field(rd->jw, "rqpn", val);
188 else
189 pr_out("rqpn %u ", val);
190 }
191
192 static void print_type(struct rd *rd, uint32_t val)
193 {
194 if (rd->json_output)
195 jsonw_string_field(rd->jw, "type",
196 qp_types_to_str(val));
197 else
198 pr_out("type %s ", qp_types_to_str(val));
199 }
200
201 static void print_state(struct rd *rd, uint32_t val)
202 {
203 if (rd->json_output)
204 jsonw_string_field(rd->jw, "state",
205 qp_states_to_str(val));
206 else
207 pr_out("state %s ", qp_states_to_str(val));
208 }
209
210 static void print_rqpsn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
211 {
212 if (!nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN])
213 return;
214
215 if (rd->json_output)
216 jsonw_uint_field(rd->jw, "rq-psn", val);
217 else
218 pr_out("rq-psn %u ", val);
219 }
220
221 static void print_sqpsn(struct rd *rd, uint32_t val)
222 {
223 if (rd->json_output)
224 jsonw_uint_field(rd->jw, "sq-psn", val);
225 else
226 pr_out("sq-psn %u ", val);
227 }
228
229 static void print_pathmig(struct rd *rd, uint32_t val,
230 struct nlattr **nla_line)
231 {
232 if (!nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE])
233 return;
234
235 if (rd->json_output)
236 jsonw_string_field(rd->jw,
237 "path-mig-state",
238 path_mig_to_str(val));
239 else
240 pr_out("path-mig-state %s ", path_mig_to_str(val));
241 }
242
243 static void print_pid(struct rd *rd, uint32_t val)
244 {
245 if (rd->json_output)
246 jsonw_uint_field(rd->jw, "pid", val);
247 else
248 pr_out("pid %u ", val);
249 }
250
251 static void print_comm(struct rd *rd, const char *str,
252 struct nlattr **nla_line)
253 {
254 char tmp[18];
255
256 if (rd->json_output) {
257 /* Don't beatify output in JSON format */
258 jsonw_string_field(rd->jw, "comm", str);
259 return;
260 }
261
262 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
263 snprintf(tmp, sizeof(tmp), "%s", str);
264 else
265 snprintf(tmp, sizeof(tmp), "[%s]", str);
266
267 pr_out("comm %s ", tmp);
268 }
269
270 static void print_dev(struct rd *rd, uint32_t idx, const char *name)
271 {
272 if (rd->json_output) {
273 jsonw_uint_field(rd->jw, "ifindex", idx);
274 jsonw_string_field(rd->jw, "ifname", name);
275 } else {
276 pr_out("dev %s ", name);
277 }
278 }
279
280 static void print_link(struct rd *rd, uint32_t idx, const char *name,
281 uint32_t port, struct nlattr **nla_line)
282 {
283 if (rd->json_output) {
284 jsonw_uint_field(rd->jw, "ifindex", idx);
285
286 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
287 jsonw_uint_field(rd->jw, "port", port);
288
289 jsonw_string_field(rd->jw, "ifname", name);
290 } else {
291 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
292 pr_out("link %s/%u ", name, port);
293 else
294 pr_out("link %s/- ", name);
295 }
296 }
297
298 static char *get_task_name(uint32_t pid)
299 {
300 char *comm;
301 FILE *f;
302
303 if (asprintf(&comm, "/proc/%d/comm", pid) < 0)
304 return NULL;
305
306 f = fopen(comm, "r");
307 free(comm);
308 if (!f)
309 return NULL;
310
311 if (fscanf(f, "%ms\n", &comm) != 1)
312 comm = NULL;
313
314 fclose(f);
315
316 return comm;
317 }
318
319 static int res_qp_parse_cb(const struct nlmsghdr *nlh, void *data)
320 {
321 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
322 struct nlattr *nla_table, *nla_entry;
323 struct rd *rd = data;
324 const char *name;
325 uint32_t idx;
326
327 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
328 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
329 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
330 !tb[RDMA_NLDEV_ATTR_RES_QP])
331 return MNL_CB_ERROR;
332
333 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
334 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
335 nla_table = tb[RDMA_NLDEV_ATTR_RES_QP];
336
337 mnl_attr_for_each_nested(nla_entry, nla_table) {
338 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
339 uint32_t lqpn, rqpn = 0, rq_psn = 0, sq_psn;
340 uint8_t type, state, path_mig_state = 0;
341 uint32_t port = 0, pid = 0;
342 char *comm = NULL;
343 int err;
344
345 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
346 if (err != MNL_CB_OK)
347 return MNL_CB_ERROR;
348
349 if (!nla_line[RDMA_NLDEV_ATTR_RES_LQPN] ||
350 !nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN] ||
351 !nla_line[RDMA_NLDEV_ATTR_RES_TYPE] ||
352 !nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
353 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
354 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
355 return MNL_CB_ERROR;
356 }
357
358 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
359 port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
360
361 if (port != rd->port_idx)
362 continue;
363
364 lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
365 if (rd_check_is_filtered(rd, "lqpn", lqpn))
366 continue;
367
368 if (nla_line[RDMA_NLDEV_ATTR_RES_RQPN]) {
369 rqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQPN]);
370 if (rd_check_is_filtered(rd, "rqpn", rqpn))
371 continue;
372 } else {
373 if (rd_check_is_key_exist(rd, "rqpn"))
374 continue;
375 }
376
377 if (nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]) {
378 rq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]);
379 if (rd_check_is_filtered(rd, "rq-psn", rq_psn))
380 continue;
381 } else {
382 if (rd_check_is_key_exist(rd, "rq-psn"))
383 continue;
384 }
385
386 sq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]);
387 if (rd_check_is_filtered(rd, "sq-psn", sq_psn))
388 continue;
389
390 if (nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]) {
391 path_mig_state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]);
392 if (rd_check_is_string_filtered(rd, "path-mig-state", path_mig_to_str(path_mig_state)))
393 continue;
394 } else {
395 if (rd_check_is_key_exist(rd, "path-mig-state"))
396 continue;
397 }
398
399 type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
400 if (rd_check_is_string_filtered(rd, "type", qp_types_to_str(type)))
401 continue;
402
403 state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
404 if (rd_check_is_string_filtered(rd, "state", qp_states_to_str(state)))
405 continue;
406
407 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
408 pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
409 comm = get_task_name(pid);
410 }
411
412 if (rd_check_is_filtered(rd, "pid", pid)) {
413 free(comm);
414 continue;
415 }
416
417 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
418 /* discard const from mnl_attr_get_str */
419 comm = (char *)mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
420
421 if (rd->json_output)
422 jsonw_start_array(rd->jw);
423
424 print_link(rd, idx, name, port, nla_line);
425
426 print_lqpn(rd, lqpn);
427 print_rqpn(rd, rqpn, nla_line);
428
429 print_type(rd, type);
430 print_state(rd, state);
431
432 print_rqpsn(rd, rq_psn, nla_line);
433 print_sqpsn(rd, sq_psn);
434
435 print_pathmig(rd, path_mig_state, nla_line);
436 print_pid(rd, pid);
437 print_comm(rd, comm, nla_line);
438
439 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
440 free(comm);
441
442 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
443 newline(rd);
444 }
445 return MNL_CB_OK;
446 }
447
448 static void print_qp_type(struct rd *rd, uint32_t val)
449 {
450 if (rd->json_output)
451 jsonw_string_field(rd->jw, "qp-type",
452 qp_types_to_str(val));
453 else
454 pr_out("qp-type %s ", qp_types_to_str(val));
455 }
456
457 static const char *cm_id_state_to_str(uint8_t idx)
458 {
459 static const char * const cm_id_states_str[] = {
460 "IDLE", "ADDR_QUERY", "ADDR_RESOLVED", "ROUTE_QUERY",
461 "ROUTE_RESOLVED", "CONNECT", "DISCONNECT", "ADDR_BOUND",
462 "LISTEN", "DEVICE_REMOVAL", "DESTROYING" };
463
464 if (idx < ARRAY_SIZE(cm_id_states_str))
465 return cm_id_states_str[idx];
466 return "UNKNOWN";
467 }
468
469 static const char *cm_id_ps_to_str(uint32_t ps)
470 {
471 switch (ps) {
472 case RDMA_PS_IPOIB:
473 return "IPoIB";
474 case RDMA_PS_IB:
475 return "IPoIB";
476 case RDMA_PS_TCP:
477 return "TCP";
478 case RDMA_PS_UDP:
479 return "UDP";
480 default:
481 return "---";
482 }
483 }
484
485 static void print_cm_id_state(struct rd *rd, uint8_t state)
486 {
487 if (rd->json_output) {
488 jsonw_string_field(rd->jw, "state", cm_id_state_to_str(state));
489 return;
490 }
491 pr_out("state %s ", cm_id_state_to_str(state));
492 }
493
494 static void print_ps(struct rd *rd, uint32_t ps)
495 {
496 if (rd->json_output) {
497 jsonw_string_field(rd->jw, "ps", cm_id_ps_to_str(ps));
498 return;
499 }
500 pr_out("ps %s ", cm_id_ps_to_str(ps));
501 }
502
503 static void print_ipaddr(struct rd *rd, const char *key, char *addrstr,
504 uint16_t port)
505 {
506 if (rd->json_output) {
507 int name_size = INET6_ADDRSTRLEN+strlen(":65535");
508 char json_name[name_size];
509
510 snprintf(json_name, name_size, "%s:%u", addrstr, port);
511 jsonw_string_field(rd->jw, key, json_name);
512 return;
513 }
514 pr_out("%s %s:%u ", key, addrstr, port);
515 }
516
517 static int ss_ntop(struct nlattr *nla_line, char *addr_str, uint16_t *port)
518 {
519 struct __kernel_sockaddr_storage *addr;
520
521 addr = (struct __kernel_sockaddr_storage *)
522 mnl_attr_get_payload(nla_line);
523 switch (addr->ss_family) {
524 case AF_INET: {
525 struct sockaddr_in *sin = (struct sockaddr_in *)addr;
526
527 if (!inet_ntop(AF_INET, (const void *)&sin->sin_addr, addr_str,
528 INET6_ADDRSTRLEN))
529 return -EINVAL;
530 *port = ntohs(sin->sin_port);
531 break;
532 }
533 case AF_INET6: {
534 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
535
536 if (!inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
537 addr_str, INET6_ADDRSTRLEN))
538 return -EINVAL;
539 *port = ntohs(sin6->sin6_port);
540 break;
541 }
542 default:
543 return -EINVAL;
544 }
545 return 0;
546 }
547
548 static int res_cm_id_parse_cb(const struct nlmsghdr *nlh, void *data)
549 {
550 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
551 struct nlattr *nla_table, *nla_entry;
552 struct rd *rd = data;
553 const char *name;
554 int idx;
555
556 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
557 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
558 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
559 !tb[RDMA_NLDEV_ATTR_RES_CM_ID])
560 return MNL_CB_ERROR;
561
562 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
563 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
564 nla_table = tb[RDMA_NLDEV_ATTR_RES_CM_ID];
565 mnl_attr_for_each_nested(nla_entry, nla_table) {
566 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
567 char src_addr_str[INET6_ADDRSTRLEN];
568 char dst_addr_str[INET6_ADDRSTRLEN];
569 uint16_t src_port, dst_port;
570 uint32_t port = 0, pid = 0;
571 uint8_t type = 0, state;
572 uint32_t lqpn = 0, ps;
573 char *comm = NULL;
574 int err;
575
576 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
577 if (err != MNL_CB_OK)
578 return -EINVAL;
579
580 if (!nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
581 !nla_line[RDMA_NLDEV_ATTR_RES_PS] ||
582 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
583 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
584 return MNL_CB_ERROR;
585 }
586
587 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
588 port = mnl_attr_get_u32(
589 nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
590
591 if (port && port != rd->port_idx)
592 continue;
593
594 if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN]) {
595 lqpn = mnl_attr_get_u32(
596 nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
597 if (rd_check_is_filtered(rd, "lqpn", lqpn))
598 continue;
599 }
600 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE]) {
601 type = mnl_attr_get_u8(
602 nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
603 if (rd_check_is_string_filtered(rd, "qp-type",
604 qp_types_to_str(type)))
605 continue;
606 }
607
608 ps = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PS]);
609 if (rd_check_is_string_filtered(rd, "ps", cm_id_ps_to_str(ps)))
610 continue;
611
612 state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
613 if (rd_check_is_string_filtered(rd, "state",
614 cm_id_state_to_str(state)))
615 continue;
616
617 if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR]) {
618 if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR],
619 src_addr_str, &src_port))
620 continue;
621 if (rd_check_is_string_filtered(rd, "src-addr",
622 src_addr_str))
623 continue;
624 if (rd_check_is_filtered(rd, "src-port", src_port))
625 continue;
626 }
627
628 if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR]) {
629 if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR],
630 dst_addr_str, &dst_port))
631 continue;
632 if (rd_check_is_string_filtered(rd, "dst-addr",
633 dst_addr_str))
634 continue;
635 if (rd_check_is_filtered(rd, "dst-port", dst_port))
636 continue;
637 }
638
639 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
640 pid = mnl_attr_get_u32(
641 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
642 comm = get_task_name(pid);
643 }
644
645 if (rd_check_is_filtered(rd, "pid", pid)) {
646 free(comm);
647 continue;
648 }
649
650 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) {
651 /* discard const from mnl_attr_get_str */
652 comm = (char *)mnl_attr_get_str(
653 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
654 }
655
656 if (rd->json_output)
657 jsonw_start_array(rd->jw);
658
659 print_link(rd, idx, name, port, nla_line);
660 if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
661 print_lqpn(rd, lqpn);
662 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
663 print_qp_type(rd, type);
664 print_cm_id_state(rd, state);
665 print_ps(rd, ps);
666 print_pid(rd, pid);
667 print_comm(rd, comm, nla_line);
668
669 if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
670 print_ipaddr(rd, "src-addr", src_addr_str, src_port);
671 if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
672 print_ipaddr(rd, "dst-addr", dst_addr_str, dst_port);
673
674 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
675 free(comm);
676
677 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
678 newline(rd);
679 }
680 return MNL_CB_OK;
681 }
682
683 static void print_cqe(struct rd *rd, uint32_t val)
684 {
685 if (rd->json_output)
686 jsonw_uint_field(rd->jw, "cqe", val);
687 else
688 pr_out("cqe %u ", val);
689 }
690
691 static void print_users(struct rd *rd, uint64_t val)
692 {
693 if (rd->json_output)
694 jsonw_uint_field(rd->jw, "users", val);
695 else
696 pr_out("users %" PRIu64 " ", val);
697 }
698
699 static const char *poll_ctx_to_str(uint8_t idx)
700 {
701 static const char * const cm_id_states_str[] = {
702 "DIRECT", "SOFTIRQ", "WORKQUEUE"};
703
704 if (idx < ARRAY_SIZE(cm_id_states_str))
705 return cm_id_states_str[idx];
706 return "UNKNOWN";
707 }
708
709 static void print_poll_ctx(struct rd *rd, uint8_t poll_ctx)
710 {
711 if (rd->json_output) {
712 jsonw_string_field(rd->jw, "poll-ctx",
713 poll_ctx_to_str(poll_ctx));
714 return;
715 }
716 pr_out("poll-ctx %s ", poll_ctx_to_str(poll_ctx));
717 }
718
719 static int res_cq_parse_cb(const struct nlmsghdr *nlh, void *data)
720 {
721 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
722 struct nlattr *nla_table, *nla_entry;
723 struct rd *rd = data;
724 const char *name;
725 uint32_t idx;
726
727 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
728 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
729 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
730 !tb[RDMA_NLDEV_ATTR_RES_CQ])
731 return MNL_CB_ERROR;
732
733 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
734 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
735 nla_table = tb[RDMA_NLDEV_ATTR_RES_CQ];
736
737 mnl_attr_for_each_nested(nla_entry, nla_table) {
738 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
739 char *comm = NULL;
740 uint32_t pid = 0;
741 uint8_t poll_ctx = 0;
742 uint64_t users;
743 uint32_t cqe;
744 int err;
745
746 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
747 if (err != MNL_CB_OK)
748 return MNL_CB_ERROR;
749
750 if (!nla_line[RDMA_NLDEV_ATTR_RES_CQE] ||
751 !nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
752 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
753 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
754 return MNL_CB_ERROR;
755 }
756
757 cqe = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQE]);
758
759 users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
760 if (rd_check_is_filtered(rd, "users", users))
761 continue;
762
763 if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]) {
764 poll_ctx = mnl_attr_get_u8(
765 nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]);
766 if (rd_check_is_string_filtered(rd, "poll-ctx",
767 poll_ctx_to_str(poll_ctx)))
768 continue;
769 }
770
771 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
772 pid = mnl_attr_get_u32(
773 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
774 comm = get_task_name(pid);
775 }
776
777 if (rd_check_is_filtered(rd, "pid", pid)) {
778 free(comm);
779 continue;
780 }
781
782 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
783 /* discard const from mnl_attr_get_str */
784 comm = (char *)mnl_attr_get_str(
785 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
786
787 if (rd->json_output)
788 jsonw_start_array(rd->jw);
789
790 print_dev(rd, idx, name);
791 print_cqe(rd, cqe);
792 print_users(rd, users);
793 if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX])
794 print_poll_ctx(rd, poll_ctx);
795 print_pid(rd, pid);
796 print_comm(rd, comm, nla_line);
797
798 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
799 free(comm);
800
801 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
802 newline(rd);
803 }
804 return MNL_CB_OK;
805 }
806
807 static void print_key(struct rd *rd, const char *name, uint32_t val)
808 {
809 if (rd->json_output)
810 jsonw_xint_field(rd->jw, name, val);
811 else
812 pr_out("%s 0x%x ", name, val);
813 }
814
815 static void print_iova(struct rd *rd, uint64_t val)
816 {
817 if (rd->json_output)
818 jsonw_xint_field(rd->jw, "iova", val);
819 else
820 pr_out("iova 0x%" PRIx64 " ", val);
821 }
822
823 static void print_mrlen(struct rd *rd, uint64_t val)
824 {
825 if (rd->json_output)
826 jsonw_uint_field(rd->jw, "mrlen", val);
827 else
828 pr_out("mrlen %" PRIu64 " ", val);
829 }
830
831 static int res_mr_parse_cb(const struct nlmsghdr *nlh, void *data)
832 {
833 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
834 struct nlattr *nla_table, *nla_entry;
835 struct rd *rd = data;
836 const char *name;
837 uint32_t idx;
838
839 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
840 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
841 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
842 !tb[RDMA_NLDEV_ATTR_RES_MR])
843 return MNL_CB_ERROR;
844
845 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
846 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
847 nla_table = tb[RDMA_NLDEV_ATTR_RES_MR];
848
849 mnl_attr_for_each_nested(nla_entry, nla_table) {
850 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
851 uint32_t rkey = 0, lkey = 0;
852 uint64_t iova = 0, mrlen;
853 char *comm = NULL;
854 uint32_t pid = 0;
855 int err;
856
857 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
858 if (err != MNL_CB_OK)
859 return MNL_CB_ERROR;
860
861 if (!nla_line[RDMA_NLDEV_ATTR_RES_MRLEN] ||
862 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
863 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
864 return MNL_CB_ERROR;
865 }
866
867 if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
868 rkey = mnl_attr_get_u32(
869 nla_line[RDMA_NLDEV_ATTR_RES_RKEY]);
870 if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
871 lkey = mnl_attr_get_u32(
872 nla_line[RDMA_NLDEV_ATTR_RES_LKEY]);
873 if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
874 iova = mnl_attr_get_u64(
875 nla_line[RDMA_NLDEV_ATTR_RES_IOVA]);
876
877 mrlen = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]);
878 if (rd_check_is_filtered(rd, "mrlen", mrlen))
879 continue;
880
881 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
882 pid = mnl_attr_get_u32(
883 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
884 comm = get_task_name(pid);
885 }
886
887 if (rd_check_is_filtered(rd, "pid", pid)) {
888 free(comm);
889 continue;
890 }
891
892 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
893 /* discard const from mnl_attr_get_str */
894 comm = (char *)mnl_attr_get_str(
895 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
896
897 if (rd->json_output)
898 jsonw_start_array(rd->jw);
899
900 print_dev(rd, idx, name);
901 if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
902 print_key(rd, "rkey", rkey);
903 if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
904 print_key(rd, "lkey", lkey);
905 if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
906 print_iova(rd, iova);
907 print_mrlen(rd, mrlen);
908 print_pid(rd, pid);
909 print_comm(rd, comm, nla_line);
910
911 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
912 free(comm);
913
914 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
915 newline(rd);
916 }
917 return MNL_CB_OK;
918 }
919
920 static int res_pd_parse_cb(const struct nlmsghdr *nlh, void *data)
921 {
922 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
923 struct nlattr *nla_table, *nla_entry;
924 struct rd *rd = data;
925 const char *name;
926 uint32_t idx;
927
928 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
929 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
930 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
931 !tb[RDMA_NLDEV_ATTR_RES_PD])
932 return MNL_CB_ERROR;
933
934 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
935 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
936 nla_table = tb[RDMA_NLDEV_ATTR_RES_PD];
937
938 mnl_attr_for_each_nested(nla_entry, nla_table) {
939 uint32_t local_dma_lkey = 0, unsafe_global_rkey = 0;
940 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
941 char *comm = NULL;
942 uint32_t pid = 0;
943 uint64_t users;
944 int err;
945
946 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
947 if (err != MNL_CB_OK)
948 return MNL_CB_ERROR;
949
950 if (!nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
951 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
952 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
953 return MNL_CB_ERROR;
954 }
955
956 if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY])
957 local_dma_lkey = mnl_attr_get_u32(
958 nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]);
959
960 users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
961 if (rd_check_is_filtered(rd, "users", users))
962 continue;
963
964 if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY])
965 unsafe_global_rkey = mnl_attr_get_u32(
966 nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]);
967
968 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
969 pid = mnl_attr_get_u32(
970 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
971 comm = get_task_name(pid);
972 }
973
974 if (rd_check_is_filtered(rd, "pid", pid))
975 continue;
976
977 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
978 /* discard const from mnl_attr_get_str */
979 comm = (char *)mnl_attr_get_str(
980 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
981
982 if (rd->json_output)
983 jsonw_start_array(rd->jw);
984
985 print_dev(rd, idx, name);
986 if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY])
987 print_key(rd, "local_dma_lkey", local_dma_lkey);
988 print_users(rd, users);
989 if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY])
990 print_key(rd, "unsafe_global_rkey", unsafe_global_rkey);
991 print_pid(rd, pid);
992 print_comm(rd, comm, nla_line);
993
994 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
995 free(comm);
996
997 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
998 newline(rd);
999 }
1000 return MNL_CB_OK;
1001 }
1002
1003 RES_FUNC(res_no_args, RDMA_NLDEV_CMD_RES_GET, NULL, true);
1004
1005 static const struct
1006 filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {{ .name = "link",
1007 .is_number = false },
1008 { .name = "lqpn",
1009 .is_number = true },
1010 { .name = "rqpn",
1011 .is_number = true },
1012 { .name = "pid",
1013 .is_number = true },
1014 { .name = "sq-psn",
1015 .is_number = true },
1016 { .name = "rq-psn",
1017 .is_number = true },
1018 { .name = "type",
1019 .is_number = false },
1020 { .name = "path-mig-state",
1021 .is_number = false },
1022 { .name = "state",
1023 .is_number = false } };
1024
1025 RES_FUNC(res_qp, RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false);
1026
1027 static const
1028 struct filters cm_id_valid_filters[MAX_NUMBER_OF_FILTERS] = {
1029 { .name = "link", .is_number = false },
1030 { .name = "lqpn", .is_number = true },
1031 { .name = "qp-type", .is_number = false },
1032 { .name = "state", .is_number = false },
1033 { .name = "ps", .is_number = false },
1034 { .name = "dev-type", .is_number = false },
1035 { .name = "transport-type", .is_number = false },
1036 { .name = "pid", .is_number = true },
1037 { .name = "src-addr", .is_number = false },
1038 { .name = "src-port", .is_number = true },
1039 { .name = "dst-addr", .is_number = false },
1040 { .name = "dst-port", .is_number = true }
1041 };
1042
1043 RES_FUNC(res_cm_id, RDMA_NLDEV_CMD_RES_CM_ID_GET, cm_id_valid_filters, false);
1044
1045 static const
1046 struct filters cq_valid_filters[MAX_NUMBER_OF_FILTERS] = {
1047 { .name = "dev", .is_number = false },
1048 { .name = "users", .is_number = true },
1049 { .name = "poll-ctx", .is_number = false },
1050 { .name = "pid", .is_number = true }
1051 };
1052
1053 RES_FUNC(res_cq, RDMA_NLDEV_CMD_RES_CQ_GET, cq_valid_filters, true);
1054
1055 static const
1056 struct filters mr_valid_filters[MAX_NUMBER_OF_FILTERS] = {
1057 { .name = "dev", .is_number = false },
1058 { .name = "rkey", .is_number = true },
1059 { .name = "lkey", .is_number = true },
1060 { .name = "mrlen", .is_number = true },
1061 { .name = "pid", .is_number = true }
1062 };
1063
1064 RES_FUNC(res_mr, RDMA_NLDEV_CMD_RES_MR_GET, mr_valid_filters, true);
1065
1066 static const
1067 struct filters pd_valid_filters[MAX_NUMBER_OF_FILTERS] = {
1068 { .name = "dev", .is_number = false },
1069 { .name = "users", .is_number = true },
1070 { .name = "pid", .is_number = true }
1071 };
1072
1073 RES_FUNC(res_pd, RDMA_NLDEV_CMD_RES_PD_GET, pd_valid_filters, true);
1074
1075 static int res_show(struct rd *rd)
1076 {
1077 const struct rd_cmd cmds[] = {
1078 { NULL, res_no_args },
1079 { "qp", res_qp },
1080 { "cm_id", res_cm_id },
1081 { "cq", res_cq },
1082 { "mr", res_mr },
1083 { "pd", res_pd },
1084 { 0 }
1085 };
1086
1087 /*
1088 * Special case to support "rdma res show DEV_NAME"
1089 */
1090 if (rd_argc(rd) == 1 && dev_map_lookup(rd, false))
1091 return rd_exec_dev(rd, _res_no_args);
1092
1093 return rd_exec_cmd(rd, cmds, "parameter");
1094 }
1095
1096 int cmd_res(struct rd *rd)
1097 {
1098 const struct rd_cmd cmds[] = {
1099 { NULL, res_show },
1100 { "show", res_show },
1101 { "list", res_show },
1102 { "help", res_help },
1103 { 0 }
1104 };
1105
1106 return rd_exec_cmd(rd, cmds, "resource command");
1107 }