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