]> git.proxmox.com Git - mirror_iproute2.git/blob - rdma/res.c
rdma: Add MR resource tracking information
[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 if (rd->json_output)
443 jsonw_end_array(rd->jw);
444 else
445 pr_out("\n");
446 }
447 return MNL_CB_OK;
448 }
449
450 static void print_qp_type(struct rd *rd, uint32_t val)
451 {
452 if (rd->json_output)
453 jsonw_string_field(rd->jw, "qp-type",
454 qp_types_to_str(val));
455 else
456 pr_out("qp-type %s ", qp_types_to_str(val));
457 }
458
459 static const char *cm_id_state_to_str(uint8_t idx)
460 {
461 static const char * const cm_id_states_str[] = {
462 "IDLE", "ADDR_QUERY", "ADDR_RESOLVED", "ROUTE_QUERY",
463 "ROUTE_RESOLVED", "CONNECT", "DISCONNECT", "ADDR_BOUND",
464 "LISTEN", "DEVICE_REMOVAL", "DESTROYING" };
465
466 if (idx < ARRAY_SIZE(cm_id_states_str))
467 return cm_id_states_str[idx];
468 return "UNKNOWN";
469 }
470
471 static const char *cm_id_ps_to_str(uint32_t ps)
472 {
473 switch (ps) {
474 case RDMA_PS_IPOIB:
475 return "IPoIB";
476 case RDMA_PS_IB:
477 return "IPoIB";
478 case RDMA_PS_TCP:
479 return "TCP";
480 case RDMA_PS_UDP:
481 return "UDP";
482 default:
483 return "---";
484 }
485 }
486
487 static void print_cm_id_state(struct rd *rd, uint8_t state)
488 {
489 if (rd->json_output) {
490 jsonw_string_field(rd->jw, "state", cm_id_state_to_str(state));
491 return;
492 }
493 pr_out("state %s ", cm_id_state_to_str(state));
494 }
495
496 static void print_ps(struct rd *rd, uint32_t ps)
497 {
498 if (rd->json_output) {
499 jsonw_string_field(rd->jw, "ps", cm_id_ps_to_str(ps));
500 return;
501 }
502 pr_out("ps %s ", cm_id_ps_to_str(ps));
503 }
504
505 static void print_ipaddr(struct rd *rd, const char *key, char *addrstr,
506 uint16_t port)
507 {
508 if (rd->json_output) {
509 int name_size = INET6_ADDRSTRLEN+strlen(":65535");
510 char json_name[name_size];
511
512 snprintf(json_name, name_size, "%s:%u", addrstr, port);
513 jsonw_string_field(rd->jw, key, json_name);
514 return;
515 }
516 pr_out("%s %s:%u ", key, addrstr, port);
517 }
518
519 static int ss_ntop(struct nlattr *nla_line, char *addr_str, uint16_t *port)
520 {
521 struct __kernel_sockaddr_storage *addr;
522
523 addr = (struct __kernel_sockaddr_storage *)
524 mnl_attr_get_payload(nla_line);
525 switch (addr->ss_family) {
526 case AF_INET: {
527 struct sockaddr_in *sin = (struct sockaddr_in *)addr;
528
529 if (!inet_ntop(AF_INET, (const void *)&sin->sin_addr, addr_str,
530 INET6_ADDRSTRLEN))
531 return -EINVAL;
532 *port = ntohs(sin->sin_port);
533 break;
534 }
535 case AF_INET6: {
536 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
537
538 if (!inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
539 addr_str, INET6_ADDRSTRLEN))
540 return -EINVAL;
541 *port = ntohs(sin6->sin6_port);
542 break;
543 }
544 default:
545 return -EINVAL;
546 }
547 return 0;
548 }
549
550 static int res_cm_id_parse_cb(const struct nlmsghdr *nlh, void *data)
551 {
552 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
553 struct nlattr *nla_table, *nla_entry;
554 struct rd *rd = data;
555 const char *name;
556 int idx;
557
558 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
559 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
560 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
561 !tb[RDMA_NLDEV_ATTR_RES_CM_ID])
562 return MNL_CB_ERROR;
563
564 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
565 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
566 nla_table = tb[RDMA_NLDEV_ATTR_RES_CM_ID];
567 mnl_attr_for_each_nested(nla_entry, nla_table) {
568 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
569 char src_addr_str[INET6_ADDRSTRLEN];
570 char dst_addr_str[INET6_ADDRSTRLEN];
571 uint16_t src_port, dst_port;
572 uint32_t port = 0, pid = 0;
573 uint8_t type = 0, state;
574 uint32_t lqpn = 0, ps;
575 char *comm = NULL;
576 int err;
577
578 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
579 if (err != MNL_CB_OK)
580 return -EINVAL;
581
582 if (!nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
583 !nla_line[RDMA_NLDEV_ATTR_RES_PS] ||
584 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
585 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
586 return MNL_CB_ERROR;
587 }
588
589 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
590 port = mnl_attr_get_u32(
591 nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
592
593 if (port && port != rd->port_idx)
594 continue;
595
596 if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN]) {
597 lqpn = mnl_attr_get_u32(
598 nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
599 if (rd_check_is_filtered(rd, "lqpn", lqpn))
600 continue;
601 }
602 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE]) {
603 type = mnl_attr_get_u8(
604 nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
605 if (rd_check_is_string_filtered(rd, "qp-type",
606 qp_types_to_str(type)))
607 continue;
608 }
609
610 ps = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PS]);
611 if (rd_check_is_string_filtered(rd, "ps", cm_id_ps_to_str(ps)))
612 continue;
613
614 state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
615 if (rd_check_is_string_filtered(rd, "state",
616 cm_id_state_to_str(state)))
617 continue;
618
619 if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR]) {
620 if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR],
621 src_addr_str, &src_port))
622 continue;
623 if (rd_check_is_string_filtered(rd, "src-addr",
624 src_addr_str))
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 }
636
637 if (rd_check_is_filtered(rd, "src-port", src_port))
638 continue;
639
640 if (rd_check_is_filtered(rd, "dst-port", dst_port))
641 continue;
642
643 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
644 pid = mnl_attr_get_u32(
645 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
646 comm = get_task_name(pid);
647 }
648
649 if (rd_check_is_filtered(rd, "pid", pid)) {
650 free(comm);
651 continue;
652 }
653
654 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) {
655 /* discard const from mnl_attr_get_str */
656 comm = (char *)mnl_attr_get_str(
657 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
658 }
659
660 if (rd->json_output)
661 jsonw_start_array(rd->jw);
662
663 print_link(rd, idx, name, port, nla_line);
664 if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
665 print_lqpn(rd, lqpn);
666 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
667 print_qp_type(rd, type);
668 print_cm_id_state(rd, state);
669 print_ps(rd, ps);
670 print_pid(rd, pid);
671 print_comm(rd, comm, nla_line);
672
673 if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
674 print_ipaddr(rd, "src-addr", src_addr_str, src_port);
675 if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
676 print_ipaddr(rd, "dst-addr", dst_addr_str, dst_port);
677
678 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
679 free(comm);
680
681 if (rd->json_output)
682 jsonw_end_array(rd->jw);
683 else
684 pr_out("\n");
685 }
686 return MNL_CB_OK;
687 }
688
689 static void print_cqe(struct rd *rd, uint32_t val)
690 {
691 if (rd->json_output)
692 jsonw_uint_field(rd->jw, "cqe", val);
693 else
694 pr_out("cqe %u ", val);
695 }
696
697 static void print_users(struct rd *rd, uint64_t val)
698 {
699 if (rd->json_output)
700 jsonw_uint_field(rd->jw, "users", val);
701 else
702 pr_out("users %" PRIu64 " ", val);
703 }
704
705 static const char *poll_ctx_to_str(uint8_t idx)
706 {
707 static const char * const cm_id_states_str[] = {
708 "DIRECT", "SOFTIRQ", "WORKQUEUE"};
709
710 if (idx < ARRAY_SIZE(cm_id_states_str))
711 return cm_id_states_str[idx];
712 return "UNKNOWN";
713 }
714
715 static void print_poll_ctx(struct rd *rd, uint8_t poll_ctx)
716 {
717 if (rd->json_output) {
718 jsonw_string_field(rd->jw, "poll-ctx",
719 poll_ctx_to_str(poll_ctx));
720 return;
721 }
722 pr_out("poll-ctx %s ", poll_ctx_to_str(poll_ctx));
723 }
724
725 static int res_cq_parse_cb(const struct nlmsghdr *nlh, void *data)
726 {
727 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
728 struct nlattr *nla_table, *nla_entry;
729 struct rd *rd = data;
730 const char *name;
731 uint32_t idx;
732
733 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
734 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
735 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
736 !tb[RDMA_NLDEV_ATTR_RES_CQ])
737 return MNL_CB_ERROR;
738
739 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
740 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
741 nla_table = tb[RDMA_NLDEV_ATTR_RES_CQ];
742
743 mnl_attr_for_each_nested(nla_entry, nla_table) {
744 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
745 char *comm = NULL;
746 uint32_t pid = 0;
747 uint8_t poll_ctx = 0;
748 uint64_t users;
749 uint32_t cqe;
750 int err;
751
752 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
753 if (err != MNL_CB_OK)
754 return MNL_CB_ERROR;
755
756 if (!nla_line[RDMA_NLDEV_ATTR_RES_CQE] ||
757 !nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
758 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
759 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
760 return MNL_CB_ERROR;
761 }
762
763 cqe = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQE]);
764
765 users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
766 if (rd_check_is_filtered(rd, "users", users))
767 continue;
768
769 if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]) {
770 poll_ctx = mnl_attr_get_u8(
771 nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]);
772 if (rd_check_is_string_filtered(rd, "poll-ctx",
773 poll_ctx_to_str(poll_ctx)))
774 continue;
775 }
776
777 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
778 pid = mnl_attr_get_u32(
779 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
780 comm = get_task_name(pid);
781 }
782
783 if (rd_check_is_filtered(rd, "pid", pid)) {
784 free(comm);
785 continue;
786 }
787
788 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
789 /* discard const from mnl_attr_get_str */
790 comm = (char *)mnl_attr_get_str(
791 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
792
793 if (rd->json_output)
794 jsonw_start_array(rd->jw);
795
796 print_dev(rd, idx, name);
797 print_cqe(rd, cqe);
798 print_users(rd, users);
799 if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX])
800 print_poll_ctx(rd, poll_ctx);
801 print_pid(rd, pid);
802 print_comm(rd, comm, nla_line);
803
804 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
805 free(comm);
806
807 if (rd->json_output)
808 jsonw_end_array(rd->jw);
809 else
810 pr_out("\n");
811 }
812 return MNL_CB_OK;
813 }
814
815 static void print_key(struct rd *rd, const char *name, uint32_t val)
816 {
817 if (rd->json_output)
818 jsonw_xint_field(rd->jw, name, val);
819 else
820 pr_out("%s 0x%x ", name, val);
821 }
822
823 static void print_iova(struct rd *rd, uint64_t val)
824 {
825 if (rd->json_output)
826 jsonw_xint_field(rd->jw, "iova", val);
827 else
828 pr_out("iova 0x%" PRIx64 " ", val);
829 }
830
831 static void print_mrlen(struct rd *rd, uint64_t val)
832 {
833 if (rd->json_output)
834 jsonw_uint_field(rd->jw, "mrlen", val);
835 else
836 pr_out("mrlen %" PRIu64 " ", val);
837 }
838
839 static int res_mr_parse_cb(const struct nlmsghdr *nlh, void *data)
840 {
841 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
842 struct nlattr *nla_table, *nla_entry;
843 struct rd *rd = data;
844 const char *name;
845 uint32_t idx;
846
847 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
848 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
849 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
850 !tb[RDMA_NLDEV_ATTR_RES_MR])
851 return MNL_CB_ERROR;
852
853 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
854 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
855 nla_table = tb[RDMA_NLDEV_ATTR_RES_MR];
856
857 mnl_attr_for_each_nested(nla_entry, nla_table) {
858 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
859 uint32_t rkey = 0, lkey = 0;
860 uint64_t iova = 0, mrlen;
861 char *comm = NULL;
862 uint32_t pid = 0;
863 int err;
864
865 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
866 if (err != MNL_CB_OK)
867 return MNL_CB_ERROR;
868
869 if (!nla_line[RDMA_NLDEV_ATTR_RES_MRLEN] ||
870 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
871 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
872 return MNL_CB_ERROR;
873 }
874
875 if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
876 rkey = mnl_attr_get_u32(
877 nla_line[RDMA_NLDEV_ATTR_RES_RKEY]);
878 if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
879 lkey = mnl_attr_get_u32(
880 nla_line[RDMA_NLDEV_ATTR_RES_LKEY]);
881 if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
882 iova = mnl_attr_get_u64(
883 nla_line[RDMA_NLDEV_ATTR_RES_IOVA]);
884
885 mrlen = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]);
886 if (rd_check_is_filtered(rd, "mrlen", mrlen))
887 continue;
888
889 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
890 pid = mnl_attr_get_u32(
891 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
892 comm = get_task_name(pid);
893 }
894
895 if (rd_check_is_filtered(rd, "pid", pid)) {
896 free(comm);
897 continue;
898 }
899
900 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
901 /* discard const from mnl_attr_get_str */
902 comm = (char *)mnl_attr_get_str(
903 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
904
905 if (rd->json_output)
906 jsonw_start_array(rd->jw);
907
908 print_dev(rd, idx, name);
909 if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
910 print_key(rd, "rkey", rkey);
911 if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
912 print_key(rd, "lkey", lkey);
913 if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
914 print_iova(rd, iova);
915 print_mrlen(rd, mrlen);
916 print_pid(rd, pid);
917 print_comm(rd, comm, nla_line);
918
919 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
920 free(comm);
921
922 if (rd->json_output)
923 jsonw_end_array(rd->jw);
924 else
925 pr_out("\n");
926 }
927 return MNL_CB_OK;
928 }
929
930 RES_FUNC(res_no_args, RDMA_NLDEV_CMD_RES_GET, NULL, true);
931
932 static const struct
933 filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {{ .name = "link",
934 .is_number = false },
935 { .name = "lqpn",
936 .is_number = true },
937 { .name = "rqpn",
938 .is_number = true },
939 { .name = "pid",
940 .is_number = true },
941 { .name = "sq-psn",
942 .is_number = true },
943 { .name = "rq-psn",
944 .is_number = true },
945 { .name = "type",
946 .is_number = false },
947 { .name = "path-mig-state",
948 .is_number = false },
949 { .name = "state",
950 .is_number = false } };
951
952 RES_FUNC(res_qp, RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false);
953
954 static const
955 struct filters cm_id_valid_filters[MAX_NUMBER_OF_FILTERS] = {
956 { .name = "link", .is_number = false },
957 { .name = "lqpn", .is_number = true },
958 { .name = "qp-type", .is_number = false },
959 { .name = "state", .is_number = false },
960 { .name = "ps", .is_number = false },
961 { .name = "dev-type", .is_number = false },
962 { .name = "transport-type", .is_number = false },
963 { .name = "pid", .is_number = true },
964 { .name = "src-addr", .is_number = false },
965 { .name = "src-port", .is_number = true },
966 { .name = "dst-addr", .is_number = false },
967 { .name = "dst-port", .is_number = true }
968 };
969
970 RES_FUNC(res_cm_id, RDMA_NLDEV_CMD_RES_CM_ID_GET, cm_id_valid_filters, false);
971
972 static const
973 struct filters cq_valid_filters[MAX_NUMBER_OF_FILTERS] = {
974 { .name = "dev", .is_number = false },
975 { .name = "users", .is_number = true },
976 { .name = "poll-ctx", .is_number = false },
977 { .name = "pid", .is_number = true }
978 };
979
980 RES_FUNC(res_cq, RDMA_NLDEV_CMD_RES_CQ_GET, cq_valid_filters, true);
981
982 static const
983 struct filters mr_valid_filters[MAX_NUMBER_OF_FILTERS] = {
984 { .name = "dev", .is_number = false },
985 { .name = "rkey", .is_number = true },
986 { .name = "lkey", .is_number = true },
987 { .name = "mrlen", .is_number = true },
988 { .name = "pid", .is_number = true }
989 };
990
991 RES_FUNC(res_mr, RDMA_NLDEV_CMD_RES_MR_GET, mr_valid_filters, true);
992
993 static int res_show(struct rd *rd)
994 {
995 const struct rd_cmd cmds[] = {
996 { NULL, res_no_args },
997 { "qp", res_qp },
998 { "cm_id", res_cm_id },
999 { "cq", res_cq },
1000 { "mr", res_mr },
1001 { 0 }
1002 };
1003
1004 /*
1005 * Special case to support "rdma res show DEV_NAME"
1006 */
1007 if (rd_argc(rd) == 1 && dev_map_lookup(rd, false))
1008 return rd_exec_dev(rd, _res_no_args);
1009
1010 return rd_exec_cmd(rd, cmds, "parameter");
1011 }
1012
1013 int cmd_res(struct rd *rd)
1014 {
1015 const struct rd_cmd cmds[] = {
1016 { NULL, res_show },
1017 { "show", res_show },
1018 { "list", res_show },
1019 { "help", res_help },
1020 { 0 }
1021 };
1022
1023 return rd_exec_cmd(rd, cmds, "resource command");
1024 }