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 int rd_argc(struct rd
*rd
)
20 char *rd_argv(struct rd
*rd
)
27 int strcmpx(const char *str1
, const char *str2
)
29 if (strlen(str1
) > strlen(str2
))
31 return strncmp(str1
, str2
, strlen(str1
));
34 static bool rd_argv_match(struct rd
*rd
, const char *pattern
)
38 return strcmpx(rd_argv(rd
), pattern
) == 0;
41 void rd_arg_inc(struct rd
*rd
)
49 bool rd_no_arg(struct rd
*rd
)
51 return rd_argc(rd
) == 0;
55 * Possible input:output
56 * dev/port | first port | is_dump_all
59 * mlx5_1/0 | 0 | false
60 * mlx5_1/1 | 1 | false
61 * mlx5_1/- | 0 | false
63 * In strict mode, /- will return error.
65 static int get_port_from_argv(struct rd
*rd
, uint32_t *port
,
66 bool *is_dump_all
, bool strict_port
)
73 slash
= strchr(rd_argv(rd
), '/');
74 /* if no port found, return 0 */
83 if (isdigit(*slash
)) {
87 if (!*port
&& strlen(slash
))
93 static struct dev_map
*dev_map_alloc(const char *dev_name
)
95 struct dev_map
*dev_map
;
97 dev_map
= calloc(1, sizeof(*dev_map
));
100 dev_map
->dev_name
= strdup(dev_name
);
105 static void dev_map_cleanup(struct rd
*rd
)
107 struct dev_map
*dev_map
, *tmp
;
109 list_for_each_entry_safe(dev_map
, tmp
,
110 &rd
->dev_map_list
, list
) {
111 list_del(&dev_map
->list
);
112 free(dev_map
->dev_name
);
117 static int add_filter(struct rd
*rd
, char *key
, char *value
,
118 const struct filters valid_filters
[])
120 char cset
[] = "1234567890,-";
121 struct filter_entry
*fe
;
122 bool key_found
= false;
126 fe
= calloc(1, sizeof(*fe
));
130 while (idx
< MAX_NUMBER_OF_FILTERS
&& valid_filters
[idx
].name
) {
131 if (!strcmpx(key
, valid_filters
[idx
].name
)) {
138 pr_err("Unsupported filter option: %s\n", key
);
144 * Check the filter validity, not optimal, but works
146 * Actually, there are three types of filters
147 * numeric - for example PID or QPN
148 * string - for example states
149 * link - user requested to filter on specific link
150 * e.g. mlx5_1/1, mlx5_1/-, mlx5_1 ...
152 if (valid_filters
[idx
].is_number
&&
153 strspn(value
, cset
) != strlen(value
)) {
154 pr_err("%s filter accepts \"%s\" characters only\n", key
, cset
);
159 fe
->key
= strdup(key
);
160 fe
->value
= strdup(value
);
161 if (!fe
->key
|| !fe
->value
) {
166 for (idx
= 0; idx
< strlen(fe
->value
); idx
++)
167 fe
->value
[idx
] = tolower(fe
->value
[idx
]);
169 list_add_tail(&fe
->list
, &rd
->filter_list
);
180 int rd_build_filter(struct rd
*rd
, const struct filters valid_filters
[])
185 if (!valid_filters
|| !rd_argc(rd
))
188 if (rd_argc(rd
) == 1) {
189 pr_err("No filter data was supplied to filter option %s\n", rd_argv(rd
));
194 if (rd_argc(rd
) % 2) {
195 pr_err("There is filter option without data\n");
200 while (idx
!= rd_argc(rd
)) {
202 * We can do micro-optimization and skip "dev"
203 * and "link" filters, but it is not worth of it.
205 ret
= add_filter(rd
, *(rd
->argv
+ idx
),
206 *(rd
->argv
+ idx
+ 1), valid_filters
);
216 bool rd_check_is_key_exist(struct rd
*rd
, const char *key
)
218 struct filter_entry
*fe
;
220 list_for_each_entry(fe
, &rd
->filter_list
, list
) {
221 if (!strcmpx(fe
->key
, key
))
229 * Check if string entry is filtered:
230 * * key doesn't exist -> user didn't request -> not filtered
232 bool rd_check_is_string_filtered(struct rd
*rd
,
233 const char *key
, const char *val
)
235 bool key_is_filtered
= false;
236 struct filter_entry
*fe
;
240 list_for_each_entry(fe
, &rd
->filter_list
, list
) {
241 if (!strcmpx(fe
->key
, key
)) {
242 /* We found the key */
243 p
= strdup(fe
->value
);
244 key_is_filtered
= true;
247 * Something extremely wrong if we fail
248 * to allocate small amount of bytes.
250 pr_err("Found key, but failed to allocate memory to store value\n");
251 return key_is_filtered
;
255 * Need to check if value in range
256 * It can come in the following formats
257 * and their permutations:
261 str
= strtok(p
, ",");
263 if (strlen(str
) == strlen(val
) &&
264 !strcasecmp(str
, val
)) {
265 key_is_filtered
= false;
268 str
= strtok(NULL
, ",");
276 return key_is_filtered
;
280 * Check if key is filtered:
281 * key doesn't exist -> user didn't request -> not filtered
283 bool rd_check_is_filtered(struct rd
*rd
, const char *key
, uint32_t val
)
285 bool key_is_filtered
= false;
286 struct filter_entry
*fe
;
288 list_for_each_entry(fe
, &rd
->filter_list
, list
) {
289 uint32_t left_val
= 0, fe_value
= 0;
290 bool range_check
= false;
293 if (!strcmpx(fe
->key
, key
)) {
294 /* We found the key */
295 key_is_filtered
= true;
297 * Need to check if value in range
298 * It can come in the following formats
299 * (and their permutations):
304 * numb1,numb2-numb3,numb4-numb5
308 fe_value
= strtol(p
, &p
, 10);
309 if (fe_value
== val
||
310 (range_check
&& left_val
< val
&&
312 key_is_filtered
= false;
329 return key_is_filtered
;
332 static void filters_cleanup(struct rd
*rd
)
334 struct filter_entry
*fe
, *tmp
;
336 list_for_each_entry_safe(fe
, tmp
,
337 &rd
->filter_list
, list
) {
345 static const enum mnl_attr_data_type nldev_policy
[RDMA_NLDEV_ATTR_MAX
] = {
346 [RDMA_NLDEV_ATTR_DEV_INDEX
] = MNL_TYPE_U32
,
347 [RDMA_NLDEV_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
348 [RDMA_NLDEV_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
349 [RDMA_NLDEV_ATTR_CAP_FLAGS
] = MNL_TYPE_U64
,
350 [RDMA_NLDEV_ATTR_FW_VERSION
] = MNL_TYPE_NUL_STRING
,
351 [RDMA_NLDEV_ATTR_NODE_GUID
] = MNL_TYPE_U64
,
352 [RDMA_NLDEV_ATTR_SYS_IMAGE_GUID
] = MNL_TYPE_U64
,
353 [RDMA_NLDEV_ATTR_LID
] = MNL_TYPE_U32
,
354 [RDMA_NLDEV_ATTR_SM_LID
] = MNL_TYPE_U32
,
355 [RDMA_NLDEV_ATTR_LMC
] = MNL_TYPE_U8
,
356 [RDMA_NLDEV_ATTR_PORT_STATE
] = MNL_TYPE_U8
,
357 [RDMA_NLDEV_ATTR_PORT_PHYS_STATE
] = MNL_TYPE_U8
,
358 [RDMA_NLDEV_ATTR_DEV_NODE_TYPE
] = MNL_TYPE_U8
,
359 [RDMA_NLDEV_ATTR_RES_SUMMARY
] = MNL_TYPE_NESTED
,
360 [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY
] = MNL_TYPE_NESTED
,
361 [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME
] = MNL_TYPE_NUL_STRING
,
362 [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR
] = MNL_TYPE_U64
,
363 [RDMA_NLDEV_ATTR_RES_QP
] = MNL_TYPE_NESTED
,
364 [RDMA_NLDEV_ATTR_RES_QP_ENTRY
] = MNL_TYPE_NESTED
,
365 [RDMA_NLDEV_ATTR_RES_LQPN
] = MNL_TYPE_U32
,
366 [RDMA_NLDEV_ATTR_RES_RQPN
] = MNL_TYPE_U32
,
367 [RDMA_NLDEV_ATTR_RES_RQ_PSN
] = MNL_TYPE_U32
,
368 [RDMA_NLDEV_ATTR_RES_SQ_PSN
] = MNL_TYPE_U32
,
369 [RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE
] = MNL_TYPE_U8
,
370 [RDMA_NLDEV_ATTR_RES_TYPE
] = MNL_TYPE_U8
,
371 [RDMA_NLDEV_ATTR_RES_STATE
] = MNL_TYPE_U8
,
372 [RDMA_NLDEV_ATTR_RES_PID
] = MNL_TYPE_U32
,
373 [RDMA_NLDEV_ATTR_RES_KERN_NAME
] = MNL_TYPE_NUL_STRING
,
376 int rd_attr_cb(const struct nlattr
*attr
, void *data
)
378 const struct nlattr
**tb
= data
;
381 if (mnl_attr_type_valid(attr
, RDMA_NLDEV_ATTR_MAX
) < 0)
384 type
= mnl_attr_get_type(attr
);
386 if (mnl_attr_validate(attr
, nldev_policy
[type
]) < 0)
393 int rd_dev_init_cb(const struct nlmsghdr
*nlh
, void *data
)
395 struct nlattr
*tb
[RDMA_NLDEV_ATTR_MAX
] = {};
396 struct dev_map
*dev_map
;
397 struct rd
*rd
= data
;
398 const char *dev_name
;
400 mnl_attr_parse(nlh
, 0, rd_attr_cb
, tb
);
401 if (!tb
[RDMA_NLDEV_ATTR_DEV_NAME
] || !tb
[RDMA_NLDEV_ATTR_DEV_INDEX
])
403 if (!tb
[RDMA_NLDEV_ATTR_PORT_INDEX
]) {
404 pr_err("This tool doesn't support switches yet\n");
408 dev_name
= mnl_attr_get_str(tb
[RDMA_NLDEV_ATTR_DEV_NAME
]);
410 dev_map
= dev_map_alloc(dev_name
);
412 /* The main function will cleanup the allocations */
414 list_add_tail(&dev_map
->list
, &rd
->dev_map_list
);
416 dev_map
->num_ports
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_PORT_INDEX
]);
417 dev_map
->idx
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_DEV_INDEX
]);
421 void rd_free(struct rd
*rd
)
430 int rd_set_arg_to_devname(struct rd
*rd
)
434 while (!rd_no_arg(rd
)) {
435 if (rd_argv_match(rd
, "dev") || rd_argv_match(rd
, "link")) {
438 pr_err("No device name was supplied\n");
449 int rd_exec_link(struct rd
*rd
, int (*cb
)(struct rd
*rd
), bool strict_port
)
451 struct dev_map
*dev_map
;
456 jsonw_start_array(rd
->jw
);
458 list_for_each_entry(dev_map
, &rd
->dev_map_list
, list
) {
459 rd
->dev_idx
= dev_map
->idx
;
460 port
= (strict_port
) ? 1 : 0;
461 for (; port
< dev_map
->num_ports
+ 1; port
++) {
472 dev_map
= dev_map_lookup(rd
, true);
473 ret
= get_port_from_argv(rd
, &port
, &is_dump_all
, strict_port
);
474 if (!dev_map
|| port
> dev_map
->num_ports
|| (!port
&& ret
)) {
475 pr_err("Wrong device name\n");
480 rd
->dev_idx
= dev_map
->idx
;
482 for (; rd
->port_idx
< dev_map
->num_ports
+ 1; rd
->port_idx
++) {
488 * We got request to show link for devname
497 jsonw_end_array(rd
->jw
);
501 int rd_exec_dev(struct rd
*rd
, int (*cb
)(struct rd
*rd
))
503 struct dev_map
*dev_map
;
507 jsonw_start_array(rd
->jw
);
509 list_for_each_entry(dev_map
, &rd
->dev_map_list
, list
) {
510 rd
->dev_idx
= dev_map
->idx
;
516 dev_map
= dev_map_lookup(rd
, false);
518 pr_err("Wrong device name - %s\n", rd_argv(rd
));
523 rd
->dev_idx
= dev_map
->idx
;
528 jsonw_end_array(rd
->jw
);
532 int rd_exec_cmd(struct rd
*rd
, const struct rd_cmd
*cmds
, const char *str
)
534 const struct rd_cmd
*c
;
536 /* First argument in objs table is default variant */
538 return cmds
->func(rd
);
540 for (c
= cmds
+ 1; c
->cmd
; ++c
) {
541 if (rd_argv_match(rd
, c
->cmd
)) {
542 /* Move to next argument */
548 pr_err("Unknown %s '%s'.\n", str
, rd_argv(rd
));
552 void rd_prepare_msg(struct rd
*rd
, uint32_t cmd
, uint32_t *seq
, uint16_t flags
)
556 rd
->nlh
= mnl_nlmsg_put_header(rd
->buff
);
557 rd
->nlh
->nlmsg_type
= RDMA_NL_GET_TYPE(RDMA_NL_NLDEV
, cmd
);
558 rd
->nlh
->nlmsg_seq
= *seq
;
559 rd
->nlh
->nlmsg_flags
= flags
;
562 int rd_send_msg(struct rd
*rd
)
566 rd
->nl
= mnl_socket_open(NETLINK_RDMA
);
568 pr_err("Failed to open NETLINK_RDMA socket\n");
572 ret
= mnl_socket_bind(rd
->nl
, 0, MNL_SOCKET_AUTOPID
);
574 pr_err("Failed to bind socket with err %d\n", ret
);
578 ret
= mnl_socket_sendto(rd
->nl
, rd
->nlh
, rd
->nlh
->nlmsg_len
);
580 pr_err("Failed to send to socket with err %d\n", ret
);
586 mnl_socket_close(rd
->nl
);
590 int rd_recv_msg(struct rd
*rd
, mnl_cb_t callback
, void *data
, unsigned int seq
)
594 char buf
[MNL_SOCKET_BUFFER_SIZE
];
596 portid
= mnl_socket_get_portid(rd
->nl
);
598 ret
= mnl_socket_recvfrom(rd
->nl
, buf
, sizeof(buf
));
602 ret
= mnl_cb_run(buf
, ret
, seq
, portid
, callback
, data
);
605 mnl_socket_close(rd
->nl
);
609 static struct dev_map
*_dev_map_lookup(struct rd
*rd
, const char *dev_name
)
611 struct dev_map
*dev_map
;
613 list_for_each_entry(dev_map
, &rd
->dev_map_list
, list
)
614 if (strcmp(dev_name
, dev_map
->dev_name
) == 0)
620 struct dev_map
*dev_map_lookup(struct rd
*rd
, bool allow_port_index
)
622 struct dev_map
*dev_map
;
629 dev_name
= strdup(rd_argv(rd
));
630 if (allow_port_index
) {
631 slash
= strrchr(dev_name
, '/');
636 dev_map
= _dev_map_lookup(rd
, dev_name
);