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>
16 int rd_argc(struct rd
*rd
)
21 static char *rd_argv(struct rd
*rd
)
28 static int strcmpx(const char *str1
, const char *str2
)
30 if (strlen(str1
) > strlen(str2
))
32 return strncmp(str1
, str2
, strlen(str1
));
35 static bool rd_argv_match(struct rd
*rd
, const char *pattern
)
39 return strcmpx(rd_argv(rd
), pattern
) == 0;
42 static void rd_arg_inc(struct rd
*rd
)
50 static bool rd_no_arg(struct rd
*rd
)
52 return rd_argc(rd
) == 0;
56 * Possible input:output
57 * dev/port | first port | is_dump_all
60 * mlx5_1/0 | 0 | false
61 * mlx5_1/1 | 1 | false
62 * mlx5_1/- | 0 | false
64 * In strict mode, /- will return error.
66 static int get_port_from_argv(struct rd
*rd
, uint32_t *port
,
67 bool *is_dump_all
, bool strict_port
)
74 slash
= strchr(rd_argv(rd
), '/');
75 /* if no port found, return 0 */
84 if (isdigit(*slash
)) {
88 if (!*port
&& strlen(slash
))
94 static struct dev_map
*dev_map_alloc(const char *dev_name
)
96 struct dev_map
*dev_map
;
98 dev_map
= calloc(1, sizeof(*dev_map
));
101 dev_map
->dev_name
= strdup(dev_name
);
102 if (!dev_map
->dev_name
) {
110 static void dev_map_cleanup(struct rd
*rd
)
112 struct dev_map
*dev_map
, *tmp
;
114 list_for_each_entry_safe(dev_map
, tmp
,
115 &rd
->dev_map_list
, list
) {
116 list_del(&dev_map
->list
);
117 free(dev_map
->dev_name
);
122 static int add_filter(struct rd
*rd
, char *key
, char *value
,
123 const struct filters valid_filters
[])
125 char cset
[] = "1234567890,-";
126 struct filter_entry
*fe
;
127 bool key_found
= false;
131 fe
= calloc(1, sizeof(*fe
));
135 while (idx
< MAX_NUMBER_OF_FILTERS
&& valid_filters
[idx
].name
) {
136 if (!strcmpx(key
, valid_filters
[idx
].name
)) {
143 pr_err("Unsupported filter option: %s\n", key
);
149 * Check the filter validity, not optimal, but works
151 * Actually, there are three types of filters
152 * numeric - for example PID or QPN
153 * string - for example states
154 * link - user requested to filter on specific link
155 * e.g. mlx5_1/1, mlx5_1/-, mlx5_1 ...
157 if (valid_filters
[idx
].is_number
&&
158 strspn(value
, cset
) != strlen(value
)) {
159 pr_err("%s filter accepts \"%s\" characters only\n", key
, cset
);
164 fe
->key
= strdup(key
);
165 fe
->value
= strdup(value
);
166 if (!fe
->key
|| !fe
->value
) {
171 for (idx
= 0; idx
< strlen(fe
->value
); idx
++)
172 fe
->value
[idx
] = tolower(fe
->value
[idx
]);
174 list_add_tail(&fe
->list
, &rd
->filter_list
);
185 int rd_build_filter(struct rd
*rd
, const struct filters valid_filters
[])
190 if (!valid_filters
|| !rd_argc(rd
))
193 if (rd_argc(rd
) == 1) {
194 pr_err("No filter data was supplied to filter option %s\n", rd_argv(rd
));
199 if (rd_argc(rd
) % 2) {
200 pr_err("There is filter option without data\n");
205 while (idx
!= rd_argc(rd
)) {
207 * We can do micro-optimization and skip "dev"
208 * and "link" filters, but it is not worth of it.
210 ret
= add_filter(rd
, *(rd
->argv
+ idx
),
211 *(rd
->argv
+ idx
+ 1), valid_filters
);
221 bool rd_check_is_key_exist(struct rd
*rd
, const char *key
)
223 struct filter_entry
*fe
;
225 list_for_each_entry(fe
, &rd
->filter_list
, list
) {
226 if (!strcmpx(fe
->key
, key
))
234 * Check if string entry is filtered:
235 * * key doesn't exist -> user didn't request -> not filtered
237 bool rd_check_is_string_filtered(struct rd
*rd
,
238 const char *key
, const char *val
)
240 bool key_is_filtered
= false;
241 struct filter_entry
*fe
;
245 list_for_each_entry(fe
, &rd
->filter_list
, list
) {
246 if (!strcmpx(fe
->key
, key
)) {
247 /* We found the key */
248 p
= strdup(fe
->value
);
249 key_is_filtered
= true;
252 * Something extremely wrong if we fail
253 * to allocate small amount of bytes.
255 pr_err("Found key, but failed to allocate memory to store value\n");
256 return key_is_filtered
;
260 * Need to check if value in range
261 * It can come in the following formats
262 * and their permutations:
266 str
= strtok(p
, ",");
268 if (strlen(str
) == strlen(val
) &&
269 !strcasecmp(str
, val
)) {
270 key_is_filtered
= false;
273 str
= strtok(NULL
, ",");
281 return key_is_filtered
;
285 * Check if key is filtered:
286 * key doesn't exist -> user didn't request -> not filtered
288 bool rd_check_is_filtered(struct rd
*rd
, const char *key
, uint32_t val
)
290 bool key_is_filtered
= false;
291 struct filter_entry
*fe
;
293 list_for_each_entry(fe
, &rd
->filter_list
, list
) {
294 uint32_t left_val
= 0, fe_value
= 0;
295 bool range_check
= false;
298 if (!strcmpx(fe
->key
, key
)) {
299 /* We found the key */
300 key_is_filtered
= true;
302 * Need to check if value in range
303 * It can come in the following formats
304 * (and their permutations):
309 * numb1,numb2-numb3,numb4-numb5
313 fe_value
= strtol(p
, &p
, 10);
314 if (fe_value
== val
||
315 (range_check
&& left_val
< val
&&
317 key_is_filtered
= false;
334 return key_is_filtered
;
337 static void filters_cleanup(struct rd
*rd
)
339 struct filter_entry
*fe
, *tmp
;
341 list_for_each_entry_safe(fe
, tmp
,
342 &rd
->filter_list
, list
) {
350 static const enum mnl_attr_data_type nldev_policy
[RDMA_NLDEV_ATTR_MAX
] = {
351 [RDMA_NLDEV_ATTR_DEV_INDEX
] = MNL_TYPE_U32
,
352 [RDMA_NLDEV_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
353 [RDMA_NLDEV_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
354 [RDMA_NLDEV_ATTR_CAP_FLAGS
] = MNL_TYPE_U64
,
355 [RDMA_NLDEV_ATTR_FW_VERSION
] = MNL_TYPE_NUL_STRING
,
356 [RDMA_NLDEV_ATTR_NODE_GUID
] = MNL_TYPE_U64
,
357 [RDMA_NLDEV_ATTR_SYS_IMAGE_GUID
] = MNL_TYPE_U64
,
358 [RDMA_NLDEV_ATTR_LID
] = MNL_TYPE_U32
,
359 [RDMA_NLDEV_ATTR_SM_LID
] = MNL_TYPE_U32
,
360 [RDMA_NLDEV_ATTR_LMC
] = MNL_TYPE_U8
,
361 [RDMA_NLDEV_ATTR_PORT_STATE
] = MNL_TYPE_U8
,
362 [RDMA_NLDEV_ATTR_PORT_PHYS_STATE
] = MNL_TYPE_U8
,
363 [RDMA_NLDEV_ATTR_DEV_NODE_TYPE
] = MNL_TYPE_U8
,
364 [RDMA_NLDEV_ATTR_RES_SUMMARY
] = MNL_TYPE_NESTED
,
365 [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY
] = MNL_TYPE_NESTED
,
366 [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME
] = MNL_TYPE_NUL_STRING
,
367 [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR
] = MNL_TYPE_U64
,
368 [RDMA_NLDEV_ATTR_RES_QP
] = MNL_TYPE_NESTED
,
369 [RDMA_NLDEV_ATTR_RES_QP_ENTRY
] = MNL_TYPE_NESTED
,
370 [RDMA_NLDEV_ATTR_RES_LQPN
] = MNL_TYPE_U32
,
371 [RDMA_NLDEV_ATTR_RES_RQPN
] = MNL_TYPE_U32
,
372 [RDMA_NLDEV_ATTR_RES_RQ_PSN
] = MNL_TYPE_U32
,
373 [RDMA_NLDEV_ATTR_RES_SQ_PSN
] = MNL_TYPE_U32
,
374 [RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE
] = MNL_TYPE_U8
,
375 [RDMA_NLDEV_ATTR_RES_TYPE
] = MNL_TYPE_U8
,
376 [RDMA_NLDEV_ATTR_RES_STATE
] = MNL_TYPE_U8
,
377 [RDMA_NLDEV_ATTR_RES_PID
] = MNL_TYPE_U32
,
378 [RDMA_NLDEV_ATTR_RES_KERN_NAME
] = MNL_TYPE_NUL_STRING
,
379 [RDMA_NLDEV_ATTR_RES_CM_ID
] = MNL_TYPE_NESTED
,
380 [RDMA_NLDEV_ATTR_RES_CM_ID_ENTRY
] = MNL_TYPE_NESTED
,
381 [RDMA_NLDEV_ATTR_RES_PS
] = MNL_TYPE_U32
,
382 [RDMA_NLDEV_ATTR_RES_SRC_ADDR
] = MNL_TYPE_UNSPEC
,
383 [RDMA_NLDEV_ATTR_RES_DST_ADDR
] = MNL_TYPE_UNSPEC
,
384 [RDMA_NLDEV_ATTR_RES_CQ
] = MNL_TYPE_NESTED
,
385 [RDMA_NLDEV_ATTR_RES_CQ_ENTRY
] = MNL_TYPE_NESTED
,
386 [RDMA_NLDEV_ATTR_RES_CQE
] = MNL_TYPE_U32
,
387 [RDMA_NLDEV_ATTR_RES_USECNT
] = MNL_TYPE_U64
,
388 [RDMA_NLDEV_ATTR_RES_POLL_CTX
] = MNL_TYPE_U8
,
389 [RDMA_NLDEV_ATTR_RES_MR
] = MNL_TYPE_NESTED
,
390 [RDMA_NLDEV_ATTR_RES_MR_ENTRY
] = MNL_TYPE_NESTED
,
391 [RDMA_NLDEV_ATTR_RES_RKEY
] = MNL_TYPE_U32
,
392 [RDMA_NLDEV_ATTR_RES_LKEY
] = MNL_TYPE_U32
,
393 [RDMA_NLDEV_ATTR_RES_IOVA
] = MNL_TYPE_U64
,
394 [RDMA_NLDEV_ATTR_RES_MRLEN
] = MNL_TYPE_U64
,
395 [RDMA_NLDEV_ATTR_NDEV_INDEX
] = MNL_TYPE_U32
,
396 [RDMA_NLDEV_ATTR_NDEV_NAME
] = MNL_TYPE_NUL_STRING
,
397 [RDMA_NLDEV_ATTR_DRIVER
] = MNL_TYPE_NESTED
,
398 [RDMA_NLDEV_ATTR_DRIVER_ENTRY
] = MNL_TYPE_NESTED
,
399 [RDMA_NLDEV_ATTR_DRIVER_STRING
] = MNL_TYPE_NUL_STRING
,
400 [RDMA_NLDEV_ATTR_DRIVER_PRINT_TYPE
] = MNL_TYPE_U8
,
401 [RDMA_NLDEV_ATTR_DRIVER_S32
] = MNL_TYPE_U32
,
402 [RDMA_NLDEV_ATTR_DRIVER_U32
] = MNL_TYPE_U32
,
403 [RDMA_NLDEV_ATTR_DRIVER_S64
] = MNL_TYPE_U64
,
404 [RDMA_NLDEV_ATTR_DRIVER_U64
] = MNL_TYPE_U64
,
407 static int rd_attr_check(const struct nlattr
*attr
, int *typep
)
411 if (mnl_attr_type_valid(attr
, RDMA_NLDEV_ATTR_MAX
) < 0)
414 type
= mnl_attr_get_type(attr
);
416 if (mnl_attr_validate(attr
, nldev_policy
[type
]) < 0)
419 *typep
= nldev_policy
[type
];
423 int rd_attr_cb(const struct nlattr
*attr
, void *data
)
425 const struct nlattr
**tb
= data
;
428 if (mnl_attr_type_valid(attr
, RDMA_NLDEV_ATTR_MAX
) < 0)
429 /* We received uknown attribute */
432 type
= mnl_attr_get_type(attr
);
434 if (mnl_attr_validate(attr
, nldev_policy
[type
]) < 0)
441 int rd_dev_init_cb(const struct nlmsghdr
*nlh
, void *data
)
443 struct nlattr
*tb
[RDMA_NLDEV_ATTR_MAX
] = {};
444 struct dev_map
*dev_map
;
445 struct rd
*rd
= data
;
446 const char *dev_name
;
448 mnl_attr_parse(nlh
, 0, rd_attr_cb
, tb
);
449 if (!tb
[RDMA_NLDEV_ATTR_DEV_NAME
] || !tb
[RDMA_NLDEV_ATTR_DEV_INDEX
])
451 if (!tb
[RDMA_NLDEV_ATTR_PORT_INDEX
]) {
452 pr_err("This tool doesn't support switches yet\n");
456 dev_name
= mnl_attr_get_str(tb
[RDMA_NLDEV_ATTR_DEV_NAME
]);
458 dev_map
= dev_map_alloc(dev_name
);
460 /* The main function will cleanup the allocations */
462 list_add_tail(&dev_map
->list
, &rd
->dev_map_list
);
464 dev_map
->num_ports
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_PORT_INDEX
]);
465 dev_map
->idx
= mnl_attr_get_u32(tb
[RDMA_NLDEV_ATTR_DEV_INDEX
]);
469 void rd_free(struct rd
*rd
)
478 int rd_set_arg_to_devname(struct rd
*rd
)
482 while (!rd_no_arg(rd
)) {
483 if (rd_argv_match(rd
, "dev") || rd_argv_match(rd
, "link")) {
486 pr_err("No device name was supplied\n");
497 int rd_exec_link(struct rd
*rd
, int (*cb
)(struct rd
*rd
), bool strict_port
)
499 struct dev_map
*dev_map
;
504 jsonw_start_array(rd
->jw
);
506 list_for_each_entry(dev_map
, &rd
->dev_map_list
, list
) {
507 rd
->dev_idx
= dev_map
->idx
;
508 port
= (strict_port
) ? 1 : 0;
509 for (; port
< dev_map
->num_ports
+ 1; port
++) {
520 dev_map
= dev_map_lookup(rd
, true);
521 ret
= get_port_from_argv(rd
, &port
, &is_dump_all
, strict_port
);
522 if (!dev_map
|| port
> dev_map
->num_ports
|| (!port
&& ret
)) {
523 pr_err("Wrong device name\n");
528 rd
->dev_idx
= dev_map
->idx
;
530 for (; rd
->port_idx
< dev_map
->num_ports
+ 1; rd
->port_idx
++) {
536 * We got request to show link for devname
545 jsonw_end_array(rd
->jw
);
549 int rd_exec_dev(struct rd
*rd
, int (*cb
)(struct rd
*rd
))
551 struct dev_map
*dev_map
;
555 jsonw_start_array(rd
->jw
);
557 list_for_each_entry(dev_map
, &rd
->dev_map_list
, list
) {
558 rd
->dev_idx
= dev_map
->idx
;
564 dev_map
= dev_map_lookup(rd
, false);
566 pr_err("Wrong device name - %s\n", rd_argv(rd
));
571 rd
->dev_idx
= dev_map
->idx
;
576 jsonw_end_array(rd
->jw
);
580 int rd_exec_cmd(struct rd
*rd
, const struct rd_cmd
*cmds
, const char *str
)
582 const struct rd_cmd
*c
;
584 /* First argument in objs table is default variant */
586 return cmds
->func(rd
);
588 for (c
= cmds
+ 1; c
->cmd
; ++c
) {
589 if (rd_argv_match(rd
, c
->cmd
)) {
590 /* Move to next argument */
596 pr_err("Unknown %s '%s'.\n", str
, rd_argv(rd
));
600 void rd_prepare_msg(struct rd
*rd
, uint32_t cmd
, uint32_t *seq
, uint16_t flags
)
604 rd
->nlh
= mnl_nlmsg_put_header(rd
->buff
);
605 rd
->nlh
->nlmsg_type
= RDMA_NL_GET_TYPE(RDMA_NL_NLDEV
, cmd
);
606 rd
->nlh
->nlmsg_seq
= *seq
;
607 rd
->nlh
->nlmsg_flags
= flags
;
610 int rd_send_msg(struct rd
*rd
)
614 rd
->nl
= mnl_socket_open(NETLINK_RDMA
);
616 pr_err("Failed to open NETLINK_RDMA socket\n");
620 ret
= mnl_socket_bind(rd
->nl
, 0, MNL_SOCKET_AUTOPID
);
622 pr_err("Failed to bind socket with err %d\n", ret
);
626 ret
= mnl_socket_sendto(rd
->nl
, rd
->nlh
, rd
->nlh
->nlmsg_len
);
628 pr_err("Failed to send to socket with err %d\n", ret
);
634 mnl_socket_close(rd
->nl
);
638 int rd_recv_msg(struct rd
*rd
, mnl_cb_t callback
, void *data
, unsigned int seq
)
642 char buf
[MNL_SOCKET_BUFFER_SIZE
];
644 portid
= mnl_socket_get_portid(rd
->nl
);
646 ret
= mnl_socket_recvfrom(rd
->nl
, buf
, sizeof(buf
));
650 ret
= mnl_cb_run(buf
, ret
, seq
, portid
, callback
, data
);
653 mnl_socket_close(rd
->nl
);
657 static struct dev_map
*_dev_map_lookup(struct rd
*rd
, const char *dev_name
)
659 struct dev_map
*dev_map
;
661 list_for_each_entry(dev_map
, &rd
->dev_map_list
, list
)
662 if (strcmp(dev_name
, dev_map
->dev_name
) == 0)
668 struct dev_map
*dev_map_lookup(struct rd
*rd
, bool allow_port_index
)
670 struct dev_map
*dev_map
;
677 dev_name
= strdup(rd_argv(rd
));
678 if (allow_port_index
) {
679 slash
= strrchr(dev_name
, '/');
684 dev_map
= _dev_map_lookup(rd
, dev_name
);
689 #define nla_type(attr) ((attr)->nla_type & NLA_TYPE_MASK)
691 void newline(struct rd
*rd
)
694 jsonw_end_array(rd
->jw
);
699 static void newline_indent(struct rd
*rd
)
702 if (!rd
->json_output
)
706 static int print_driver_string(struct rd
*rd
, const char *key_str
,
709 if (rd
->json_output
) {
710 jsonw_string_field(rd
->jw
, key_str
, val_str
);
713 return pr_out("%s %s ", key_str
, val_str
);
717 static int print_driver_s32(struct rd
*rd
, const char *key_str
, int32_t val
,
718 enum rdma_nldev_print_type print_type
)
720 if (rd
->json_output
) {
721 jsonw_int_field(rd
->jw
, key_str
, val
);
724 switch (print_type
) {
725 case RDMA_NLDEV_PRINT_TYPE_UNSPEC
:
726 return pr_out("%s %d ", key_str
, val
);
727 case RDMA_NLDEV_PRINT_TYPE_HEX
:
728 return pr_out("%s 0x%x ", key_str
, val
);
734 static int print_driver_u32(struct rd
*rd
, const char *key_str
, uint32_t val
,
735 enum rdma_nldev_print_type print_type
)
737 if (rd
->json_output
) {
738 jsonw_int_field(rd
->jw
, key_str
, val
);
741 switch (print_type
) {
742 case RDMA_NLDEV_PRINT_TYPE_UNSPEC
:
743 return pr_out("%s %u ", key_str
, val
);
744 case RDMA_NLDEV_PRINT_TYPE_HEX
:
745 return pr_out("%s 0x%x ", key_str
, val
);
751 static int print_driver_s64(struct rd
*rd
, const char *key_str
, int64_t val
,
752 enum rdma_nldev_print_type print_type
)
754 if (rd
->json_output
) {
755 jsonw_int_field(rd
->jw
, key_str
, val
);
758 switch (print_type
) {
759 case RDMA_NLDEV_PRINT_TYPE_UNSPEC
:
760 return pr_out("%s %" PRId64
" ", key_str
, val
);
761 case RDMA_NLDEV_PRINT_TYPE_HEX
:
762 return pr_out("%s 0x%" PRIx64
" ", key_str
, val
);
768 static int print_driver_u64(struct rd
*rd
, const char *key_str
, uint64_t val
,
769 enum rdma_nldev_print_type print_type
)
771 if (rd
->json_output
) {
772 jsonw_int_field(rd
->jw
, key_str
, val
);
775 switch (print_type
) {
776 case RDMA_NLDEV_PRINT_TYPE_UNSPEC
:
777 return pr_out("%s %" PRIu64
" ", key_str
, val
);
778 case RDMA_NLDEV_PRINT_TYPE_HEX
:
779 return pr_out("%s 0x%" PRIx64
" ", key_str
, val
);
785 static int print_driver_entry(struct rd
*rd
, struct nlattr
*key_attr
,
786 struct nlattr
*val_attr
,
787 enum rdma_nldev_print_type print_type
)
789 const char *key_str
= mnl_attr_get_str(key_attr
);
790 int attr_type
= nla_type(val_attr
);
793 case RDMA_NLDEV_ATTR_DRIVER_STRING
:
794 return print_driver_string(rd
, key_str
,
795 mnl_attr_get_str(val_attr
));
796 case RDMA_NLDEV_ATTR_DRIVER_S32
:
797 return print_driver_s32(rd
, key_str
,
798 mnl_attr_get_u32(val_attr
), print_type
);
799 case RDMA_NLDEV_ATTR_DRIVER_U32
:
800 return print_driver_u32(rd
, key_str
,
801 mnl_attr_get_u32(val_attr
), print_type
);
802 case RDMA_NLDEV_ATTR_DRIVER_S64
:
803 return print_driver_s64(rd
, key_str
,
804 mnl_attr_get_u64(val_attr
), print_type
);
805 case RDMA_NLDEV_ATTR_DRIVER_U64
:
806 return print_driver_u64(rd
, key_str
,
807 mnl_attr_get_u64(val_attr
), print_type
);
812 void print_driver_table(struct rd
*rd
, struct nlattr
*tb
)
814 int print_type
= RDMA_NLDEV_PRINT_TYPE_UNSPEC
;
815 struct nlattr
*tb_entry
, *key
= NULL
, *val
;
819 if (!rd
->show_driver_details
|| !tb
)
822 if (rd
->pretty_output
)
826 * Driver attrs are tuples of {key, [print-type], value}.
827 * The key must be a string. If print-type is present, it
828 * defines an alternate printf format type vs the native format
829 * for the attribute. And the value can be any available
832 mnl_attr_for_each_nested(tb_entry
, tb
) {
834 if (cc
> MAX_LINE_LENGTH
) {
835 if (rd
->pretty_output
)
839 if (rd_attr_check(tb_entry
, &type
) != MNL_CB_OK
)
842 if (type
!= MNL_TYPE_NUL_STRING
)
845 } else if (type
== MNL_TYPE_U8
) {
846 print_type
= mnl_attr_get_u8(tb_entry
);
849 ret
= print_driver_entry(rd
, key
, val
, print_type
);
853 print_type
= RDMA_NLDEV_PRINT_TYPE_UNSPEC
;