1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
4 * Authors: Mark Zhang <markz@mellanox.com>
11 static int stat_help(struct rd
*rd
)
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("where OBJECT: = { qp }\n");
19 pr_out(" CRITERIA : = { type }\n");
20 pr_out(" COUNTER_SCOPE: = { link | dev }\n");
21 pr_out("Examples:\n");
22 pr_out(" %s statistic qp show\n", rd
->filename
);
23 pr_out(" %s statistic qp show link mlx5_2/1\n", rd
->filename
);
24 pr_out(" %s statistic qp mode\n", rd
->filename
);
25 pr_out(" %s statistic qp mode link mlx5_0\n", rd
->filename
);
26 pr_out(" %s statistic qp set link mlx5_2/1 auto type on\n", rd
->filename
);
27 pr_out(" %s statistic qp set link mlx5_2/1 auto off\n", rd
->filename
);
32 struct counter_param
{
37 static struct counter_param auto_params
[] = {
38 { "type", RDMA_COUNTER_MASK_QP_TYPE
, },
42 static int prepare_auto_mode_str(struct nlattr
**tb
, uint32_t mask
,
43 char *output
, int len
)
46 int i
, outlen
= strlen(s
);
48 memset(output
, 0, len
);
49 snprintf(output
, len
, "%s", s
);
52 for (i
= 0; auto_params
[i
].name
!= NULL
; i
++) {
53 if (mask
& auto_params
[i
].attr
) {
54 outlen
+= strlen(auto_params
[i
].name
) + 1;
58 strcat(output
, auto_params
[i
].name
);
62 if (outlen
+ strlen(" on") >= len
)
64 strcat(output
, " on");
66 if (outlen
+ strlen(" off") >= len
)
68 strcat(output
, " off");
74 static int qp_link_get_mode_parse_cb(const struct nlmsghdr
*nlh
, void *data
)
76 struct nlattr
*tb
[RDMA_NLDEV_ATTR_MAX
] = {};
77 uint32_t mode
= 0, mask
= 0;
78 char output
[128] = {};
83 mnl_attr_parse(nlh
, 0, rd_attr_cb
, tb
);
84 if (!tb
[RDMA_NLDEV_ATTR_DEV_INDEX
] || !tb
[RDMA_NLDEV_ATTR_DEV_NAME
])
87 if (!tb
[RDMA_NLDEV_ATTR_PORT_INDEX
]) {
88 pr_err("This tool doesn't support switches yet\n");
92 idx
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_DEV_INDEX
]);
93 port
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_PORT_INDEX
]);
94 name
= mnl_attr_get_str(tb
[RDMA_NLDEV_ATTR_DEV_NAME
]);
95 if (tb
[RDMA_NLDEV_ATTR_STAT_MODE
])
96 mode
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_STAT_MODE
]);
98 if (mode
== RDMA_COUNTER_MODE_AUTO
) {
99 if (!tb
[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK
])
101 mask
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK
]);
102 prepare_auto_mode_str(tb
, mask
, output
, sizeof(output
));
104 snprintf(output
, sizeof(output
), "qp auto off");
107 if (rd
->json_output
) {
108 jsonw_uint_field(rd
->jw
, "ifindex", idx
);
109 jsonw_uint_field(rd
->jw
, "port", port
);
110 jsonw_string_field(rd
->jw
, "mode", output
);
112 pr_out("%u/%u: %s/%u: %s\n", idx
, port
, name
, port
, output
);
118 static int stat_one_qp_link_get_mode(struct rd
*rd
)
126 rd_prepare_msg(rd
, RDMA_NLDEV_CMD_STAT_GET
,
127 &seq
, (NLM_F_REQUEST
| NLM_F_ACK
));
129 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_DEV_INDEX
, rd
->dev_idx
);
130 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_PORT_INDEX
, rd
->port_idx
);
131 /* Make RDMA_NLDEV_ATTR_STAT_MODE valid so that kernel knows
132 * return only mode instead of all counters
134 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_MODE
,
135 RDMA_COUNTER_MODE_MANUAL
);
136 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_RES
, RDMA_NLDEV_ATTR_RES_QP
);
137 ret
= rd_send_msg(rd
);
142 jsonw_start_object(rd
->jw
);
143 ret
= rd_recv_msg(rd
, qp_link_get_mode_parse_cb
, rd
, seq
);
145 jsonw_end_object(rd
->jw
);
150 static int stat_qp_link_get_mode(struct rd
*rd
)
152 return rd_exec_link(rd
, stat_one_qp_link_get_mode
, false);
155 static int stat_qp_get_mode(struct rd
*rd
)
157 const struct rd_cmd cmds
[] = {
158 { NULL
, stat_qp_link_get_mode
},
159 { "link", stat_qp_link_get_mode
},
160 { "help", stat_help
},
164 return rd_exec_cmd(rd
, cmds
, "parameter");
167 static int res_get_hwcounters(struct rd
*rd
, struct nlattr
*hwc_table
, bool print
)
169 struct nlattr
*nla_entry
;
174 mnl_attr_for_each_nested(nla_entry
, hwc_table
) {
175 struct nlattr
*hw_line
[RDMA_NLDEV_ATTR_MAX
] = {};
177 err
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, hw_line
);
178 if (err
!= MNL_CB_OK
)
181 if (!hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME
] ||
182 !hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE
]) {
189 nm
= mnl_attr_get_str(hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME
]);
190 v
= mnl_attr_get_u64(hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE
]);
191 if (rd
->pretty_output
&& !rd
->json_output
)
193 res_print_uint(rd
, nm
, v
, hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME
]);
199 static int res_counter_line(struct rd
*rd
, const char *name
, int index
,
200 struct nlattr
**nla_line
)
202 uint32_t cntn
, port
= 0, pid
= 0, qpn
;
203 struct nlattr
*hwc_table
, *qp_table
;
204 struct nlattr
*nla_entry
;
205 const char *comm
= NULL
;
209 if (nla_line
[RDMA_NLDEV_ATTR_PORT_INDEX
])
210 port
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_PORT_INDEX
]);
212 hwc_table
= nla_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS
];
213 qp_table
= nla_line
[RDMA_NLDEV_ATTR_RES_QP
];
214 if (!hwc_table
|| !qp_table
||
215 !nla_line
[RDMA_NLDEV_ATTR_STAT_COUNTER_ID
])
218 cntn
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_STAT_COUNTER_ID
]);
219 if (rd_is_filtered_attr(rd
, "cntn", cntn
,
220 nla_line
[RDMA_NLDEV_ATTR_STAT_COUNTER_ID
]))
223 if (nla_line
[RDMA_NLDEV_ATTR_RES_PID
]) {
224 pid
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_RES_PID
]);
225 comm
= get_task_name(pid
);
227 if (rd_is_filtered_attr(rd
, "pid", pid
,
228 nla_line
[RDMA_NLDEV_ATTR_RES_PID
]))
231 if (nla_line
[RDMA_NLDEV_ATTR_RES_KERN_NAME
])
232 comm
= (char *)mnl_attr_get_str(
233 nla_line
[RDMA_NLDEV_ATTR_RES_KERN_NAME
]);
235 mnl_attr_for_each_nested(nla_entry
, qp_table
) {
236 struct nlattr
*qp_line
[RDMA_NLDEV_ATTR_MAX
] = {};
238 err
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, qp_line
);
239 if (err
!= MNL_CB_OK
)
242 if (!qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
])
245 qpn
= mnl_attr_get_u32(qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
]);
246 if (rd_is_filtered_attr(rd
, "lqpn", qpn
,
247 qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
]))
251 err
= res_get_hwcounters(rd
, hwc_table
, false);
252 if (err
!= MNL_CB_OK
)
255 if (rd
->json_output
) {
256 jsonw_string_field(rd
->jw
, "ifname", name
);
258 jsonw_uint_field(rd
->jw
, "port", port
);
259 jsonw_uint_field(rd
->jw
, "cntn", cntn
);
262 pr_out("link %s/%u cntn %u ", name
, port
, cntn
);
264 pr_out("dev %s cntn %u ", name
, cntn
);
267 res_print_uint(rd
, "pid", pid
, nla_line
[RDMA_NLDEV_ATTR_RES_PID
]);
268 print_comm(rd
, comm
, nla_line
);
270 res_get_hwcounters(rd
, hwc_table
, true);
273 mnl_attr_for_each_nested(nla_entry
, qp_table
) {
274 struct nlattr
*qp_line
[RDMA_NLDEV_ATTR_MAX
] = {};
276 if (isfirst
&& !rd
->json_output
)
277 pr_out("\n LQPN: <");
279 err
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, qp_line
);
280 if (err
!= MNL_CB_OK
)
283 if (!qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
])
286 qpn
= mnl_attr_get_u32(qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
]);
287 if (rd
->json_output
) {
288 jsonw_uint_field(rd
->jw
, "lqpn", qpn
);
298 if (!rd
->json_output
)
303 static int stat_qp_show_parse_cb(const struct nlmsghdr
*nlh
, void *data
)
305 struct nlattr
*tb
[RDMA_NLDEV_ATTR_MAX
] = {};
306 struct nlattr
*nla_table
, *nla_entry
;
307 struct rd
*rd
= data
;
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
])
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
];
321 mnl_attr_for_each_nested(nla_entry
, nla_table
) {
322 struct nlattr
*nla_line
[RDMA_NLDEV_ATTR_MAX
] = {};
324 ret
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, nla_line
);
325 if (ret
!= MNL_CB_OK
)
328 ret
= res_counter_line(rd
, name
, idx
, nla_line
);
329 if (ret
!= MNL_CB_OK
)
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 },
342 static int stat_qp_show_one_link(struct rd
*rd
)
344 int flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
351 ret
= rd_build_filter(rd
, stat_valid_filters
);
355 rd_prepare_msg(rd
, RDMA_NLDEV_CMD_STAT_GET
, &seq
, flags
);
356 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_DEV_INDEX
, rd
->dev_idx
);
357 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_PORT_INDEX
, rd
->port_idx
);
358 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_RES
, RDMA_NLDEV_ATTR_RES_QP
);
359 ret
= rd_send_msg(rd
);
364 jsonw_start_object(rd
->jw
);
365 ret
= rd_recv_msg(rd
, stat_qp_show_parse_cb
, rd
, seq
);
367 jsonw_end_object(rd
->jw
);
372 static int stat_qp_show_link(struct rd
*rd
)
374 return rd_exec_link(rd
, stat_qp_show_one_link
, false);
377 static int stat_qp_show(struct rd
*rd
)
379 const struct rd_cmd cmds
[] = {
380 { NULL
, stat_qp_show_link
},
381 { "link", stat_qp_show_link
},
382 { "help", stat_help
},
386 return rd_exec_cmd(rd
, cmds
, "parameter");
389 static int stat_qp_set_link_auto_sendmsg(struct rd
*rd
, uint32_t mask
)
393 rd_prepare_msg(rd
, RDMA_NLDEV_CMD_STAT_SET
,
394 &seq
, (NLM_F_REQUEST
| NLM_F_ACK
));
396 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_DEV_INDEX
, rd
->dev_idx
);
397 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_PORT_INDEX
, rd
->port_idx
);
398 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_RES
, RDMA_NLDEV_ATTR_RES_QP
);
399 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_MODE
,
400 RDMA_COUNTER_MODE_AUTO
);
401 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK
, mask
);
403 return rd_sendrecv_msg(rd
, seq
);
406 static int stat_one_qp_set_link_auto_off(struct rd
*rd
)
408 return stat_qp_set_link_auto_sendmsg(rd
, 0);
411 static int stat_one_qp_set_auto_type_on(struct rd
*rd
)
413 return stat_qp_set_link_auto_sendmsg(rd
, RDMA_COUNTER_MASK_QP_TYPE
);
416 static int stat_one_qp_set_link_auto_type(struct rd
*rd
)
418 const struct rd_cmd cmds
[] = {
420 { "on", stat_one_qp_set_auto_type_on
},
424 return rd_exec_cmd(rd
, cmds
, "parameter");
427 static int stat_one_qp_set_link_auto(struct rd
*rd
)
429 const struct rd_cmd cmds
[] = {
430 { NULL
, stat_one_qp_link_get_mode
},
431 { "off", stat_one_qp_set_link_auto_off
},
432 { "type", stat_one_qp_set_link_auto_type
},
436 return rd_exec_cmd(rd
, cmds
, "parameter");
439 static int stat_one_qp_set_link(struct rd
*rd
)
441 const struct rd_cmd cmds
[] = {
442 { NULL
, stat_one_qp_link_get_mode
},
443 { "auto", stat_one_qp_set_link_auto
},
450 return rd_exec_cmd(rd
, cmds
, "parameter");
453 static int stat_qp_set_link(struct rd
*rd
)
455 return rd_exec_link(rd
, stat_one_qp_set_link
, false);
458 static int stat_qp_set(struct rd
*rd
)
460 const struct rd_cmd cmds
[] = {
462 { "link", stat_qp_set_link
},
463 { "help", stat_help
},
467 return rd_exec_cmd(rd
, cmds
, "parameter");
470 static int stat_qp(struct rd
*rd
)
472 const struct rd_cmd cmds
[] = {
473 { NULL
, stat_qp_show
},
474 { "show", stat_qp_show
},
475 { "list", stat_qp_show
},
476 { "mode", stat_qp_get_mode
},
477 { "set", stat_qp_set
},
478 { "help", stat_help
},
482 return rd_exec_cmd(rd
, cmds
, "parameter");
485 int cmd_stat(struct rd
*rd
)
487 const struct rd_cmd cmds
[] = {
489 { "help", stat_help
},
494 return rd_exec_cmd(rd
, cmds
, "statistic command");