]> git.proxmox.com Git - mirror_iproute2.git/blob - rdma/stat.c
Merge git://git.kernel.org/pub/scm/network/iproute2/iproute2-next into main
[mirror_iproute2.git] / rdma / stat.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3 * rdma.c RDMA tool
4 * Authors: Mark Zhang <markz@mellanox.com>
5 */
6
7 #include "rdma.h"
8 #include "res.h"
9 #include "stat.h"
10 #include <inttypes.h>
11
12 static int stat_help(struct rd *rd)
13 {
14 pr_out("Usage: %s [ OPTIONS ] statistic { COMMAND | help }\n", rd->filename);
15 pr_out(" %s statistic OBJECT show\n", rd->filename);
16 pr_out(" %s statistic OBJECT show link [ DEV/PORT_INDEX ] [ FILTER-NAME FILTER-VALUE ]\n", rd->filename);
17 pr_out(" %s statistic OBJECT mode\n", rd->filename);
18 pr_out(" %s statistic OBJECT set COUNTER_SCOPE [DEV/PORT_INDEX] auto {CRITERIA | off}\n", rd->filename);
19 pr_out(" %s statistic OBJECT bind COUNTER_SCOPE [DEV/PORT_INDEX] [OBJECT-ID] [COUNTER-ID]\n", rd->filename);
20 pr_out(" %s statistic OBJECT unbind COUNTER_SCOPE [DEV/PORT_INDEX] [COUNTER-ID]\n", rd->filename);
21 pr_out(" %s statistic show\n", rd->filename);
22 pr_out(" %s statistic show link [ DEV/PORT_INDEX ]\n", rd->filename);
23 pr_out("where OBJECT: = { qp }\n");
24 pr_out(" CRITERIA : = { type }\n");
25 pr_out(" COUNTER_SCOPE: = { link | dev }\n");
26 pr_out(" FILTER_NAME: = { cntn | lqpn | pid }\n");
27 pr_out("Examples:\n");
28 pr_out(" %s statistic qp show\n", rd->filename);
29 pr_out(" %s statistic qp show link mlx5_2/1\n", rd->filename);
30 pr_out(" %s statistic qp mode\n", rd->filename);
31 pr_out(" %s statistic qp mode link mlx5_0\n", rd->filename);
32 pr_out(" %s statistic qp set link mlx5_2/1 auto type on\n", rd->filename);
33 pr_out(" %s statistic qp set link mlx5_2/1 auto off\n", rd->filename);
34 pr_out(" %s statistic qp bind link mlx5_2/1 lqpn 178\n", rd->filename);
35 pr_out(" %s statistic qp bind link mlx5_2/1 lqpn 178 cntn 4\n", rd->filename);
36 pr_out(" %s statistic qp unbind link mlx5_2/1 cntn 4\n", rd->filename);
37 pr_out(" %s statistic qp unbind link mlx5_2/1 cntn 4 lqpn 178\n", rd->filename);
38 pr_out(" %s statistic show\n", rd->filename);
39 pr_out(" %s statistic show link mlx5_2/1\n", rd->filename);
40
41 return 0;
42 }
43
44 struct counter_param {
45 char *name;
46 uint32_t attr;
47 };
48
49 static struct counter_param auto_params[] = {
50 { "type", RDMA_COUNTER_MASK_QP_TYPE, },
51 { "pid", RDMA_COUNTER_MASK_PID, },
52 { NULL },
53 };
54
55 static int prepare_auto_mode_str(struct nlattr **tb, uint32_t mask,
56 char *output, int len)
57 {
58 char s[] = "qp auto";
59 int i, outlen = strlen(s);
60 bool first = true;
61
62 memset(output, 0, len);
63 snprintf(output, len, "%s", s);
64
65 if (mask) {
66 for (i = 0; auto_params[i].name != NULL; i++) {
67 if (mask & auto_params[i].attr) {
68 outlen += strlen(auto_params[i].name) + 1;
69 if (outlen >= len)
70 return -EINVAL;
71 if (first) {
72 strcat(output, " ");
73 first = false;
74 } else
75 strcat(output, ",");
76
77 strcat(output, auto_params[i].name);
78 }
79 }
80
81 if (outlen + strlen(" on") >= len)
82 return -EINVAL;
83 strcat(output, " on");
84 } else {
85 if (outlen + strlen(" off") >= len)
86 return -EINVAL;
87 strcat(output, " off");
88 }
89
90 return 0;
91 }
92
93 static int qp_link_get_mode_parse_cb(const struct nlmsghdr *nlh, void *data)
94 {
95 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
96 uint32_t mode = 0, mask = 0;
97 char output[128] = {};
98 struct rd *rd = data;
99 uint32_t idx, port;
100 const char *name;
101
102 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
103 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
104 return MNL_CB_ERROR;
105
106 if (!tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
107 pr_err("This tool doesn't support switches yet\n");
108 return MNL_CB_ERROR;
109 }
110
111 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
112 port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
113 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
114 if (tb[RDMA_NLDEV_ATTR_STAT_MODE])
115 mode = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_STAT_MODE]);
116
117 if (mode == RDMA_COUNTER_MODE_AUTO) {
118 if (!tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK])
119 return MNL_CB_ERROR;
120 mask = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK]);
121 prepare_auto_mode_str(tb, mask, output, sizeof(output));
122 } else {
123 snprintf(output, sizeof(output), "qp auto off");
124 }
125
126 open_json_object(NULL);
127 print_link(rd, idx, name, port, tb);
128 print_color_string(PRINT_ANY, COLOR_NONE, "mode", "mode %s ", output);
129 newline(rd);
130 return MNL_CB_OK;
131 }
132
133 static int stat_one_qp_link_get_mode(struct rd *rd)
134 {
135 uint32_t seq;
136 int ret;
137
138 if (!rd->port_idx)
139 return 0;
140
141 rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_GET,
142 &seq, (NLM_F_REQUEST | NLM_F_ACK));
143
144 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
145 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
146 /* Make RDMA_NLDEV_ATTR_STAT_MODE valid so that kernel knows
147 * return only mode instead of all counters
148 */
149 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
150 RDMA_COUNTER_MODE_MANUAL);
151 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
152 ret = rd_send_msg(rd);
153 if (ret)
154 return ret;
155
156 ret = rd_recv_msg(rd, qp_link_get_mode_parse_cb, rd, seq);
157 return ret;
158 }
159
160 static int stat_qp_link_get_mode(struct rd *rd)
161 {
162 return rd_exec_link(rd, stat_one_qp_link_get_mode, false);
163 }
164
165 static int stat_qp_get_mode(struct rd *rd)
166 {
167 const struct rd_cmd cmds[] = {
168 { NULL, stat_qp_link_get_mode },
169 { "link", stat_qp_link_get_mode },
170 { "help", stat_help },
171 { 0 }
172 };
173
174 return rd_exec_cmd(rd, cmds, "parameter");
175 }
176
177 int res_get_hwcounters(struct rd *rd, struct nlattr *hwc_table, bool print)
178 {
179 struct nlattr *nla_entry;
180 const char *nm;
181 uint64_t v;
182 int err;
183
184 mnl_attr_for_each_nested(nla_entry, hwc_table) {
185 struct nlattr *hw_line[RDMA_NLDEV_ATTR_MAX] = {};
186
187 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, hw_line);
188 if (err != MNL_CB_OK)
189 return -EINVAL;
190
191 if (!hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME] ||
192 !hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE]) {
193 return -EINVAL;
194 }
195
196 if (!print)
197 continue;
198
199 nm = mnl_attr_get_str(hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME]);
200 v = mnl_attr_get_u64(hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE]);
201 if (rd->pretty_output && !rd->json_output)
202 newline_indent(rd);
203 res_print_uint(rd, nm, v, hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME]);
204 }
205
206 return MNL_CB_OK;
207 }
208
209 static int res_counter_line(struct rd *rd, const char *name, int index,
210 struct nlattr **nla_line)
211 {
212 uint32_t cntn, port = 0, pid = 0, qpn, qp_type = 0;
213 struct nlattr *hwc_table, *qp_table;
214 struct nlattr *nla_entry;
215 const char *comm = NULL;
216 bool isfirst;
217 int err;
218
219 if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
220 port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
221
222 hwc_table = nla_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS];
223 qp_table = nla_line[RDMA_NLDEV_ATTR_RES_QP];
224 if (!hwc_table || !qp_table ||
225 !nla_line[RDMA_NLDEV_ATTR_STAT_COUNTER_ID])
226 return MNL_CB_ERROR;
227
228 cntn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]);
229 if (rd_is_filtered_attr(rd, "cntn", cntn,
230 nla_line[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]))
231 return MNL_CB_OK;
232
233 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
234 qp_type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
235
236 if (rd_is_string_filtered_attr(rd, "qp-type", qp_types_to_str(qp_type),
237 nla_line[RDMA_NLDEV_ATTR_RES_TYPE]))
238 return MNL_CB_OK;
239
240 if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
241 pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
242 comm = get_task_name(pid);
243 }
244 if (rd_is_filtered_attr(rd, "pid", pid,
245 nla_line[RDMA_NLDEV_ATTR_RES_PID]))
246 return MNL_CB_OK;
247
248 if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
249 comm = (char *)mnl_attr_get_str(
250 nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
251
252 mnl_attr_for_each_nested(nla_entry, qp_table) {
253 struct nlattr *qp_line[RDMA_NLDEV_ATTR_MAX] = {};
254
255 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, qp_line);
256 if (err != MNL_CB_OK)
257 return -EINVAL;
258
259 if (!qp_line[RDMA_NLDEV_ATTR_RES_LQPN])
260 return -EINVAL;
261
262 qpn = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_RES_LQPN]);
263 if (rd_is_filtered_attr(rd, "lqpn", qpn,
264 qp_line[RDMA_NLDEV_ATTR_RES_LQPN]))
265 return MNL_CB_OK;
266 }
267
268 err = res_get_hwcounters(rd, hwc_table, false);
269 if (err != MNL_CB_OK)
270 return err;
271 open_json_object(NULL);
272 print_link(rd, index, name, port, nla_line);
273 print_color_uint(PRINT_ANY, COLOR_NONE, "cntn", "cntn %u ", cntn);
274 if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
275 print_qp_type(rd, qp_type);
276 res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
277 print_comm(rd, comm, nla_line);
278 res_get_hwcounters(rd, hwc_table, true);
279 isfirst = true;
280 open_json_array(PRINT_JSON, "lqpn");
281 print_color_string(PRINT_FP, COLOR_NONE, NULL, "\n LQPN: <", NULL);
282 mnl_attr_for_each_nested(nla_entry, qp_table) {
283 struct nlattr *qp_line[RDMA_NLDEV_ATTR_MAX] = {};
284 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, qp_line);
285 if (err != MNL_CB_OK)
286 return -EINVAL;
287
288 if (!qp_line[RDMA_NLDEV_ATTR_RES_LQPN])
289 return -EINVAL;
290
291 qpn = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_RES_LQPN]);
292 if (!isfirst)
293 print_color_string(PRINT_FP, COLOR_NONE, NULL, ",",
294 NULL);
295 print_color_uint(PRINT_ANY, COLOR_NONE, NULL, "%d", qpn);
296 isfirst = false;
297 }
298 close_json_array(PRINT_ANY, ">");
299 newline(rd);
300 return MNL_CB_OK;
301 }
302
303 static int stat_qp_show_parse_cb(const struct nlmsghdr *nlh, void *data)
304 {
305 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
306 struct nlattr *nla_table, *nla_entry;
307 struct rd *rd = data;
308 const char *name;
309 uint32_t idx;
310 int ret;
311
312 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
313 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
314 !tb[RDMA_NLDEV_ATTR_STAT_COUNTER])
315 return MNL_CB_ERROR;
316
317 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
318 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
319 nla_table = tb[RDMA_NLDEV_ATTR_STAT_COUNTER];
320
321 mnl_attr_for_each_nested(nla_entry, nla_table) {
322 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
323
324 ret = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
325 if (ret != MNL_CB_OK)
326 break;
327
328 ret = res_counter_line(rd, name, idx, nla_line);
329 if (ret != MNL_CB_OK)
330 break;
331 }
332
333 return ret;
334 }
335
336 static const struct filters stat_valid_filters[MAX_NUMBER_OF_FILTERS] = {
337 { .name = "cntn", .is_number = true },
338 { .name = "lqpn", .is_number = true },
339 { .name = "pid", .is_number = true },
340 { .name = "qp-type", .is_number = false },
341 };
342
343 static int stat_qp_show_one_link(struct rd *rd)
344 {
345 int flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
346 uint32_t seq;
347 int ret;
348
349 if (!rd->port_idx)
350 return 0;
351
352 ret = rd_build_filter(rd, stat_valid_filters);
353 if (ret)
354 return ret;
355
356 rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_GET, &seq, flags);
357 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
358 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
359 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
360 ret = rd_send_msg(rd);
361 if (ret)
362 return ret;
363
364 ret = rd_recv_msg(rd, stat_qp_show_parse_cb, rd, seq);
365 return ret;
366 }
367
368 static int stat_qp_show_link(struct rd *rd)
369 {
370 return rd_exec_link(rd, stat_qp_show_one_link, false);
371 }
372
373 static int stat_qp_show(struct rd *rd)
374 {
375 const struct rd_cmd cmds[] = {
376 { NULL, stat_qp_show_link },
377 { "link", stat_qp_show_link },
378 { "help", stat_help },
379 { 0 }
380 };
381
382 return rd_exec_cmd(rd, cmds, "parameter");
383 }
384
385 static int stat_qp_set_link_auto_sendmsg(struct rd *rd, uint32_t mask)
386 {
387 uint32_t seq;
388
389 rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_SET,
390 &seq, (NLM_F_REQUEST | NLM_F_ACK));
391
392 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
393 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
394 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
395 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
396 RDMA_COUNTER_MODE_AUTO);
397 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, mask);
398
399 return rd_sendrecv_msg(rd, seq);
400 }
401
402 static int stat_get_auto_mode_mask(struct rd *rd)
403 {
404 char *modes = rd_argv(rd), *mode, *saved_ptr;
405 const char *delim = ",";
406 int mask = 0, found, i;
407
408 if (!modes)
409 return mask;
410
411 mode = strtok_r(modes, delim, &saved_ptr);
412 do {
413 if (!mode)
414 break;
415
416 found = false;
417 for (i = 0; auto_params[i].name != NULL; i++) {
418 if (!strcmp(mode, auto_params[i].name)) {
419 mask |= auto_params[i].attr;
420 found = true;
421 break;
422 }
423 }
424
425 if (!found) {
426 pr_err("Unknown auto mode '%s'.\n", mode);
427 mask = 0;
428 break;
429 }
430
431 mode = strtok_r(NULL, delim, &saved_ptr);
432 } while(1);
433
434 if (mask)
435 rd_arg_inc(rd);
436
437 return mask;
438 }
439
440 static int stat_one_qp_set_link_auto(struct rd *rd)
441 {
442 int auto_mask = 0;
443
444 if (!rd_argc(rd))
445 return -EINVAL;
446
447 if (!strcmpx(rd_argv(rd), "off")) {
448 rd_arg_inc(rd);
449 return stat_qp_set_link_auto_sendmsg(rd, 0);
450 }
451
452 auto_mask = stat_get_auto_mode_mask(rd);
453 if (!auto_mask || !rd_argc(rd))
454 return -EINVAL;
455
456 if (!strcmpx(rd_argv(rd), "on")) {
457 rd_arg_inc(rd);
458 return stat_qp_set_link_auto_sendmsg(rd, auto_mask);
459 } else {
460 pr_err("Unknown parameter '%s'.\n", rd_argv(rd));
461 return -EINVAL;
462 }
463 }
464
465 static int stat_one_qp_set_link(struct rd *rd)
466 {
467 const struct rd_cmd cmds[] = {
468 { NULL, stat_one_qp_link_get_mode },
469 { "auto", stat_one_qp_set_link_auto },
470 { 0 }
471 };
472
473 if (!rd->port_idx)
474 return 0;
475
476 return rd_exec_cmd(rd, cmds, "parameter");
477 }
478
479 static int stat_qp_set_link(struct rd *rd)
480 {
481 return rd_exec_link(rd, stat_one_qp_set_link, false);
482 }
483
484 static int stat_qp_set(struct rd *rd)
485 {
486 const struct rd_cmd cmds[] = {
487 { NULL, stat_help },
488 { "link", stat_qp_set_link },
489 { "help", stat_help },
490 { 0 }
491 };
492
493 return rd_exec_cmd(rd, cmds, "parameter");
494 }
495
496 static int stat_get_arg(struct rd *rd, const char *arg)
497 {
498 int value = 0;
499 char *endp;
500
501 if (strcmpx(rd_argv(rd), arg) != 0)
502 return -EINVAL;
503
504 rd_arg_inc(rd);
505 value = strtol(rd_argv(rd), &endp, 10);
506 rd_arg_inc(rd);
507
508 return value;
509 }
510
511 static int stat_one_qp_bind(struct rd *rd)
512 {
513 int lqpn = 0, cntn = 0, ret;
514 uint32_t seq;
515
516 if (rd_no_arg(rd)) {
517 stat_help(rd);
518 return -EINVAL;
519 }
520
521 ret = rd_build_filter(rd, stat_valid_filters);
522 if (ret)
523 return ret;
524
525 lqpn = stat_get_arg(rd, "lqpn");
526
527 rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_SET,
528 &seq, (NLM_F_REQUEST | NLM_F_ACK));
529
530 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
531 RDMA_COUNTER_MODE_MANUAL);
532
533 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
534 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
535 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
536 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_RES_LQPN, lqpn);
537
538 if (rd_argc(rd)) {
539 cntn = stat_get_arg(rd, "cntn");
540 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_COUNTER_ID,
541 cntn);
542 }
543
544 return rd_sendrecv_msg(rd, seq);
545 }
546
547 static int do_stat_qp_unbind_lqpn(struct rd *rd, uint32_t cntn, uint32_t lqpn)
548 {
549 uint32_t seq;
550
551 rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_DEL,
552 &seq, (NLM_F_REQUEST | NLM_F_ACK));
553
554 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
555 RDMA_COUNTER_MODE_MANUAL);
556 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
557 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
558 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
559 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, cntn);
560 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_RES_LQPN, lqpn);
561
562 return rd_sendrecv_msg(rd, seq);
563 }
564
565 static int stat_get_counter_parse_cb(const struct nlmsghdr *nlh, void *data)
566 {
567 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
568 struct nlattr *nla_table, *nla_entry;
569 struct rd *rd = data;
570 uint32_t lqpn, cntn;
571 int err;
572
573 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
574
575 if (!tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID])
576 return MNL_CB_ERROR;
577 cntn = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]);
578
579 nla_table = tb[RDMA_NLDEV_ATTR_RES_QP];
580 if (!nla_table)
581 return MNL_CB_ERROR;
582
583 mnl_attr_for_each_nested(nla_entry, nla_table) {
584 struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
585
586 err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
587 if (err != MNL_CB_OK)
588 return -EINVAL;
589
590 if (!nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
591 return -EINVAL;
592
593 lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
594 err = do_stat_qp_unbind_lqpn(rd, cntn, lqpn);
595 if (err)
596 return MNL_CB_ERROR;
597 }
598
599 return MNL_CB_OK;
600 }
601
602 static int stat_one_qp_unbind(struct rd *rd)
603 {
604 int flags = NLM_F_REQUEST | NLM_F_ACK, ret;
605 char buf[MNL_SOCKET_BUFFER_SIZE];
606 int lqpn = 0, cntn = 0;
607 unsigned int portid;
608 uint32_t seq;
609
610 ret = rd_build_filter(rd, stat_valid_filters);
611 if (ret)
612 return ret;
613
614 cntn = stat_get_arg(rd, "cntn");
615 if (rd_argc(rd)) {
616 lqpn = stat_get_arg(rd, "lqpn");
617 return do_stat_qp_unbind_lqpn(rd, cntn, lqpn);
618 }
619
620 rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_GET, &seq, flags);
621 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
622 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
623 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
624 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, cntn);
625 ret = rd_send_msg(rd);
626 if (ret)
627 return ret;
628
629
630 /* Can't use rd_recv_msg() since the callback also calls it (recursively),
631 * then rd_recv_msg() always return -1 here
632 */
633 portid = mnl_socket_get_portid(rd->nl);
634 ret = mnl_socket_recvfrom(rd->nl, buf, sizeof(buf));
635 if (ret <= 0)
636 return ret;
637
638 ret = mnl_cb_run(buf, ret, seq, portid, stat_get_counter_parse_cb, rd);
639 mnl_socket_close(rd->nl);
640 if (ret != MNL_CB_OK)
641 return ret;
642
643 return 0;
644 }
645
646 static int stat_qp_bind_link(struct rd *rd)
647 {
648 return rd_exec_link(rd, stat_one_qp_bind, true);
649 }
650
651 static int stat_qp_bind(struct rd *rd)
652 {
653 const struct rd_cmd cmds[] = {
654 { NULL, stat_help },
655 { "link", stat_qp_bind_link },
656 { "help", stat_help },
657 { 0 },
658 };
659
660 return rd_exec_cmd(rd, cmds, "parameter");
661 }
662
663 static int stat_qp_unbind_link(struct rd *rd)
664 {
665 return rd_exec_link(rd, stat_one_qp_unbind, true);
666 }
667
668 static int stat_qp_unbind(struct rd *rd)
669 {
670 const struct rd_cmd cmds[] = {
671 { NULL, stat_help },
672 { "link", stat_qp_unbind_link },
673 { "help", stat_help },
674 { 0 },
675 };
676
677 return rd_exec_cmd(rd, cmds, "parameter");
678 }
679
680 static int stat_qp(struct rd *rd)
681 {
682 const struct rd_cmd cmds[] = {
683 { NULL, stat_qp_show },
684 { "show", stat_qp_show },
685 { "list", stat_qp_show },
686 { "mode", stat_qp_get_mode },
687 { "set", stat_qp_set },
688 { "bind", stat_qp_bind },
689 { "unbind", stat_qp_unbind },
690 { "help", stat_help },
691 { 0 }
692 };
693
694 return rd_exec_cmd(rd, cmds, "parameter");
695 }
696
697 static int stat_show_parse_cb(const struct nlmsghdr *nlh, void *data)
698 {
699 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
700 struct rd *rd = data;
701 const char *name;
702 uint32_t port;
703 int ret;
704
705 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
706 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
707 !tb[RDMA_NLDEV_ATTR_PORT_INDEX] ||
708 !tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS])
709 return MNL_CB_ERROR;
710
711 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
712 port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
713 open_json_object(NULL);
714 print_color_string(PRINT_ANY, COLOR_NONE, "ifname", "link %s/", name);
715 print_color_uint(PRINT_ANY, COLOR_NONE, "port", "%u ", port);
716 ret = res_get_hwcounters(rd, tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS], true);
717
718 newline(rd);
719 return ret;
720 }
721
722 static int stat_show_one_link(struct rd *rd)
723 {
724 int flags = NLM_F_REQUEST | NLM_F_ACK;
725 uint32_t seq;
726 int ret;
727
728 if (!rd->port_idx)
729 return 0;
730
731 rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_GET, &seq, flags);
732 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
733 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
734 ret = rd_send_msg(rd);
735 if (ret)
736 return ret;
737
738 return rd_recv_msg(rd, stat_show_parse_cb, rd, seq);
739 }
740
741 static int stat_show_link(struct rd *rd)
742 {
743 return rd_exec_link(rd, stat_show_one_link, false);
744 }
745
746 static int stat_show(struct rd *rd)
747 {
748 const struct rd_cmd cmds[] = {
749 { NULL, stat_show_link },
750 { "link", stat_show_link },
751 { "mr", stat_mr },
752 { "help", stat_help },
753 { 0 }
754 };
755
756 return rd_exec_cmd(rd, cmds, "parameter");
757 }
758
759 int cmd_stat(struct rd *rd)
760 {
761 const struct rd_cmd cmds[] = {
762 { NULL, stat_show },
763 { "show", stat_show },
764 { "list", stat_show },
765 { "help", stat_help },
766 { "qp", stat_qp },
767 { "mr", stat_mr },
768 { 0 }
769 };
770
771 return rd_exec_cmd(rd, cmds, "statistic command");
772 }