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.
9 * Authors: Leon Romanovsky <leonro@mellanox.com>
15 static int res_help(struct rd
*rd
)
17 pr_out("Usage: %s resource\n", rd
->filename
);
18 pr_out(" resource show [DEV]\n");
19 pr_out(" resource show [qp]\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");
25 static int res_print_summary(struct rd
*rd
, struct nlattr
**tb
)
27 struct nlattr
*nla_table
= tb
[RDMA_NLDEV_ATTR_RES_SUMMARY
];
28 struct nlattr
*nla_entry
;
33 mnl_attr_for_each_nested(nla_entry
, nla_table
) {
34 struct nlattr
*nla_line
[RDMA_NLDEV_ATTR_MAX
] = {};
37 err
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, nla_line
);
41 if (!nla_line
[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME
] ||
42 !nla_line
[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR
]) {
46 name
= mnl_attr_get_str(nla_line
[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME
]);
47 curr
= mnl_attr_get_u64(nla_line
[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR
]);
48 if (rd
->json_output
) {
49 snprintf(json_name
, 32, "%s", name
);
50 jsonw_lluint_field(rd
->jw
, json_name
, curr
);
52 pr_out("%s %"PRId64
" ", name
, curr
);
58 static int res_no_args_parse_cb(const struct nlmsghdr
*nlh
, void *data
)
60 struct nlattr
*tb
[RDMA_NLDEV_ATTR_MAX
] = {};
65 mnl_attr_parse(nlh
, 0, rd_attr_cb
, tb
);
66 if (!tb
[RDMA_NLDEV_ATTR_DEV_INDEX
] ||
67 !tb
[RDMA_NLDEV_ATTR_DEV_NAME
] ||
68 !tb
[RDMA_NLDEV_ATTR_RES_SUMMARY
])
71 idx
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_DEV_INDEX
]);
72 name
= mnl_attr_get_str(tb
[RDMA_NLDEV_ATTR_DEV_NAME
]);
73 if (rd
->json_output
) {
74 jsonw_uint_field(rd
->jw
, "ifindex", idx
);
75 jsonw_string_field(rd
->jw
, "ifname", name
);
77 pr_out("%u: %s: ", idx
, name
);
80 res_print_summary(rd
, tb
);
87 static int _res_send_msg(struct rd
*rd
, uint32_t command
, mnl_cb_t callback
)
89 uint32_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
93 if (command
!= RDMA_NLDEV_CMD_RES_GET
)
96 rd_prepare_msg(rd
, command
, &seq
, flags
);
97 mnl_attr_put_u32(rd
->nlh
, RDMA_NLDEV_ATTR_DEV_INDEX
, rd
->dev_idx
);
99 mnl_attr_put_u32(rd
->nlh
,
100 RDMA_NLDEV_ATTR_PORT_INDEX
, rd
->port_idx
);
102 ret
= rd_send_msg(rd
);
107 jsonw_start_object(rd
->jw
);
108 ret
= rd_recv_msg(rd
, callback
, rd
, seq
);
110 jsonw_end_object(rd
->jw
);
114 #define RES_FUNC(name, command, valid_filters, strict_port) \
115 static int _##name(struct rd *rd)\
117 return _res_send_msg(rd, command, name##_parse_cb); \
119 static int name(struct rd *rd) \
121 int ret = rd_build_filter(rd, valid_filters); \
124 if ((uintptr_t)valid_filters != (uintptr_t)NULL) { \
125 ret = rd_set_arg_to_devname(rd); \
130 return rd_exec_dev(rd, _##name); \
132 return rd_exec_link(rd, _##name, strict_port); \
135 static const char *path_mig_to_str(uint8_t idx
)
137 static const char * const path_mig_str
[] = { "MIGRATED",
140 if (idx
< ARRAY_SIZE(path_mig_str
))
141 return path_mig_str
[idx
];
145 static const char *qp_states_to_str(uint8_t idx
)
147 static const char * const qp_states_str
[] = { "RESET", "INIT",
151 if (idx
< ARRAY_SIZE(qp_states_str
))
152 return qp_states_str
[idx
];
156 static const char *qp_types_to_str(uint8_t idx
)
158 static const char * const qp_types_str
[] = { "SMI", "GSI", "RC",
159 "UC", "UD", "RAW_IPV6",
161 "UNKNOWN", "RAW_PACKET",
162 "XRC_INI", "XRC_TGT" };
164 if (idx
< ARRAY_SIZE(qp_types_str
))
165 return qp_types_str
[idx
];
169 static void print_lqpn(struct rd
*rd
, uint32_t val
)
172 jsonw_uint_field(rd
->jw
, "lqpn", val
);
174 pr_out("lqpn %u ", val
);
177 static void print_rqpn(struct rd
*rd
, uint32_t val
, struct nlattr
**nla_line
)
179 if (!nla_line
[RDMA_NLDEV_ATTR_RES_RQPN
])
183 jsonw_uint_field(rd
->jw
, "rqpn", val
);
185 pr_out("rqpn %u ", val
);
188 static void print_type(struct rd
*rd
, uint32_t val
)
191 jsonw_string_field(rd
->jw
, "type",
192 qp_types_to_str(val
));
194 pr_out("type %s ", qp_types_to_str(val
));
197 static void print_state(struct rd
*rd
, uint32_t val
)
200 jsonw_string_field(rd
->jw
, "state",
201 qp_states_to_str(val
));
203 pr_out("state %s ", qp_states_to_str(val
));
206 static void print_rqpsn(struct rd
*rd
, uint32_t val
, struct nlattr
**nla_line
)
208 if (!nla_line
[RDMA_NLDEV_ATTR_RES_RQ_PSN
])
212 jsonw_uint_field(rd
->jw
, "rq-psn", val
);
214 pr_out("rq-psn %u ", val
);
217 static void print_sqpsn(struct rd
*rd
, uint32_t val
)
220 jsonw_uint_field(rd
->jw
, "sq-psn", val
);
222 pr_out("sq-psn %u ", val
);
225 static void print_pathmig(struct rd
*rd
, uint32_t val
,
226 struct nlattr
**nla_line
)
228 if (!nla_line
[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE
])
232 jsonw_string_field(rd
->jw
,
234 path_mig_to_str(val
));
236 pr_out("path-mig-state %s ", path_mig_to_str(val
));
239 static void print_pid(struct rd
*rd
, uint32_t val
)
242 jsonw_uint_field(rd
->jw
, "pid", val
);
244 pr_out("pid %u ", val
);
247 static void print_comm(struct rd
*rd
, const char *str
,
248 struct nlattr
**nla_line
)
252 if (rd
->json_output
) {
253 /* Don't beatify output in JSON format */
254 jsonw_string_field(rd
->jw
, "comm", str
);
258 if (nla_line
[RDMA_NLDEV_ATTR_RES_PID
])
259 snprintf(tmp
, sizeof(tmp
), "%s", str
);
261 snprintf(tmp
, sizeof(tmp
), "[%s]", str
);
263 pr_out("comm %s ", tmp
);
266 static void print_link(struct rd
*rd
, uint32_t idx
, const char *name
,
267 uint32_t port
, struct nlattr
**nla_line
)
269 if (rd
->json_output
) {
270 jsonw_uint_field(rd
->jw
, "ifindex", idx
);
272 if (nla_line
[RDMA_NLDEV_ATTR_PORT_INDEX
])
273 jsonw_uint_field(rd
->jw
, "port", port
);
275 jsonw_string_field(rd
->jw
, "ifname", name
);
277 if (nla_line
[RDMA_NLDEV_ATTR_PORT_INDEX
])
278 pr_out("link %s/%u ", name
, port
);
280 pr_out("link %s/- ", name
);
284 static char *get_task_name(uint32_t pid
)
289 if (asprintf(&comm
, "/proc/%d/comm", pid
) < 0)
292 f
= fopen(comm
, "r");
297 if (fscanf(f
, "%ms\n", &comm
) != 1)
305 static int res_qp_parse_cb(const struct nlmsghdr
*nlh
, void *data
)
307 struct nlattr
*tb
[RDMA_NLDEV_ATTR_MAX
] = {};
308 struct nlattr
*nla_table
, *nla_entry
;
309 struct rd
*rd
= data
;
313 mnl_attr_parse(nlh
, 0, rd_attr_cb
, tb
);
314 if (!tb
[RDMA_NLDEV_ATTR_DEV_INDEX
] ||
315 !tb
[RDMA_NLDEV_ATTR_DEV_NAME
] ||
316 !tb
[RDMA_NLDEV_ATTR_RES_QP
])
319 name
= mnl_attr_get_str(tb
[RDMA_NLDEV_ATTR_DEV_NAME
]);
320 idx
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_DEV_INDEX
]);
321 nla_table
= tb
[RDMA_NLDEV_ATTR_RES_QP
];
323 mnl_attr_for_each_nested(nla_entry
, nla_table
) {
324 struct nlattr
*nla_line
[RDMA_NLDEV_ATTR_MAX
] = {};
325 uint32_t lqpn
, rqpn
= 0, rq_psn
= 0, sq_psn
;
326 uint8_t type
, state
, path_mig_state
= 0;
327 uint32_t port
= 0, pid
= 0;
331 err
= mnl_attr_parse_nested(nla_entry
, rd_attr_cb
, nla_line
);
332 if (err
!= MNL_CB_OK
)
335 if (!nla_line
[RDMA_NLDEV_ATTR_RES_LQPN
] ||
336 !nla_line
[RDMA_NLDEV_ATTR_RES_SQ_PSN
] ||
337 !nla_line
[RDMA_NLDEV_ATTR_RES_TYPE
] ||
338 !nla_line
[RDMA_NLDEV_ATTR_RES_STATE
] ||
339 (!nla_line
[RDMA_NLDEV_ATTR_RES_PID
] &&
340 !nla_line
[RDMA_NLDEV_ATTR_RES_KERN_NAME
])) {
344 if (nla_line
[RDMA_NLDEV_ATTR_PORT_INDEX
])
345 port
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_PORT_INDEX
]);
347 if (port
!= rd
->port_idx
)
350 lqpn
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_RES_LQPN
]);
351 if (rd_check_is_filtered(rd
, "lqpn", lqpn
))
354 if (nla_line
[RDMA_NLDEV_ATTR_RES_RQPN
]) {
355 rqpn
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_RES_RQPN
]);
356 if (rd_check_is_filtered(rd
, "rqpn", rqpn
))
359 if (rd_check_is_key_exist(rd
, "rqpn"))
363 if (nla_line
[RDMA_NLDEV_ATTR_RES_RQ_PSN
]) {
364 rq_psn
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_RES_RQ_PSN
]);
365 if (rd_check_is_filtered(rd
, "rq-psn", rq_psn
))
368 if (rd_check_is_key_exist(rd
, "rq-psn"))
372 sq_psn
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_RES_SQ_PSN
]);
373 if (rd_check_is_filtered(rd
, "sq-psn", sq_psn
))
376 if (nla_line
[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE
]) {
377 path_mig_state
= mnl_attr_get_u8(nla_line
[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE
]);
378 if (rd_check_is_string_filtered(rd
, "path-mig-state", path_mig_to_str(path_mig_state
)))
381 if (rd_check_is_key_exist(rd
, "path-mig-state"))
385 type
= mnl_attr_get_u8(nla_line
[RDMA_NLDEV_ATTR_RES_TYPE
]);
386 if (rd_check_is_string_filtered(rd
, "type", qp_types_to_str(type
)))
389 state
= mnl_attr_get_u8(nla_line
[RDMA_NLDEV_ATTR_RES_STATE
]);
390 if (rd_check_is_string_filtered(rd
, "state", qp_states_to_str(state
)))
393 if (nla_line
[RDMA_NLDEV_ATTR_RES_PID
]) {
394 pid
= mnl_attr_get_u32(nla_line
[RDMA_NLDEV_ATTR_RES_PID
]);
395 comm
= get_task_name(pid
);
398 if (rd_check_is_filtered(rd
, "pid", pid
))
401 if (nla_line
[RDMA_NLDEV_ATTR_RES_KERN_NAME
])
402 /* discard const from mnl_attr_get_str */
403 comm
= (char *)mnl_attr_get_str(nla_line
[RDMA_NLDEV_ATTR_RES_KERN_NAME
]);
406 jsonw_start_array(rd
->jw
);
408 print_link(rd
, idx
, name
, port
, nla_line
);
410 print_lqpn(rd
, lqpn
);
411 print_rqpn(rd
, rqpn
, nla_line
);
413 print_type(rd
, type
);
414 print_state(rd
, state
);
416 print_rqpsn(rd
, rq_psn
, nla_line
);
417 print_sqpsn(rd
, sq_psn
);
419 print_pathmig(rd
, path_mig_state
, nla_line
);
421 print_comm(rd
, comm
, nla_line
);
423 if (nla_line
[RDMA_NLDEV_ATTR_RES_PID
])
427 jsonw_end_array(rd
->jw
);
434 RES_FUNC(res_no_args
, RDMA_NLDEV_CMD_RES_GET
, NULL
, true);
437 filters qp_valid_filters
[MAX_NUMBER_OF_FILTERS
] = {{ .name
= "link",
438 .is_number
= false },
450 .is_number
= false },
451 { .name
= "path-mig-state",
452 .is_number
= false },
454 .is_number
= false } };
456 RES_FUNC(res_qp
, RDMA_NLDEV_CMD_RES_QP_GET
, qp_valid_filters
, false);
458 static int res_show(struct rd
*rd
)
460 const struct rd_cmd cmds
[] = {
461 { NULL
, res_no_args
},
467 * Special case to support "rdma res show DEV_NAME"
469 if (rd_argc(rd
) == 1 && dev_map_lookup(rd
, false))
470 return rd_exec_dev(rd
, _res_no_args
);
472 return rd_exec_cmd(rd
, cmds
, "parameter");
475 int cmd_res(struct rd
*rd
)
477 const struct rd_cmd cmds
[] = {
479 { "show", res_show
},
480 { "list", res_show
},
481 { "help", res_help
},
485 return rd_exec_cmd(rd
, cmds
, "resource command");