+
+#define nla_type(attr) ((attr)->nla_type & NLA_TYPE_MASK)
+
+void newline(struct rd *rd)
+{
+ close_json_object();
+ print_color_string(PRINT_FP, COLOR_NONE, NULL, "\n", NULL);
+}
+
+void newline_indent(struct rd *rd)
+{
+ newline(rd);
+ print_color_string(PRINT_FP, COLOR_NONE, NULL, " ", NULL);
+}
+
+static int print_driver_string(struct rd *rd, const char *key_str,
+ const char *val_str)
+{
+ print_color_string(PRINT_ANY, COLOR_NONE, key_str, key_str, val_str);
+ print_color_string(PRINT_FP, COLOR_NONE, NULL, " %s ", val_str);
+ return 0;
+}
+
+void print_on_off(struct rd *rd, const char *key_str, bool on)
+{
+ print_driver_string(rd, key_str, (on) ? "on":"off");
+}
+
+static int print_driver_s32(struct rd *rd, const char *key_str, int32_t val,
+ enum rdma_nldev_print_type print_type)
+{
+ if (!rd->json_output) {
+ switch (print_type) {
+ case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
+ return pr_out("%s %d ", key_str, val);
+ case RDMA_NLDEV_PRINT_TYPE_HEX:
+ return pr_out("%s 0x%x ", key_str, val);
+ default:
+ return -EINVAL;
+ }
+ }
+ print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
+ return 0;
+}
+
+static int print_driver_u32(struct rd *rd, const char *key_str, uint32_t val,
+ enum rdma_nldev_print_type print_type)
+{
+ if (!rd->json_output) {
+ switch (print_type) {
+ case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
+ return pr_out("%s %u ", key_str, val);
+ case RDMA_NLDEV_PRINT_TYPE_HEX:
+ return pr_out("%s 0x%x ", key_str, val);
+ default:
+ return -EINVAL;
+ }
+ }
+ print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
+ return 0;
+}
+
+static int print_driver_s64(struct rd *rd, const char *key_str, int64_t val,
+ enum rdma_nldev_print_type print_type)
+{
+ if (!rd->json_output) {
+ switch (print_type) {
+ case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
+ return pr_out("%s %" PRId64 " ", key_str, val);
+ case RDMA_NLDEV_PRINT_TYPE_HEX:
+ return pr_out("%s 0x%" PRIx64 " ", key_str, val);
+ default:
+ return -EINVAL;
+ }
+ }
+ print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
+ return 0;
+}
+
+static int print_driver_u64(struct rd *rd, const char *key_str, uint64_t val,
+ enum rdma_nldev_print_type print_type)
+{
+ if (!rd->json_output) {
+ switch (print_type) {
+ case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
+ return pr_out("%s %" PRIu64 " ", key_str, val);
+ case RDMA_NLDEV_PRINT_TYPE_HEX:
+ return pr_out("%s 0x%" PRIx64 " ", key_str, val);
+ default:
+ return -EINVAL;
+ }
+ }
+ print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
+ return 0;
+}
+
+static int print_driver_entry(struct rd *rd, struct nlattr *key_attr,
+ struct nlattr *val_attr,
+ enum rdma_nldev_print_type print_type)
+{
+ int attr_type = nla_type(val_attr);
+ int ret = -EINVAL;
+ char *key_str;
+
+ if (asprintf(&key_str, "drv_%s", mnl_attr_get_str(key_attr)) == -1)
+ return -ENOMEM;
+
+ switch (attr_type) {
+ case RDMA_NLDEV_ATTR_DRIVER_STRING:
+ ret = print_driver_string(rd, key_str,
+ mnl_attr_get_str(val_attr));
+ break;
+ case RDMA_NLDEV_ATTR_DRIVER_S32:
+ ret = print_driver_s32(rd, key_str, mnl_attr_get_u32(val_attr),
+ print_type);
+ break;
+ case RDMA_NLDEV_ATTR_DRIVER_U32:
+ ret = print_driver_u32(rd, key_str, mnl_attr_get_u32(val_attr),
+ print_type);
+ break;
+ case RDMA_NLDEV_ATTR_DRIVER_S64:
+ ret = print_driver_s64(rd, key_str, mnl_attr_get_u64(val_attr),
+ print_type);
+ break;
+ case RDMA_NLDEV_ATTR_DRIVER_U64:
+ ret = print_driver_u64(rd, key_str, mnl_attr_get_u64(val_attr),
+ print_type);
+ break;
+ }
+ free(key_str);
+ return ret;
+}
+
+void print_raw_data(struct rd *rd, struct nlattr **nla_line)
+{
+ uint8_t *data;
+ uint32_t len;
+ int i = 0;
+
+ if (!rd->show_raw)
+ return;
+
+ len = mnl_attr_get_payload_len(nla_line[RDMA_NLDEV_ATTR_RES_RAW]);
+ data = mnl_attr_get_payload(nla_line[RDMA_NLDEV_ATTR_RES_RAW]);
+ open_json_array(PRINT_JSON, "data");
+ while (i < len) {
+ print_color_uint(PRINT_ANY, COLOR_NONE, NULL, "%d", data[i]);
+ i++;
+ }
+ close_json_array(PRINT_ANY, ">");
+}
+
+void print_driver_table(struct rd *rd, struct nlattr *tb)
+{
+ int print_type = RDMA_NLDEV_PRINT_TYPE_UNSPEC;
+ struct nlattr *tb_entry, *key = NULL, *val;
+ int type, cc = 0;
+ int ret;
+
+ if (!rd->show_driver_details || !tb)
+ return;
+
+ if (rd->pretty_output)
+ newline_indent(rd);
+
+ /*
+ * Driver attrs are tuples of {key, [print-type], value}.
+ * The key must be a string. If print-type is present, it
+ * defines an alternate printf format type vs the native format
+ * for the attribute. And the value can be any available
+ * driver type.
+ */
+ mnl_attr_for_each_nested(tb_entry, tb) {
+
+ if (cc > MAX_LINE_LENGTH) {
+ if (rd->pretty_output)
+ newline_indent(rd);
+ cc = 0;
+ }
+ if (rd_attr_check(tb_entry, &type) != MNL_CB_OK)
+ return;
+ if (!key) {
+ if (type != MNL_TYPE_NUL_STRING)
+ return;
+ key = tb_entry;
+ } else if (type == MNL_TYPE_U8) {
+ print_type = mnl_attr_get_u8(tb_entry);
+ } else {
+ val = tb_entry;
+ ret = print_driver_entry(rd, key, val, print_type);
+ if (ret < 0)
+ return;
+ cc += ret;
+ print_type = RDMA_NLDEV_PRINT_TYPE_UNSPEC;
+ key = NULL;
+ }
+ }
+ return;
+}