]> git.proxmox.com Git - mirror_iproute2.git/blob - rdma/res.c
rdma: Add CM_ID 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 return 0;
25 }
26
27 static int res_print_summary(struct rd *rd, struct nlattr **tb)
28 {
29 struct nlattr *nla_table = tb[RDMA_NLDEV_ATTR_RES_SUMMARY];
30 struct nlattr *nla_entry;
31 const char *name;
32 uint64_t curr;
33 int err;
34
35 mnl_attr_for_each_nested(nla_entry, nla_table) {
36 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
37 char json_name[32];
38
39 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
40 if (err != MNL_CB_OK)
41 return -EINVAL;
42
43 if (!nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] ||
44 !nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]) {
45 return -EINVAL;
46 }
47
48 name = mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]);
49 curr = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
50 if (rd->json_output) {
51 snprintf(json_name, 32, "%s", name);
52 jsonw_lluint_field(rd->jw, json_name, curr);
53 } else {
54 pr_out("%s %"PRId64 " ", name, curr);
55 }
56 }
57 return 0;
58 }
59
60 static int res_no_args_parse_cb(const struct nlmsghdr *nlh, void *data)
61 {
62 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
63 struct rd *rd = data;
64 const char *name;
65 uint32_t idx;
66
67 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
68 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
69 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
70 !tb[RDMA_NLDEV_ATTR_RES_SUMMARY])
71 return MNL_CB_ERROR;
72
73 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
74 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
75 if (rd->json_output) {
76 jsonw_uint_field(rd->jw, "ifindex", idx);
77 jsonw_string_field(rd->jw, "ifname", name);
78 } else {
79 pr_out("%u: %s: ", idx, name);
80 }
81
82 res_print_summary(rd, tb);
83
84 if (!rd->json_output)
85 pr_out("\n");
86 return MNL_CB_OK;
87 }
88
89 static int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback)
90 {
91 uint32_t flags = NLM_F_REQUEST | NLM_F_ACK;
92 uint32_t seq;
93 int ret;
94
95 if (command != RDMA_NLDEV_CMD_RES_GET)
96 flags |= NLM_F_DUMP;
97
98 rd_prepare_msg(rd, command, &seq, flags);
99 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
100 if (rd->port_idx)
101 mnl_attr_put_u32(rd->nlh,
102 RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
103
104 ret = rd_send_msg(rd);
105 if (ret)
106 return ret;
107
108 if (rd->json_output)
109 jsonw_start_object(rd->jw);
110 ret = rd_recv_msg(rd, callback, rd, seq);
111 if (rd->json_output)
112 jsonw_end_object(rd->jw);
113 return ret;
114 }
115
116 #define RES_FUNC(name, command, valid_filters, strict_port) \
117 static int _##name(struct rd *rd)\
118 { \
119 return _res_send_msg(rd, command, name##_parse_cb); \
120 } \
121 static int name(struct rd *rd) \
122 {\
123 int ret = rd_build_filter(rd, valid_filters); \
124 if (ret) \
125 return ret; \
126 if ((uintptr_t)valid_filters != (uintptr_t)NULL) { \
127 ret = rd_set_arg_to_devname(rd); \
128 if (ret) \
129 return ret;\
130 } \
131 if (strict_port) \
132 return rd_exec_dev(rd, _##name); \
133 else \
134 return rd_exec_link(rd, _##name, strict_port); \
135 }
136
137 static const char *path_mig_to_str(uint8_t idx)
138 {
139 static const char * const path_mig_str[] = { "MIGRATED",
140 "REARM", "ARMED" };
141
142 if (idx < ARRAY_SIZE(path_mig_str))
143 return path_mig_str[idx];
144 return "UNKNOWN";
145 }
146
147 static const char *qp_states_to_str(uint8_t idx)
148 {
149 static const char * const qp_states_str[] = { "RESET", "INIT",
150 "RTR", "RTS", "SQD",
151 "SQE", "ERR" };
152
153 if (idx < ARRAY_SIZE(qp_states_str))
154 return qp_states_str[idx];
155 return "UNKNOWN";
156 }
157
158 static const char *qp_types_to_str(uint8_t idx)
159 {
160 static const char * const qp_types_str[] = { "SMI", "GSI", "RC",
161 "UC", "UD", "RAW_IPV6",
162 "RAW_ETHERTYPE",
163 "UNKNOWN", "RAW_PACKET",
164 "XRC_INI", "XRC_TGT" };
165
166 if (idx < ARRAY_SIZE(qp_types_str))
167 return qp_types_str[idx];
168 return "UNKNOWN";
169 }
170
171 static void print_lqpn(struct rd *rd, uint32_t val)
172 {
173 if (rd->json_output)
174 jsonw_uint_field(rd->jw, "lqpn", val);
175 else
176 pr_out("lqpn %u ", val);
177 }
178
179 static void print_rqpn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
180 {
181 if (!nla_line[RDMA_NLDEV_ATTR_RES_RQPN])
182 return;
183
184 if (rd->json_output)
185 jsonw_uint_field(rd->jw, "rqpn", val);
186 else
187 pr_out("rqpn %u ", val);
188 }
189
190 static void print_type(struct rd *rd, uint32_t val)
191 {
192 if (rd->json_output)
193 jsonw_string_field(rd->jw, "type",
194 qp_types_to_str(val));
195 else
196 pr_out("type %s ", qp_types_to_str(val));
197 }
198
199 static void print_state(struct rd *rd, uint32_t val)
200 {
201 if (rd->json_output)
202 jsonw_string_field(rd->jw, "state",
203 qp_states_to_str(val));
204 else
205 pr_out("state %s ", qp_states_to_str(val));
206 }
207
208 static void print_rqpsn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
209 {
210 if (!nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN])
211 return;
212
213 if (rd->json_output)
214 jsonw_uint_field(rd->jw, "rq-psn", val);
215 else
216 pr_out("rq-psn %u ", val);
217 }
218
219 static void print_sqpsn(struct rd *rd, uint32_t val)
220 {
221 if (rd->json_output)
222 jsonw_uint_field(rd->jw, "sq-psn", val);
223 else
224 pr_out("sq-psn %u ", val);
225 }
226
227 static void print_pathmig(struct rd *rd, uint32_t val,
228 struct nlattr **nla_line)
229 {
230 if (!nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE])
231 return;
232
233 if (rd->json_output)
234 jsonw_string_field(rd->jw,
235 "path-mig-state",
236 path_mig_to_str(val));
237 else
238 pr_out("path-mig-state %s ", path_mig_to_str(val));
239 }
240
241 static void print_pid(struct rd *rd, uint32_t val)
242 {
243 if (rd->json_output)
244 jsonw_uint_field(rd->jw, "pid", val);
245 else
246 pr_out("pid %u ", val);
247 }
248
249 static void print_comm(struct rd *rd, const char *str,
250 struct nlattr **nla_line)
251 {
252 char tmp[18];
253
254 if (rd->json_output) {
255 /* Don't beatify output in JSON format */
256 jsonw_string_field(rd->jw, "comm", str);
257 return;
258 }
259
260 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
261 snprintf(tmp, sizeof(tmp), "%s", str);
262 else
263 snprintf(tmp, sizeof(tmp), "[%s]", str);
264
265 pr_out("comm %s ", tmp);
266 }
267
268 static void print_link(struct rd *rd, uint32_t idx, const char *name,
269 uint32_t port, struct nlattr **nla_line)
270 {
271 if (rd->json_output) {
272 jsonw_uint_field(rd->jw, "ifindex", idx);
273
274 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
275 jsonw_uint_field(rd->jw, "port", port);
276
277 jsonw_string_field(rd->jw, "ifname", name);
278 } else {
279 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
280 pr_out("link %s/%u ", name, port);
281 else
282 pr_out("link %s/- ", name);
283 }
284 }
285
286 static char *get_task_name(uint32_t pid)
287 {
288 char *comm;
289 FILE *f;
290
291 if (asprintf(&comm, "/proc/%d/comm", pid) < 0)
292 return NULL;
293
294 f = fopen(comm, "r");
295 free(comm);
296 if (!f)
297 return NULL;
298
299 if (fscanf(f, "%ms\n", &comm) != 1)
300 comm = NULL;
301
302 fclose(f);
303
304 return comm;
305 }
306
307 static int res_qp_parse_cb(const struct nlmsghdr *nlh, void *data)
308 {
309 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
310 struct nlattr *nla_table, *nla_entry;
311 struct rd *rd = data;
312 const char *name;
313 uint32_t idx;
314
315 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
316 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
317 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
318 !tb[RDMA_NLDEV_ATTR_RES_QP])
319 return MNL_CB_ERROR;
320
321 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
322 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
323 nla_table = tb[RDMA_NLDEV_ATTR_RES_QP];
324
325 mnl_attr_for_each_nested(nla_entry, nla_table) {
326 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
327 uint32_t lqpn, rqpn = 0, rq_psn = 0, sq_psn;
328 uint8_t type, state, path_mig_state = 0;
329 uint32_t port = 0, pid = 0;
330 char *comm = NULL;
331 int err;
332
333 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
334 if (err != MNL_CB_OK)
335 return MNL_CB_ERROR;
336
337 if (!nla_line[RDMA_NLDEV_ATTR_RES_LQPN] ||
338 !nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN] ||
339 !nla_line[RDMA_NLDEV_ATTR_RES_TYPE] ||
340 !nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
341 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
342 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
343 return MNL_CB_ERROR;
344 }
345
346 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
347 port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
348
349 if (port != rd->port_idx)
350 continue;
351
352 lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
353 if (rd_check_is_filtered(rd, "lqpn", lqpn))
354 continue;
355
356 if (nla_line[RDMA_NLDEV_ATTR_RES_RQPN]) {
357 rqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQPN]);
358 if (rd_check_is_filtered(rd, "rqpn", rqpn))
359 continue;
360 } else {
361 if (rd_check_is_key_exist(rd, "rqpn"))
362 continue;
363 }
364
365 if (nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]) {
366 rq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]);
367 if (rd_check_is_filtered(rd, "rq-psn", rq_psn))
368 continue;
369 } else {
370 if (rd_check_is_key_exist(rd, "rq-psn"))
371 continue;
372 }
373
374 sq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]);
375 if (rd_check_is_filtered(rd, "sq-psn", sq_psn))
376 continue;
377
378 if (nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]) {
379 path_mig_state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]);
380 if (rd_check_is_string_filtered(rd, "path-mig-state", path_mig_to_str(path_mig_state)))
381 continue;
382 } else {
383 if (rd_check_is_key_exist(rd, "path-mig-state"))
384 continue;
385 }
386
387 type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
388 if (rd_check_is_string_filtered(rd, "type", qp_types_to_str(type)))
389 continue;
390
391 state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
392 if (rd_check_is_string_filtered(rd, "state", qp_states_to_str(state)))
393 continue;
394
395 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
396 pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
397 comm = get_task_name(pid);
398 }
399
400 if (rd_check_is_filtered(rd, "pid", pid)) {
401 free(comm);
402 continue;
403 }
404
405 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
406 /* discard const from mnl_attr_get_str */
407 comm = (char *)mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
408
409 if (rd->json_output)
410 jsonw_start_array(rd->jw);
411
412 print_link(rd, idx, name, port, nla_line);
413
414 print_lqpn(rd, lqpn);
415 print_rqpn(rd, rqpn, nla_line);
416
417 print_type(rd, type);
418 print_state(rd, state);
419
420 print_rqpsn(rd, rq_psn, nla_line);
421 print_sqpsn(rd, sq_psn);
422
423 print_pathmig(rd, path_mig_state, nla_line);
424 print_pid(rd, pid);
425 print_comm(rd, comm, nla_line);
426
427 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
428 free(comm);
429
430 if (rd->json_output)
431 jsonw_end_array(rd->jw);
432 else
433 pr_out("\n");
434 }
435 return MNL_CB_OK;
436 }
437
438 static void print_qp_type(struct rd *rd, uint32_t val)
439 {
440 if (rd->json_output)
441 jsonw_string_field(rd->jw, "qp-type",
442 qp_types_to_str(val));
443 else
444 pr_out("qp-type %s ", qp_types_to_str(val));
445 }
446
447 static const char *cm_id_state_to_str(uint8_t idx)
448 {
449 static const char * const cm_id_states_str[] = {
450 "IDLE", "ADDR_QUERY", "ADDR_RESOLVED", "ROUTE_QUERY",
451 "ROUTE_RESOLVED", "CONNECT", "DISCONNECT", "ADDR_BOUND",
452 "LISTEN", "DEVICE_REMOVAL", "DESTROYING" };
453
454 if (idx < ARRAY_SIZE(cm_id_states_str))
455 return cm_id_states_str[idx];
456 return "UNKNOWN";
457 }
458
459 static const char *cm_id_ps_to_str(uint32_t ps)
460 {
461 switch (ps) {
462 case RDMA_PS_IPOIB:
463 return "IPoIB";
464 case RDMA_PS_IB:
465 return "IPoIB";
466 case RDMA_PS_TCP:
467 return "TCP";
468 case RDMA_PS_UDP:
469 return "UDP";
470 default:
471 return "---";
472 }
473 }
474
475 static void print_cm_id_state(struct rd *rd, uint8_t state)
476 {
477 if (rd->json_output) {
478 jsonw_string_field(rd->jw, "state", cm_id_state_to_str(state));
479 return;
480 }
481 pr_out("state %s ", cm_id_state_to_str(state));
482 }
483
484 static void print_ps(struct rd *rd, uint32_t ps)
485 {
486 if (rd->json_output) {
487 jsonw_string_field(rd->jw, "ps", cm_id_ps_to_str(ps));
488 return;
489 }
490 pr_out("ps %s ", cm_id_ps_to_str(ps));
491 }
492
493 static void print_ipaddr(struct rd *rd, const char *key, char *addrstr,
494 uint16_t port)
495 {
496 if (rd->json_output) {
497 int name_size = INET6_ADDRSTRLEN+strlen(":65535");
498 char json_name[name_size];
499
500 snprintf(json_name, name_size, "%s:%u", addrstr, port);
501 jsonw_string_field(rd->jw, key, json_name);
502 return;
503 }
504 pr_out("%s %s:%u ", key, addrstr, port);
505 }
506
507 static int ss_ntop(struct nlattr *nla_line, char *addr_str, uint16_t *port)
508 {
509 struct __kernel_sockaddr_storage *addr;
510
511 addr = (struct __kernel_sockaddr_storage *)
512 mnl_attr_get_payload(nla_line);
513 switch (addr->ss_family) {
514 case AF_INET: {
515 struct sockaddr_in *sin = (struct sockaddr_in *)addr;
516
517 if (!inet_ntop(AF_INET, (const void *)&sin->sin_addr, addr_str,
518 INET6_ADDRSTRLEN))
519 return -EINVAL;
520 *port = ntohs(sin->sin_port);
521 break;
522 }
523 case AF_INET6: {
524 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
525
526 if (!inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
527 addr_str, INET6_ADDRSTRLEN))
528 return -EINVAL;
529 *port = ntohs(sin6->sin6_port);
530 break;
531 }
532 default:
533 return -EINVAL;
534 }
535 return 0;
536 }
537
538 static int res_cm_id_parse_cb(const struct nlmsghdr *nlh, void *data)
539 {
540 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
541 struct nlattr *nla_table, *nla_entry;
542 struct rd *rd = data;
543 const char *name;
544 int idx;
545
546 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
547 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
548 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
549 !tb[RDMA_NLDEV_ATTR_RES_CM_ID])
550 return MNL_CB_ERROR;
551
552 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
553 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
554 nla_table = tb[RDMA_NLDEV_ATTR_RES_CM_ID];
555 mnl_attr_for_each_nested(nla_entry, nla_table) {
556 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
557 char src_addr_str[INET6_ADDRSTRLEN];
558 char dst_addr_str[INET6_ADDRSTRLEN];
559 uint16_t src_port, dst_port;
560 uint32_t port = 0, pid = 0;
561 uint8_t type = 0, state;
562 uint32_t lqpn = 0, ps;
563 char *comm = NULL;
564 int err;
565
566 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
567 if (err != MNL_CB_OK)
568 return -EINVAL;
569
570 if (!nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
571 !nla_line[RDMA_NLDEV_ATTR_RES_PS] ||
572 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
573 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
574 return MNL_CB_ERROR;
575 }
576
577 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
578 port = mnl_attr_get_u32(
579 nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
580
581 if (port && port != rd->port_idx)
582 continue;
583
584 if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN]) {
585 lqpn = mnl_attr_get_u32(
586 nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
587 if (rd_check_is_filtered(rd, "lqpn", lqpn))
588 continue;
589 }
590 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE]) {
591 type = mnl_attr_get_u8(
592 nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
593 if (rd_check_is_string_filtered(rd, "qp-type",
594 qp_types_to_str(type)))
595 continue;
596 }
597
598 ps = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PS]);
599 if (rd_check_is_string_filtered(rd, "ps", cm_id_ps_to_str(ps)))
600 continue;
601
602 state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
603 if (rd_check_is_string_filtered(rd, "state",
604 cm_id_state_to_str(state)))
605 continue;
606
607 if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR]) {
608 if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR],
609 src_addr_str, &src_port))
610 continue;
611 if (rd_check_is_string_filtered(rd, "src-addr",
612 src_addr_str))
613 continue;
614 }
615
616 if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR]) {
617 if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR],
618 dst_addr_str, &dst_port))
619 continue;
620 if (rd_check_is_string_filtered(rd, "dst-addr",
621 dst_addr_str))
622 continue;
623 }
624
625 if (rd_check_is_filtered(rd, "src-port", src_port))
626 continue;
627
628 if (rd_check_is_filtered(rd, "dst-port", dst_port))
629 continue;
630
631 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
632 pid = mnl_attr_get_u32(
633 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
634 comm = get_task_name(pid);
635 }
636
637 if (rd_check_is_filtered(rd, "pid", pid)) {
638 free(comm);
639 continue;
640 }
641
642 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) {
643 /* discard const from mnl_attr_get_str */
644 comm = (char *)mnl_attr_get_str(
645 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
646 }
647
648 if (rd->json_output)
649 jsonw_start_array(rd->jw);
650
651 print_link(rd, idx, name, port, nla_line);
652 if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
653 print_lqpn(rd, lqpn);
654 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
655 print_qp_type(rd, type);
656 print_cm_id_state(rd, state);
657 print_ps(rd, ps);
658 print_pid(rd, pid);
659 print_comm(rd, comm, nla_line);
660
661 if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
662 print_ipaddr(rd, "src-addr", src_addr_str, src_port);
663 if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
664 print_ipaddr(rd, "dst-addr", dst_addr_str, dst_port);
665
666 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
667 free(comm);
668
669 if (rd->json_output)
670 jsonw_end_array(rd->jw);
671 else
672 pr_out("\n");
673 }
674 return MNL_CB_OK;
675 }
676
677 RES_FUNC(res_no_args, RDMA_NLDEV_CMD_RES_GET, NULL, true);
678
679 static const struct
680 filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {{ .name = "link",
681 .is_number = false },
682 { .name = "lqpn",
683 .is_number = true },
684 { .name = "rqpn",
685 .is_number = true },
686 { .name = "pid",
687 .is_number = true },
688 { .name = "sq-psn",
689 .is_number = true },
690 { .name = "rq-psn",
691 .is_number = true },
692 { .name = "type",
693 .is_number = false },
694 { .name = "path-mig-state",
695 .is_number = false },
696 { .name = "state",
697 .is_number = false } };
698
699 RES_FUNC(res_qp, RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false);
700
701 static const
702 struct filters cm_id_valid_filters[MAX_NUMBER_OF_FILTERS] = {
703 { .name = "link", .is_number = false },
704 { .name = "lqpn", .is_number = true },
705 { .name = "qp-type", .is_number = false },
706 { .name = "state", .is_number = false },
707 { .name = "ps", .is_number = false },
708 { .name = "dev-type", .is_number = false },
709 { .name = "transport-type", .is_number = false },
710 { .name = "pid", .is_number = true },
711 { .name = "src-addr", .is_number = false },
712 { .name = "src-port", .is_number = true },
713 { .name = "dst-addr", .is_number = false },
714 { .name = "dst-port", .is_number = true }
715 };
716
717 RES_FUNC(res_cm_id, RDMA_NLDEV_CMD_RES_CM_ID_GET, cm_id_valid_filters, false);
718
719 static int res_show(struct rd *rd)
720 {
721 const struct rd_cmd cmds[] = {
722 { NULL, res_no_args },
723 { "qp", res_qp },
724 { "cm_id", res_cm_id },
725 { 0 }
726 };
727
728 /*
729 * Special case to support "rdma res show DEV_NAME"
730 */
731 if (rd_argc(rd) == 1 && dev_map_lookup(rd, false))
732 return rd_exec_dev(rd, _res_no_args);
733
734 return rd_exec_cmd(rd, cmds, "parameter");
735 }
736
737 int cmd_res(struct rd *rd)
738 {
739 const struct rd_cmd cmds[] = {
740 { NULL, res_show },
741 { "show", res_show },
742 { "list", res_show },
743 { "help", res_help },
744 { 0 }
745 };
746
747 return rd_exec_cmd(rd, cmds, "resource command");
748 }