]> git.proxmox.com Git - mirror_iproute2.git/blob - rdma/res.c
Merge branch 'rdma-resource-tracking' into iproute2-next
[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 }
625
626 if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR]) {
627 if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR],
628 dst_addr_str, &dst_port))
629 continue;
630 if (rd_check_is_string_filtered(rd, "dst-addr",
631 dst_addr_str))
632 continue;
633 }
634
635 if (rd_check_is_filtered(rd, "src-port", src_port))
636 continue;
637
638 if (rd_check_is_filtered(rd, "dst-port", dst_port))
639 continue;
640
641 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
642 pid = mnl_attr_get_u32(
643 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
644 comm = get_task_name(pid);
645 }
646
647 if (rd_check_is_filtered(rd, "pid", pid)) {
648 free(comm);
649 continue;
650 }
651
652 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) {
653 /* discard const from mnl_attr_get_str */
654 comm = (char *)mnl_attr_get_str(
655 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
656 }
657
658 if (rd->json_output)
659 jsonw_start_array(rd->jw);
660
661 print_link(rd, idx, name, port, nla_line);
662 if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
663 print_lqpn(rd, lqpn);
664 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
665 print_qp_type(rd, type);
666 print_cm_id_state(rd, state);
667 print_ps(rd, ps);
668 print_pid(rd, pid);
669 print_comm(rd, comm, nla_line);
670
671 if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
672 print_ipaddr(rd, "src-addr", src_addr_str, src_port);
673 if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
674 print_ipaddr(rd, "dst-addr", dst_addr_str, dst_port);
675
676 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
677 free(comm);
678
679 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
680 newline(rd);
681 }
682 return MNL_CB_OK;
683 }
684
685 static void print_cqe(struct rd *rd, uint32_t val)
686 {
687 if (rd->json_output)
688 jsonw_uint_field(rd->jw, "cqe", val);
689 else
690 pr_out("cqe %u ", val);
691 }
692
693 static void print_users(struct rd *rd, uint64_t val)
694 {
695 if (rd->json_output)
696 jsonw_uint_field(rd->jw, "users", val);
697 else
698 pr_out("users %" PRIu64 " ", val);
699 }
700
701 static const char *poll_ctx_to_str(uint8_t idx)
702 {
703 static const char * const cm_id_states_str[] = {
704 "DIRECT", "SOFTIRQ", "WORKQUEUE"};
705
706 if (idx < ARRAY_SIZE(cm_id_states_str))
707 return cm_id_states_str[idx];
708 return "UNKNOWN";
709 }
710
711 static void print_poll_ctx(struct rd *rd, uint8_t poll_ctx)
712 {
713 if (rd->json_output) {
714 jsonw_string_field(rd->jw, "poll-ctx",
715 poll_ctx_to_str(poll_ctx));
716 return;
717 }
718 pr_out("poll-ctx %s ", poll_ctx_to_str(poll_ctx));
719 }
720
721 static int res_cq_parse_cb(const struct nlmsghdr *nlh, void *data)
722 {
723 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
724 struct nlattr *nla_table, *nla_entry;
725 struct rd *rd = data;
726 const char *name;
727 uint32_t idx;
728
729 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
730 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
731 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
732 !tb[RDMA_NLDEV_ATTR_RES_CQ])
733 return MNL_CB_ERROR;
734
735 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
736 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
737 nla_table = tb[RDMA_NLDEV_ATTR_RES_CQ];
738
739 mnl_attr_for_each_nested(nla_entry, nla_table) {
740 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
741 char *comm = NULL;
742 uint32_t pid = 0;
743 uint8_t poll_ctx = 0;
744 uint64_t users;
745 uint32_t cqe;
746 int err;
747
748 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
749 if (err != MNL_CB_OK)
750 return MNL_CB_ERROR;
751
752 if (!nla_line[RDMA_NLDEV_ATTR_RES_CQE] ||
753 !nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
754 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
755 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
756 return MNL_CB_ERROR;
757 }
758
759 cqe = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQE]);
760
761 users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
762 if (rd_check_is_filtered(rd, "users", users))
763 continue;
764
765 if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]) {
766 poll_ctx = mnl_attr_get_u8(
767 nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]);
768 if (rd_check_is_string_filtered(rd, "poll-ctx",
769 poll_ctx_to_str(poll_ctx)))
770 continue;
771 }
772
773 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
774 pid = mnl_attr_get_u32(
775 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
776 comm = get_task_name(pid);
777 }
778
779 if (rd_check_is_filtered(rd, "pid", pid)) {
780 free(comm);
781 continue;
782 }
783
784 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
785 /* discard const from mnl_attr_get_str */
786 comm = (char *)mnl_attr_get_str(
787 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
788
789 if (rd->json_output)
790 jsonw_start_array(rd->jw);
791
792 print_dev(rd, idx, name);
793 print_cqe(rd, cqe);
794 print_users(rd, users);
795 if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX])
796 print_poll_ctx(rd, poll_ctx);
797 print_pid(rd, pid);
798 print_comm(rd, comm, nla_line);
799
800 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
801 free(comm);
802
803 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
804 newline(rd);
805 }
806 return MNL_CB_OK;
807 }
808
809 static void print_key(struct rd *rd, const char *name, uint32_t val)
810 {
811 if (rd->json_output)
812 jsonw_xint_field(rd->jw, name, val);
813 else
814 pr_out("%s 0x%x ", name, val);
815 }
816
817 static void print_iova(struct rd *rd, uint64_t val)
818 {
819 if (rd->json_output)
820 jsonw_xint_field(rd->jw, "iova", val);
821 else
822 pr_out("iova 0x%" PRIx64 " ", val);
823 }
824
825 static void print_mrlen(struct rd *rd, uint64_t val)
826 {
827 if (rd->json_output)
828 jsonw_uint_field(rd->jw, "mrlen", val);
829 else
830 pr_out("mrlen %" PRIu64 " ", val);
831 }
832
833 static int res_mr_parse_cb(const struct nlmsghdr *nlh, void *data)
834 {
835 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
836 struct nlattr *nla_table, *nla_entry;
837 struct rd *rd = data;
838 const char *name;
839 uint32_t idx;
840
841 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
842 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
843 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
844 !tb[RDMA_NLDEV_ATTR_RES_MR])
845 return MNL_CB_ERROR;
846
847 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
848 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
849 nla_table = tb[RDMA_NLDEV_ATTR_RES_MR];
850
851 mnl_attr_for_each_nested(nla_entry, nla_table) {
852 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
853 uint32_t rkey = 0, lkey = 0;
854 uint64_t iova = 0, mrlen;
855 char *comm = NULL;
856 uint32_t pid = 0;
857 int err;
858
859 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
860 if (err != MNL_CB_OK)
861 return MNL_CB_ERROR;
862
863 if (!nla_line[RDMA_NLDEV_ATTR_RES_MRLEN] ||
864 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
865 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
866 return MNL_CB_ERROR;
867 }
868
869 if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
870 rkey = mnl_attr_get_u32(
871 nla_line[RDMA_NLDEV_ATTR_RES_RKEY]);
872 if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
873 lkey = mnl_attr_get_u32(
874 nla_line[RDMA_NLDEV_ATTR_RES_LKEY]);
875 if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
876 iova = mnl_attr_get_u64(
877 nla_line[RDMA_NLDEV_ATTR_RES_IOVA]);
878
879 mrlen = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]);
880 if (rd_check_is_filtered(rd, "mrlen", mrlen))
881 continue;
882
883 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
884 pid = mnl_attr_get_u32(
885 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
886 comm = get_task_name(pid);
887 }
888
889 if (rd_check_is_filtered(rd, "pid", pid)) {
890 free(comm);
891 continue;
892 }
893
894 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
895 /* discard const from mnl_attr_get_str */
896 comm = (char *)mnl_attr_get_str(
897 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
898
899 if (rd->json_output)
900 jsonw_start_array(rd->jw);
901
902 print_dev(rd, idx, name);
903 if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
904 print_key(rd, "rkey", rkey);
905 if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
906 print_key(rd, "lkey", lkey);
907 if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
908 print_iova(rd, iova);
909 print_mrlen(rd, mrlen);
910 print_pid(rd, pid);
911 print_comm(rd, comm, nla_line);
912
913 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
914 free(comm);
915
916 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
917 newline(rd);
918 }
919 return MNL_CB_OK;
920 }
921
922 static int res_pd_parse_cb(const struct nlmsghdr *nlh, void *data)
923 {
924 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
925 struct nlattr *nla_table, *nla_entry;
926 struct rd *rd = data;
927 const char *name;
928 uint32_t idx;
929
930 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
931 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
932 !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
933 !tb[RDMA_NLDEV_ATTR_RES_PD])
934 return MNL_CB_ERROR;
935
936 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
937 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
938 nla_table = tb[RDMA_NLDEV_ATTR_RES_PD];
939
940 mnl_attr_for_each_nested(nla_entry, nla_table) {
941 uint32_t local_dma_lkey = 0, unsafe_global_rkey = 0;
942 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
943 char *comm = NULL;
944 uint32_t pid = 0;
945 uint64_t users;
946 int err;
947
948 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
949 if (err != MNL_CB_OK)
950 return MNL_CB_ERROR;
951
952 if (!nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
953 (!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
954 !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
955 return MNL_CB_ERROR;
956 }
957
958 if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY])
959 local_dma_lkey = mnl_attr_get_u32(
960 nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]);
961
962 users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
963 if (rd_check_is_filtered(rd, "users", users))
964 continue;
965
966 if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY])
967 unsafe_global_rkey = mnl_attr_get_u32(
968 nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]);
969
970 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
971 pid = mnl_attr_get_u32(
972 nla_line[RDMA_NLDEV_ATTR_RES_PID]);
973 comm = get_task_name(pid);
974 }
975
976 if (rd_check_is_filtered(rd, "pid", pid))
977 continue;
978
979 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
980 /* discard const from mnl_attr_get_str */
981 comm = (char *)mnl_attr_get_str(
982 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
983
984 if (rd->json_output)
985 jsonw_start_array(rd->jw);
986
987 print_dev(rd, idx, name);
988 if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY])
989 print_key(rd, "local_dma_lkey", local_dma_lkey);
990 print_users(rd, users);
991 if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY])
992 print_key(rd, "unsafe_global_rkey", unsafe_global_rkey);
993 print_pid(rd, pid);
994 print_comm(rd, comm, nla_line);
995
996 if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
997 free(comm);
998
999 print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
1000 newline(rd);
1001 }
1002 return MNL_CB_OK;
1003 }
1004
1005 RES_FUNC(res_no_args, RDMA_NLDEV_CMD_RES_GET, NULL, true);
1006
1007 static const struct
1008 filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {{ .name = "link",
1009 .is_number = false },
1010 { .name = "lqpn",
1011 .is_number = true },
1012 { .name = "rqpn",
1013 .is_number = true },
1014 { .name = "pid",
1015 .is_number = true },
1016 { .name = "sq-psn",
1017 .is_number = true },
1018 { .name = "rq-psn",
1019 .is_number = true },
1020 { .name = "type",
1021 .is_number = false },
1022 { .name = "path-mig-state",
1023 .is_number = false },
1024 { .name = "state",
1025 .is_number = false } };
1026
1027 RES_FUNC(res_qp, RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false);
1028
1029 static const
1030 struct filters cm_id_valid_filters[MAX_NUMBER_OF_FILTERS] = {
1031 { .name = "link", .is_number = false },
1032 { .name = "lqpn", .is_number = true },
1033 { .name = "qp-type", .is_number = false },
1034 { .name = "state", .is_number = false },
1035 { .name = "ps", .is_number = false },
1036 { .name = "dev-type", .is_number = false },
1037 { .name = "transport-type", .is_number = false },
1038 { .name = "pid", .is_number = true },
1039 { .name = "src-addr", .is_number = false },
1040 { .name = "src-port", .is_number = true },
1041 { .name = "dst-addr", .is_number = false },
1042 { .name = "dst-port", .is_number = true }
1043 };
1044
1045 RES_FUNC(res_cm_id, RDMA_NLDEV_CMD_RES_CM_ID_GET, cm_id_valid_filters, false);
1046
1047 static const
1048 struct filters cq_valid_filters[MAX_NUMBER_OF_FILTERS] = {
1049 { .name = "dev", .is_number = false },
1050 { .name = "users", .is_number = true },
1051 { .name = "poll-ctx", .is_number = false },
1052 { .name = "pid", .is_number = true }
1053 };
1054
1055 RES_FUNC(res_cq, RDMA_NLDEV_CMD_RES_CQ_GET, cq_valid_filters, true);
1056
1057 static const
1058 struct filters mr_valid_filters[MAX_NUMBER_OF_FILTERS] = {
1059 { .name = "dev", .is_number = false },
1060 { .name = "rkey", .is_number = true },
1061 { .name = "lkey", .is_number = true },
1062 { .name = "mrlen", .is_number = true },
1063 { .name = "pid", .is_number = true }
1064 };
1065
1066 RES_FUNC(res_mr, RDMA_NLDEV_CMD_RES_MR_GET, mr_valid_filters, true);
1067
1068 static const
1069 struct filters pd_valid_filters[MAX_NUMBER_OF_FILTERS] = {
1070 { .name = "dev", .is_number = false },
1071 { .name = "users", .is_number = true },
1072 { .name = "pid", .is_number = true }
1073 };
1074
1075 RES_FUNC(res_pd, RDMA_NLDEV_CMD_RES_PD_GET, pd_valid_filters, true);
1076
1077 static int res_show(struct rd *rd)
1078 {
1079 const struct rd_cmd cmds[] = {
1080 { NULL, res_no_args },
1081 { "qp", res_qp },
1082 { "cm_id", res_cm_id },
1083 { "cq", res_cq },
1084 { "mr", res_mr },
1085 { "pd", res_pd },
1086 { 0 }
1087 };
1088
1089 /*
1090 * Special case to support "rdma res show DEV_NAME"
1091 */
1092 if (rd_argc(rd) == 1 && dev_map_lookup(rd, false))
1093 return rd_exec_dev(rd, _res_no_args);
1094
1095 return rd_exec_cmd(rd, cmds, "parameter");
1096 }
1097
1098 int cmd_res(struct rd *rd)
1099 {
1100 const struct rd_cmd cmds[] = {
1101 { NULL, res_show },
1102 { "show", res_show },
1103 { "list", res_show },
1104 { "help", res_help },
1105 { 0 }
1106 };
1107
1108 return rd_exec_cmd(rd, cmds, "resource command");
1109 }