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("where OBJECT: = { qp }\n");
18 pr_out("Examples:\n");
19 pr_out(" %s statistic qp show\n", rd
->filename
);
20 pr_out(" %s statistic qp show link mlx5_2/1\n", rd
->filename
);
21 pr_out(" %s statistic qp mode\n", rd
->filename
);
22 pr_out(" %s statistic qp mode link mlx5_0\n", rd
->filename
);
27 struct counter_param
{
32 static struct counter_param auto_params
[] = {
33 { "type", RDMA_COUNTER_MASK_QP_TYPE
, },
37 static int prepare_auto_mode_str(struct nlattr
**tb
, uint32_t mask
,
38 char *output
, int len
)
41 int i
, outlen
= strlen(s
);
43 memset(output
, 0, len
);
44 snprintf(output
, len
, "%s", s
);
47 for (i
= 0; auto_params
[i
].name
!= NULL
; i
++) {
48 if (mask
& auto_params
[i
].attr
) {
49 outlen
+= strlen(auto_params
[i
].name
) + 1;
53 strcat(output
, auto_params
[i
].name
);
57 if (outlen
+ strlen(" on") >= len
)
59 strcat(output
, " on");
61 if (outlen
+ strlen(" off") >= len
)
63 strcat(output
, " off");
69 static int qp_link_get_mode_parse_cb(const struct nlmsghdr
*nlh
, void *data
)
71 struct nlattr
*tb
[RDMA_NLDEV_ATTR_MAX
] = {};
72 uint32_t mode
= 0, mask
= 0;
73 char output
[128] = {};
78 mnl_attr_parse(nlh
, 0, rd_attr_cb
, tb
);
79 if (!tb
[RDMA_NLDEV_ATTR_DEV_INDEX
] || !tb
[RDMA_NLDEV_ATTR_DEV_NAME
])
82 if (!tb
[RDMA_NLDEV_ATTR_PORT_INDEX
]) {
83 pr_err("This tool doesn't support switches yet\n");
87 idx
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_DEV_INDEX
]);
88 port
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_PORT_INDEX
]);
89 name
= mnl_attr_get_str(tb
[RDMA_NLDEV_ATTR_DEV_NAME
]);
90 if (tb
[RDMA_NLDEV_ATTR_STAT_MODE
])
91 mode
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_STAT_MODE
]);
93 if (mode
== RDMA_COUNTER_MODE_AUTO
) {
94 if (!tb
[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK
])
96 mask
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK
]);
97 prepare_auto_mode_str(tb
, mask
, output
, sizeof(output
));
99 snprintf(output
, sizeof(output
), "qp auto off");
102 if (rd
->json_output
) {
103 jsonw_uint_field(rd
->jw
, "ifindex", idx
);
104 jsonw_uint_field(rd
->jw
, "port", port
);
105 jsonw_string_field(rd
->jw
, "mode", output
);
107 pr_out("%u/%u: %s/%u: %s\n", idx
, port
, name
, port
, output
);
113 static int stat_one_qp_link_get_mode(struct rd
*rd
)
121 rd_prepare_msg(rd
, RDMA_NLDEV_CMD_STAT_GET
,
122 &seq
, (NLM_F_REQUEST
| NLM_F_ACK
));
124 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_DEV_INDEX
, rd
->dev_idx
);
125 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_PORT_INDEX
, rd
->port_idx
);
126 /* Make RDMA_NLDEV_ATTR_STAT_MODE valid so that kernel knows
127 * return only mode instead of all counters
129 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_MODE
,
130 RDMA_COUNTER_MODE_MANUAL
);
131 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_RES
, RDMA_NLDEV_ATTR_RES_QP
);
132 ret
= rd_send_msg(rd
);
137 jsonw_start_object(rd
->jw
);
138 ret
= rd_recv_msg(rd
, qp_link_get_mode_parse_cb
, rd
, seq
);
140 jsonw_end_object(rd
->jw
);
145 static int stat_qp_link_get_mode(struct rd
*rd
)
147 return rd_exec_link(rd
, stat_one_qp_link_get_mode
, false);
150 static int stat_qp_get_mode(struct rd
*rd
)
152 const struct rd_cmd cmds
[] = {
153 { NULL
, stat_qp_link_get_mode
},
154 { "link", stat_qp_link_get_mode
},
155 { "help", stat_help
},
159 return rd_exec_cmd(rd
, cmds
, "parameter");
162 static int res_get_hwcounters(struct rd
*rd
, struct nlattr
*hwc_table
, bool print
)
164 struct nlattr
*nla_entry
;
169 mnl_attr_for_each_nested(nla_entry
, hwc_table
) {
170 struct nlattr
*hw_line
[RDMA_NLDEV_ATTR_MAX
] = {};
172 err
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, hw_line
);
173 if (err
!= MNL_CB_OK
)
176 if (!hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME
] ||
177 !hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE
]) {
184 nm
= mnl_attr_get_str(hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME
]);
185 v
= mnl_attr_get_u64(hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE
]);
186 if (rd
->pretty_output
&& !rd
->json_output
)
188 res_print_uint(rd
, nm
, v
, hw_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME
]);
194 static int res_counter_line(struct rd
*rd
, const char *name
, int index
,
195 struct nlattr
**nla_line
)
197 uint32_t cntn
, port
= 0, pid
= 0, qpn
;
198 struct nlattr
*hwc_table
, *qp_table
;
199 struct nlattr
*nla_entry
;
200 const char *comm
= NULL
;
204 if (nla_line
[RDMA_NLDEV_ATTR_PORT_INDEX
])
205 port
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_PORT_INDEX
]);
207 hwc_table
= nla_line
[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS
];
208 qp_table
= nla_line
[RDMA_NLDEV_ATTR_RES_QP
];
209 if (!hwc_table
|| !qp_table
||
210 !nla_line
[RDMA_NLDEV_ATTR_STAT_COUNTER_ID
])
213 cntn
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_STAT_COUNTER_ID
]);
214 if (rd_is_filtered_attr(rd
, "cntn", cntn
,
215 nla_line
[RDMA_NLDEV_ATTR_STAT_COUNTER_ID
]))
218 if (nla_line
[RDMA_NLDEV_ATTR_RES_PID
]) {
219 pid
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_RES_PID
]);
220 comm
= get_task_name(pid
);
222 if (rd_is_filtered_attr(rd
, "pid", pid
,
223 nla_line
[RDMA_NLDEV_ATTR_RES_PID
]))
226 if (nla_line
[RDMA_NLDEV_ATTR_RES_KERN_NAME
])
227 comm
= (char *)mnl_attr_get_str(
228 nla_line
[RDMA_NLDEV_ATTR_RES_KERN_NAME
]);
230 mnl_attr_for_each_nested(nla_entry
, qp_table
) {
231 struct nlattr
*qp_line
[RDMA_NLDEV_ATTR_MAX
] = {};
233 err
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, qp_line
);
234 if (err
!= MNL_CB_OK
)
237 if (!qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
])
240 qpn
= mnl_attr_get_u32(qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
]);
241 if (rd_is_filtered_attr(rd
, "lqpn", qpn
,
242 qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
]))
246 err
= res_get_hwcounters(rd
, hwc_table
, false);
247 if (err
!= MNL_CB_OK
)
250 if (rd
->json_output
) {
251 jsonw_string_field(rd
->jw
, "ifname", name
);
253 jsonw_uint_field(rd
->jw
, "port", port
);
254 jsonw_uint_field(rd
->jw
, "cntn", cntn
);
257 pr_out("link %s/%u cntn %u ", name
, port
, cntn
);
259 pr_out("dev %s cntn %u ", name
, cntn
);
262 res_print_uint(rd
, "pid", pid
, nla_line
[RDMA_NLDEV_ATTR_RES_PID
]);
263 print_comm(rd
, comm
, nla_line
);
265 res_get_hwcounters(rd
, hwc_table
, true);
268 mnl_attr_for_each_nested(nla_entry
, qp_table
) {
269 struct nlattr
*qp_line
[RDMA_NLDEV_ATTR_MAX
] = {};
271 if (isfirst
&& !rd
->json_output
)
272 pr_out("\n LQPN: <");
274 err
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, qp_line
);
275 if (err
!= MNL_CB_OK
)
278 if (!qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
])
281 qpn
= mnl_attr_get_u32(qp_line
[RDMA_NLDEV_ATTR_RES_LQPN
]);
282 if (rd
->json_output
) {
283 jsonw_uint_field(rd
->jw
, "lqpn", qpn
);
293 if (!rd
->json_output
)
298 static int stat_qp_show_parse_cb(const struct nlmsghdr
*nlh
, void *data
)
300 struct nlattr
*tb
[RDMA_NLDEV_ATTR_MAX
] = {};
301 struct nlattr
*nla_table
, *nla_entry
;
302 struct rd
*rd
= data
;
307 mnl_attr_parse(nlh
, 0, rd_attr_cb
, tb
);
308 if (!tb
[RDMA_NLDEV_ATTR_DEV_INDEX
] || !tb
[RDMA_NLDEV_ATTR_DEV_NAME
] ||
309 !tb
[RDMA_NLDEV_ATTR_STAT_COUNTER
])
312 name
= mnl_attr_get_str(tb
[RDMA_NLDEV_ATTR_DEV_NAME
]);
313 idx
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_DEV_INDEX
]);
314 nla_table
= tb
[RDMA_NLDEV_ATTR_STAT_COUNTER
];
316 mnl_attr_for_each_nested(nla_entry
, nla_table
) {
317 struct nlattr
*nla_line
[RDMA_NLDEV_ATTR_MAX
] = {};
319 ret
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, nla_line
);
320 if (ret
!= MNL_CB_OK
)
323 ret
= res_counter_line(rd
, name
, idx
, nla_line
);
324 if (ret
!= MNL_CB_OK
)
331 static const struct filters stat_valid_filters
[MAX_NUMBER_OF_FILTERS
] = {
332 { .name
= "cntn", .is_number
= true },
333 { .name
= "lqpn", .is_number
= true },
334 { .name
= "pid", .is_number
= true },
337 static int stat_qp_show_one_link(struct rd
*rd
)
339 int flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
346 ret
= rd_build_filter(rd
, stat_valid_filters
);
350 rd_prepare_msg(rd
, RDMA_NLDEV_CMD_STAT_GET
, &seq
, flags
);
351 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_DEV_INDEX
, rd
->dev_idx
);
352 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_PORT_INDEX
, rd
->port_idx
);
353 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_STAT_RES
, RDMA_NLDEV_ATTR_RES_QP
);
354 ret
= rd_send_msg(rd
);
359 jsonw_start_object(rd
->jw
);
360 ret
= rd_recv_msg(rd
, stat_qp_show_parse_cb
, rd
, seq
);
362 jsonw_end_object(rd
->jw
);
367 static int stat_qp_show_link(struct rd
*rd
)
369 return rd_exec_link(rd
, stat_qp_show_one_link
, false);
372 static int stat_qp_show(struct rd
*rd
)
374 const struct rd_cmd cmds
[] = {
375 { NULL
, stat_qp_show_link
},
376 { "link", stat_qp_show_link
},
377 { "help", stat_help
},
381 return rd_exec_cmd(rd
, cmds
, "parameter");
384 static int stat_qp(struct rd
*rd
)
386 const struct rd_cmd cmds
[] = {
387 { NULL
, stat_qp_show
},
388 { "show", stat_qp_show
},
389 { "list", stat_qp_show
},
390 { "mode", stat_qp_get_mode
},
391 { "help", stat_help
},
395 return rd_exec_cmd(rd
, cmds
, "parameter");
398 int cmd_stat(struct rd
*rd
)
400 const struct rd_cmd cmds
[] = {
402 { "help", stat_help
},
407 return rd_exec_cmd(rd
, cmds
, "statistic command");