Fix build break in 64bit architectures
[platform/upstream/iproute2.git] / rdma / utils.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3  * utils.c      RDMA tool
4  * Authors:     Leon Romanovsky <leonro@mellanox.com>
5  */
6
7 #include "rdma.h"
8 #include <ctype.h>
9 #include <inttypes.h>
10
11 int rd_argc(struct rd *rd)
12 {
13         return rd->argc;
14 }
15
16 char *rd_argv(struct rd *rd)
17 {
18         if (!rd_argc(rd))
19                 return NULL;
20         return *rd->argv;
21 }
22
23 int strcmpx(const char *str1, const char *str2)
24 {
25         if (strlen(str1) > strlen(str2))
26                 return -1;
27         return strncmp(str1, str2, strlen(str1));
28 }
29
30 static bool rd_argv_match(struct rd *rd, const char *pattern)
31 {
32         if (!rd_argc(rd))
33                 return false;
34         return strcmpx(rd_argv(rd), pattern) == 0;
35 }
36
37 void rd_arg_inc(struct rd *rd)
38 {
39         if (!rd_argc(rd))
40                 return;
41         rd->argc--;
42         rd->argv++;
43 }
44
45 bool rd_no_arg(struct rd *rd)
46 {
47         return rd_argc(rd) == 0;
48 }
49
50 /*
51  * Possible input:output
52  * dev/port    | first port | is_dump_all
53  * mlx5_1      | 0          | true
54  * mlx5_1/     | 0          | true
55  * mlx5_1/0    | 0          | false
56  * mlx5_1/1    | 1          | false
57  * mlx5_1/-    | 0          | false
58  *
59  * In strict port mode, a non-0 port must be provided
60  */
61 static int get_port_from_argv(struct rd *rd, uint32_t *port,
62                               bool *is_dump_all, bool strict_port)
63 {
64         char *slash;
65
66         *port = 0;
67         *is_dump_all = strict_port ? false : true;
68
69         slash = strchr(rd_argv(rd), '/');
70         /* if no port found, return 0 */
71         if (slash++) {
72                 if (*slash == '-') {
73                         if (strict_port)
74                                 return -EINVAL;
75                         *is_dump_all = false;
76                         return 0;
77                 }
78
79                 if (isdigit(*slash)) {
80                         *is_dump_all = false;
81                         *port = atoi(slash);
82                 }
83                 if (!*port && strlen(slash))
84                         return -EINVAL;
85         }
86         if (strict_port && (*port == 0))
87                 return -EINVAL;
88
89         return 0;
90 }
91
92 static struct dev_map *dev_map_alloc(const char *dev_name)
93 {
94         struct dev_map *dev_map;
95
96         dev_map = calloc(1, sizeof(*dev_map));
97         if (!dev_map)
98                 return NULL;
99         dev_map->dev_name = strdup(dev_name);
100         if (!dev_map->dev_name) {
101                 free(dev_map);
102                 return NULL;
103         }
104
105         return dev_map;
106 }
107
108 static void dev_map_cleanup(struct rd *rd)
109 {
110         struct dev_map *dev_map, *tmp;
111
112         list_for_each_entry_safe(dev_map, tmp,
113                                  &rd->dev_map_list, list) {
114                 list_del(&dev_map->list);
115                 free(dev_map->dev_name);
116                 free(dev_map);
117         }
118 }
119
120 static int add_filter(struct rd *rd, char *key, char *value,
121                       const struct filters valid_filters[])
122 {
123         char cset[] = "1234567890,-";
124         struct filter_entry *fe;
125         bool key_found = false;
126         int idx = 0;
127         char *endp;
128         int ret;
129
130         fe = calloc(1, sizeof(*fe));
131         if (!fe)
132                 return -ENOMEM;
133
134         while (idx < MAX_NUMBER_OF_FILTERS && valid_filters[idx].name) {
135                 if (!strcmpx(key, valid_filters[idx].name)) {
136                         key_found = true;
137                         break;
138                 }
139                 idx++;
140         }
141         if (!key_found) {
142                 pr_err("Unsupported filter option: %s\n", key);
143                 ret = -EINVAL;
144                 goto err;
145         }
146
147         /*
148          * Check the filter validity, not optimal, but works
149          *
150          * Actually, there are three types of filters
151          *  numeric - for example PID or QPN
152          *  string  - for example states
153          *  link    - user requested to filter on specific link
154          *            e.g. mlx5_1/1, mlx5_1/-, mlx5_1 ...
155          */
156         if (valid_filters[idx].is_number &&
157             strspn(value, cset) != strlen(value)) {
158                 pr_err("%s filter accepts \"%s\" characters only\n", key, cset);
159                 ret = -EINVAL;
160                 goto err;
161         }
162
163         fe->key = strdup(key);
164         fe->value = strdup(value);
165         if (!fe->key || !fe->value) {
166                 ret = -ENOMEM;
167                 goto err_alloc;
168         }
169
170         errno = 0;
171         strtol(fe->value, &endp, 10);
172         if (valid_filters[idx].is_doit && !errno && *endp == '\0')
173                 fe->is_doit = true;
174
175         for (idx = 0; idx < strlen(fe->value); idx++)
176                 fe->value[idx] = tolower(fe->value[idx]);
177
178         list_add_tail(&fe->list, &rd->filter_list);
179         return 0;
180
181 err_alloc:
182         free(fe->value);
183         free(fe->key);
184 err:
185         free(fe);
186         return ret;
187 }
188
189 bool rd_doit_index(struct rd *rd, uint32_t *idx)
190 {
191         struct filter_entry *fe;
192
193         list_for_each_entry(fe, &rd->filter_list, list) {
194                 if (fe->is_doit) {
195                         *idx = atoi(fe->value);
196                         return true;
197                 }
198         }
199
200         return false;
201 }
202
203 int rd_build_filter(struct rd *rd, const struct filters valid_filters[])
204 {
205         int ret = 0;
206         int idx = 0;
207
208         if (!valid_filters || !rd_argc(rd))
209                 goto out;
210
211         if (rd_argc(rd) == 1) {
212                 pr_err("No filter data was supplied to filter option %s\n", rd_argv(rd));
213                 ret = -EINVAL;
214                 goto out;
215         }
216
217         if (rd_argc(rd) % 2) {
218                 pr_err("There is filter option without data\n");
219                 ret = -EINVAL;
220                 goto out;
221         }
222
223         while (idx != rd_argc(rd)) {
224                 /*
225                  * We can do micro-optimization and skip "dev"
226                  * and "link" filters, but it is not worth of it.
227                  */
228                 ret = add_filter(rd, *(rd->argv + idx),
229                                  *(rd->argv + idx + 1), valid_filters);
230                 if (ret)
231                         goto out;
232                 idx += 2;
233         }
234
235 out:
236         return ret;
237 }
238
239 static bool rd_check_is_key_exist(struct rd *rd, const char *key)
240 {
241         struct filter_entry *fe;
242
243         list_for_each_entry(fe, &rd->filter_list, list) {
244                 if (!strcmpx(fe->key, key))
245                         return true;
246         }
247
248         return false;
249 }
250
251 /*
252  * Check if string entry is filtered:
253  *  * key doesn't exist -> user didn't request -> not filtered
254  */
255 static bool rd_check_is_string_filtered(struct rd *rd, const char *key,
256                                         const char *val)
257 {
258         bool key_is_filtered = false;
259         struct filter_entry *fe;
260         char *p = NULL;
261         char *str;
262
263         list_for_each_entry(fe, &rd->filter_list, list) {
264                 if (!strcmpx(fe->key, key)) {
265                         /* We found the key */
266                         p = strdup(fe->value);
267                         key_is_filtered = true;
268                         if (!p) {
269                                 /*
270                                  * Something extremely wrong if we fail
271                                  * to allocate small amount of bytes.
272                                  */
273                                 pr_err("Found key, but failed to allocate memory to store value\n");
274                                 return key_is_filtered;
275                         }
276
277                         /*
278                          * Need to check if value in range
279                          * It can come in the following formats
280                          * and their permutations:
281                          * str
282                          * str1,str2
283                          */
284                         str = strtok(p, ",");
285                         while (str) {
286                                 if (strlen(str) == strlen(val) &&
287                                     !strcasecmp(str, val)) {
288                                         key_is_filtered = false;
289                                         goto out;
290                                 }
291                                 str = strtok(NULL, ",");
292                         }
293                         goto out;
294                 }
295         }
296
297 out:
298         free(p);
299         return key_is_filtered;
300 }
301
302 /*
303  * Check if key is filtered:
304  * key doesn't exist -> user didn't request -> not filtered
305  */
306 static bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val)
307 {
308         bool key_is_filtered = false;
309         struct filter_entry *fe;
310
311         list_for_each_entry(fe, &rd->filter_list, list) {
312                 uint32_t left_val = 0, fe_value = 0;
313                 bool range_check = false;
314                 char *p = fe->value;
315
316                 if (!strcmpx(fe->key, key)) {
317                         /* We found the key */
318                         key_is_filtered = true;
319                         /*
320                          * Need to check if value in range
321                          * It can come in the following formats
322                          * (and their permutations):
323                          * numb
324                          * numb1,numb2
325                          * ,numb1,numb2
326                          * numb1-numb2
327                          * numb1,numb2-numb3,numb4-numb5
328                          */
329                         while (*p) {
330                                 if (isdigit(*p)) {
331                                         fe_value = strtol(p, &p, 10);
332                                         if (fe_value == val ||
333                                             (range_check && left_val < val &&
334                                              val < fe_value)) {
335                                                 key_is_filtered = false;
336                                                 goto out;
337                                         }
338                                         range_check = false;
339                                 } else {
340                                         if (*p == '-') {
341                                                 left_val = fe_value;
342                                                 range_check = true;
343                                         }
344                                         p++;
345                                 }
346                         }
347                         goto out;
348                 }
349         }
350
351 out:
352         return key_is_filtered;
353 }
354
355 bool rd_is_filtered_attr(struct rd *rd, const char *key, uint32_t val,
356                          struct nlattr *attr)
357 {
358         if (!attr)
359                 return rd_check_is_key_exist(rd, key);
360
361         return rd_check_is_filtered(rd, key, val);
362 }
363
364 bool rd_is_string_filtered_attr(struct rd *rd, const char *key, const char *val,
365                                 struct nlattr *attr)
366 {
367         if (!attr)
368                 rd_check_is_key_exist(rd, key);
369
370         return rd_check_is_string_filtered(rd, key, val);
371 }
372
373 static void filters_cleanup(struct rd *rd)
374 {
375         struct filter_entry *fe, *tmp;
376
377         list_for_each_entry_safe(fe, tmp,
378                                  &rd->filter_list, list) {
379                 list_del(&fe->list);
380                 free(fe->key);
381                 free(fe->value);
382                 free(fe);
383         }
384 }
385
386 static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
387         [RDMA_NLDEV_ATTR_DEV_INDEX] = MNL_TYPE_U32,
388         [RDMA_NLDEV_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
389         [RDMA_NLDEV_ATTR_PORT_INDEX] = MNL_TYPE_U32,
390         [RDMA_NLDEV_ATTR_CAP_FLAGS] = MNL_TYPE_U64,
391         [RDMA_NLDEV_ATTR_FW_VERSION] = MNL_TYPE_NUL_STRING,
392         [RDMA_NLDEV_ATTR_NODE_GUID] = MNL_TYPE_U64,
393         [RDMA_NLDEV_ATTR_SYS_IMAGE_GUID] = MNL_TYPE_U64,
394         [RDMA_NLDEV_ATTR_LID] = MNL_TYPE_U32,
395         [RDMA_NLDEV_ATTR_SM_LID] = MNL_TYPE_U32,
396         [RDMA_NLDEV_ATTR_LMC] = MNL_TYPE_U8,
397         [RDMA_NLDEV_ATTR_PORT_STATE] = MNL_TYPE_U8,
398         [RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = MNL_TYPE_U8,
399         [RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = MNL_TYPE_U8,
400         [RDMA_NLDEV_ATTR_RES_SUMMARY]   = MNL_TYPE_NESTED,
401         [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY]     = MNL_TYPE_NESTED,
402         [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] = MNL_TYPE_NUL_STRING,
403         [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR] = MNL_TYPE_U64,
404         [RDMA_NLDEV_ATTR_RES_QP]                = MNL_TYPE_NESTED,
405         [RDMA_NLDEV_ATTR_RES_QP_ENTRY]          = MNL_TYPE_NESTED,
406         [RDMA_NLDEV_ATTR_RES_LQPN]      = MNL_TYPE_U32,
407         [RDMA_NLDEV_ATTR_RES_RQPN]      = MNL_TYPE_U32,
408         [RDMA_NLDEV_ATTR_RES_RQ_PSN]            = MNL_TYPE_U32,
409         [RDMA_NLDEV_ATTR_RES_SQ_PSN]            = MNL_TYPE_U32,
410         [RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]    = MNL_TYPE_U8,
411         [RDMA_NLDEV_ATTR_RES_TYPE]              = MNL_TYPE_U8,
412         [RDMA_NLDEV_ATTR_RES_STATE]             = MNL_TYPE_U8,
413         [RDMA_NLDEV_ATTR_RES_PID]               = MNL_TYPE_U32,
414         [RDMA_NLDEV_ATTR_RES_KERN_NAME] = MNL_TYPE_NUL_STRING,
415         [RDMA_NLDEV_ATTR_RES_CM_ID]             = MNL_TYPE_NESTED,
416         [RDMA_NLDEV_ATTR_RES_CM_ID_ENTRY]       = MNL_TYPE_NESTED,
417         [RDMA_NLDEV_ATTR_RES_PS]                = MNL_TYPE_U32,
418         [RDMA_NLDEV_ATTR_RES_SRC_ADDR]          = MNL_TYPE_UNSPEC,
419         [RDMA_NLDEV_ATTR_RES_DST_ADDR]          = MNL_TYPE_UNSPEC,
420         [RDMA_NLDEV_ATTR_RES_CQ] = MNL_TYPE_NESTED,
421         [RDMA_NLDEV_ATTR_RES_CQ_ENTRY] = MNL_TYPE_NESTED,
422         [RDMA_NLDEV_ATTR_RES_CQE] = MNL_TYPE_U32,
423         [RDMA_NLDEV_ATTR_RES_USECNT] = MNL_TYPE_U64,
424         [RDMA_NLDEV_ATTR_RES_POLL_CTX] = MNL_TYPE_U8,
425         [RDMA_NLDEV_ATTR_RES_MR] = MNL_TYPE_NESTED,
426         [RDMA_NLDEV_ATTR_RES_MR_ENTRY] = MNL_TYPE_NESTED,
427         [RDMA_NLDEV_ATTR_RES_RKEY] = MNL_TYPE_U32,
428         [RDMA_NLDEV_ATTR_RES_LKEY] = MNL_TYPE_U32,
429         [RDMA_NLDEV_ATTR_RES_IOVA] = MNL_TYPE_U64,
430         [RDMA_NLDEV_ATTR_RES_MRLEN] = MNL_TYPE_U64,
431         [RDMA_NLDEV_ATTR_NDEV_INDEX]            = MNL_TYPE_U32,
432         [RDMA_NLDEV_ATTR_NDEV_NAME]             = MNL_TYPE_NUL_STRING,
433         [RDMA_NLDEV_ATTR_DRIVER] = MNL_TYPE_NESTED,
434         [RDMA_NLDEV_ATTR_DRIVER_ENTRY] = MNL_TYPE_NESTED,
435         [RDMA_NLDEV_ATTR_DRIVER_STRING] = MNL_TYPE_NUL_STRING,
436         [RDMA_NLDEV_ATTR_DRIVER_PRINT_TYPE] = MNL_TYPE_U8,
437         [RDMA_NLDEV_ATTR_DRIVER_S32] = MNL_TYPE_U32,
438         [RDMA_NLDEV_ATTR_DRIVER_U32] = MNL_TYPE_U32,
439         [RDMA_NLDEV_ATTR_DRIVER_S64] = MNL_TYPE_U64,
440         [RDMA_NLDEV_ATTR_DRIVER_U64] = MNL_TYPE_U64,
441         [RDMA_NLDEV_SYS_ATTR_NETNS_MODE] = MNL_TYPE_U8,
442         [RDMA_NLDEV_ATTR_STAT_COUNTER] = MNL_TYPE_NESTED,
443         [RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY] = MNL_TYPE_NESTED,
444         [RDMA_NLDEV_ATTR_STAT_COUNTER_ID] = MNL_TYPE_U32,
445         [RDMA_NLDEV_ATTR_STAT_HWCOUNTERS] = MNL_TYPE_NESTED,
446         [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY] = MNL_TYPE_NESTED,
447         [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME] = MNL_TYPE_NUL_STRING,
448         [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE] = MNL_TYPE_U64,
449         [RDMA_NLDEV_ATTR_STAT_MODE] = MNL_TYPE_U32,
450         [RDMA_NLDEV_ATTR_STAT_RES] = MNL_TYPE_U32,
451         [RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK] = MNL_TYPE_U32,
452         [RDMA_NLDEV_ATTR_DEV_DIM] = MNL_TYPE_U8,
453 };
454
455 int rd_attr_check(const struct nlattr *attr, int *typep)
456 {
457         int type;
458
459         if (mnl_attr_type_valid(attr, RDMA_NLDEV_ATTR_MAX) < 0)
460                 return MNL_CB_ERROR;
461
462         type = mnl_attr_get_type(attr);
463
464         if (mnl_attr_validate(attr, nldev_policy[type]) < 0)
465                 return MNL_CB_ERROR;
466
467         *typep = nldev_policy[type];
468         return MNL_CB_OK;
469 }
470
471 int rd_attr_cb(const struct nlattr *attr, void *data)
472 {
473         const struct nlattr **tb = data;
474         int type;
475
476         if (mnl_attr_type_valid(attr, RDMA_NLDEV_ATTR_MAX - 1) < 0)
477                 /* We received unknown attribute */
478                 return MNL_CB_OK;
479
480         type = mnl_attr_get_type(attr);
481
482         if (mnl_attr_validate(attr, nldev_policy[type]) < 0)
483                 return MNL_CB_ERROR;
484
485         tb[type] = attr;
486         return MNL_CB_OK;
487 }
488
489 int rd_dev_init_cb(const struct nlmsghdr *nlh, void *data)
490 {
491         struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
492         struct dev_map *dev_map;
493         struct rd *rd = data;
494         const char *dev_name;
495
496         mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
497         if (!tb[RDMA_NLDEV_ATTR_DEV_NAME] || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
498                 return MNL_CB_ERROR;
499         if (!tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
500                 pr_err("This tool doesn't support switches yet\n");
501                 return MNL_CB_ERROR;
502         }
503
504         dev_name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
505
506         dev_map = dev_map_alloc(dev_name);
507         if (!dev_map)
508                 /* The main function will cleanup the allocations */
509                 return MNL_CB_ERROR;
510         list_add_tail(&dev_map->list, &rd->dev_map_list);
511
512         dev_map->num_ports = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
513         dev_map->idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
514         return MNL_CB_OK;
515 }
516
517 void rd_free(struct rd *rd)
518 {
519         if (!rd)
520                 return;
521         free(rd->buff);
522         dev_map_cleanup(rd);
523         filters_cleanup(rd);
524 }
525
526 int rd_set_arg_to_devname(struct rd *rd)
527 {
528         int ret = 0;
529
530         while (!rd_no_arg(rd)) {
531                 if (rd_argv_match(rd, "dev") || rd_argv_match(rd, "link")) {
532                         rd_arg_inc(rd);
533                         if (rd_no_arg(rd)) {
534                                 pr_err("No device name was supplied\n");
535                                 ret = -EINVAL;
536                         }
537                         goto out;
538                 }
539                 rd_arg_inc(rd);
540         }
541 out:
542         return ret;
543 }
544
545 int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port)
546 {
547         struct dev_map *dev_map;
548         uint32_t port;
549         int ret = 0;
550
551         new_json_obj(rd->json_output);
552         if (rd_no_arg(rd)) {
553                 list_for_each_entry(dev_map, &rd->dev_map_list, list) {
554                         rd->dev_idx = dev_map->idx;
555                         port = (strict_port) ? 1 : 0;
556                         for (; port < dev_map->num_ports + 1; port++) {
557                                 rd->port_idx = port;
558                                 ret = cb(rd);
559                                 if (ret)
560                                         goto out;
561                         }
562                 }
563
564         } else {
565                 bool is_dump_all;
566
567                 dev_map = dev_map_lookup(rd, true);
568                 ret = get_port_from_argv(rd, &port, &is_dump_all, strict_port);
569                 if (!dev_map || port > dev_map->num_ports || (!port && ret)) {
570                         pr_err("Wrong device name\n");
571                         ret = -ENOENT;
572                         goto out;
573                 }
574                 rd_arg_inc(rd);
575                 rd->dev_idx = dev_map->idx;
576                 rd->port_idx = port;
577                 for (; rd->port_idx < dev_map->num_ports + 1; rd->port_idx++) {
578                         ret = cb(rd);
579                         if (ret)
580                                 goto out;
581                         if (!is_dump_all)
582                                 /*
583                                  * We got request to show link for devname
584                                  * with port index.
585                                  */
586                                 break;
587                 }
588         }
589
590 out:
591         delete_json_obj();
592         return ret;
593 }
594
595 int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd))
596 {
597         struct dev_map *dev_map;
598         int ret = 0;
599
600         new_json_obj(rd->json_output);
601         if (rd_no_arg(rd)) {
602                 list_for_each_entry(dev_map, &rd->dev_map_list, list) {
603                         rd->dev_idx = dev_map->idx;
604                         ret = cb(rd);
605                         if (ret)
606                                 goto out;
607                 }
608         } else {
609                 dev_map = dev_map_lookup(rd, false);
610                 if (!dev_map) {
611                         pr_err("Wrong device name - %s\n", rd_argv(rd));
612                         ret = -ENOENT;
613                         goto out;
614                 }
615                 rd_arg_inc(rd);
616                 rd->dev_idx = dev_map->idx;
617                 ret = cb(rd);
618         }
619 out:
620         delete_json_obj();
621         return ret;
622 }
623
624 int rd_exec_require_dev(struct rd *rd, int (*cb)(struct rd *rd))
625 {
626         if (rd_no_arg(rd)) {
627                 pr_err("Please provide device name.\n");
628                 return -EINVAL;
629         }
630
631         return rd_exec_dev(rd, cb);
632 }
633
634 int rd_exec_cmd(struct rd *rd, const struct rd_cmd *cmds, const char *str)
635 {
636         const struct rd_cmd *c;
637
638         /* First argument in objs table is default variant */
639         if (rd_no_arg(rd))
640                 return cmds->func(rd);
641
642         for (c = cmds + 1; c->cmd; ++c) {
643                 if (rd_argv_match(rd, c->cmd)) {
644                         /* Move to next argument */
645                         rd_arg_inc(rd);
646                         return c->func(rd);
647                 }
648         }
649
650         pr_err("Unknown %s '%s'.\n", str, rd_argv(rd));
651         return 0;
652 }
653
654 void rd_prepare_msg(struct rd *rd, uint32_t cmd, uint32_t *seq, uint16_t flags)
655 {
656         *seq = time(NULL);
657
658         rd->nlh = mnl_nlmsg_put_header(rd->buff);
659         rd->nlh->nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, cmd);
660         rd->nlh->nlmsg_seq = *seq;
661         rd->nlh->nlmsg_flags = flags;
662 }
663
664 int rd_send_msg(struct rd *rd)
665 {
666         int ret;
667
668         rd->nl = mnl_socket_open(NETLINK_RDMA);
669         if (!rd->nl) {
670                 pr_err("Failed to open NETLINK_RDMA socket\n");
671                 return -ENODEV;
672         }
673
674         ret = mnl_socket_bind(rd->nl, 0, MNL_SOCKET_AUTOPID);
675         if (ret < 0) {
676                 pr_err("Failed to bind socket with err %d\n", ret);
677                 goto err;
678         }
679
680         ret = mnl_socket_sendto(rd->nl, rd->nlh, rd->nlh->nlmsg_len);
681         if (ret < 0) {
682                 pr_err("Failed to send to socket with err %d\n", ret);
683                 goto err;
684         }
685         return 0;
686
687 err:
688         mnl_socket_close(rd->nl);
689         return ret;
690 }
691
692 int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, unsigned int seq)
693 {
694         int ret;
695         unsigned int portid;
696         char buf[MNL_SOCKET_BUFFER_SIZE];
697
698         portid = mnl_socket_get_portid(rd->nl);
699         do {
700                 ret = mnl_socket_recvfrom(rd->nl, buf, sizeof(buf));
701                 if (ret <= 0)
702                         break;
703
704                 ret = mnl_cb_run(buf, ret, seq, portid, callback, data);
705         } while (ret > 0);
706
707         if (ret < 0 && !rd->suppress_errors)
708                 perror("error");
709
710         mnl_socket_close(rd->nl);
711         return ret;
712 }
713
714 static int null_cb(const struct nlmsghdr *nlh, void *data)
715 {
716         return MNL_CB_OK;
717 }
718
719 int rd_sendrecv_msg(struct rd *rd, unsigned int seq)
720 {
721         int ret;
722
723         ret = rd_send_msg(rd);
724         if (!ret)
725                 ret = rd_recv_msg(rd, null_cb, rd, seq);
726         return ret;
727 }
728
729 static struct dev_map *_dev_map_lookup(struct rd *rd, const char *dev_name)
730 {
731         struct dev_map *dev_map;
732
733         list_for_each_entry(dev_map, &rd->dev_map_list, list)
734                 if (strcmp(dev_name, dev_map->dev_name) == 0)
735                         return dev_map;
736
737         return NULL;
738 }
739
740 struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index)
741 {
742         struct dev_map *dev_map;
743         char *dev_name;
744         char *slash;
745
746         if (rd_no_arg(rd))
747                 return NULL;
748
749         dev_name = strdup(rd_argv(rd));
750         if (allow_port_index) {
751                 slash = strrchr(dev_name, '/');
752                 if (slash)
753                         *slash = '\0';
754         }
755
756         dev_map = _dev_map_lookup(rd, dev_name);
757         free(dev_name);
758         return dev_map;
759 }
760
761 #define nla_type(attr) ((attr)->nla_type & NLA_TYPE_MASK)
762
763 void newline(struct rd *rd)
764 {
765         close_json_object();
766         print_color_string(PRINT_FP, COLOR_NONE, NULL, "\n", NULL);
767 }
768
769 void newline_indent(struct rd *rd)
770 {
771         newline(rd);
772         print_color_string(PRINT_FP, COLOR_NONE, NULL, "    ", NULL);
773 }
774
775 static int print_driver_string(struct rd *rd, const char *key_str,
776                                  const char *val_str)
777 {
778         print_color_string(PRINT_ANY, COLOR_NONE, key_str, key_str, val_str);
779         print_color_string(PRINT_FP, COLOR_NONE, NULL, " %s ", val_str);
780         return 0;
781 }
782
783 void print_on_off(struct rd *rd, const char *key_str, bool on)
784 {
785         print_driver_string(rd, key_str, (on) ? "on":"off");
786 }
787
788 static int print_driver_s32(struct rd *rd, const char *key_str, int32_t val,
789                               enum rdma_nldev_print_type print_type)
790 {
791         if (!rd->json_output) {
792                 switch (print_type) {
793                 case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
794                         return pr_out("%s %d ", key_str, val);
795                 case RDMA_NLDEV_PRINT_TYPE_HEX:
796                         return pr_out("%s 0x%x ", key_str, val);
797                 default:
798                         return -EINVAL;
799                 }
800         }
801         print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
802         return 0;
803 }
804
805 static int print_driver_u32(struct rd *rd, const char *key_str, uint32_t val,
806                               enum rdma_nldev_print_type print_type)
807 {
808         if (!rd->json_output) {
809                 switch (print_type) {
810                 case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
811                         return pr_out("%s %u ", key_str, val);
812                 case RDMA_NLDEV_PRINT_TYPE_HEX:
813                         return pr_out("%s 0x%x ", key_str, val);
814                 default:
815                         return -EINVAL;
816                 }
817         }
818         print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
819         return 0;
820 }
821
822 static int print_driver_s64(struct rd *rd, const char *key_str, int64_t val,
823                               enum rdma_nldev_print_type print_type)
824 {
825         if (!rd->json_output) {
826                 switch (print_type) {
827                 case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
828                         return pr_out("%s %" PRId64 " ", key_str, val);
829                 case RDMA_NLDEV_PRINT_TYPE_HEX:
830                         return pr_out("%s 0x%" PRIx64 " ", key_str, val);
831                 default:
832                         return -EINVAL;
833                 }
834         }
835         print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
836         return 0;
837 }
838
839 static int print_driver_u64(struct rd *rd, const char *key_str, uint64_t val,
840                               enum rdma_nldev_print_type print_type)
841 {
842         if (!rd->json_output) {
843                 switch (print_type) {
844                 case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
845                         return pr_out("%s %" PRIu64 " ", key_str, val);
846                 case RDMA_NLDEV_PRINT_TYPE_HEX:
847                         return pr_out("%s 0x%" PRIx64 " ", key_str, val);
848                 default:
849                         return -EINVAL;
850                 }
851         }
852         print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
853         return 0;
854 }
855
856 static int print_driver_entry(struct rd *rd, struct nlattr *key_attr,
857                                 struct nlattr *val_attr,
858                                 enum rdma_nldev_print_type print_type)
859 {
860         int attr_type = nla_type(val_attr);
861         int ret = -EINVAL;
862         char *key_str;
863
864         if (asprintf(&key_str, "drv_%s", mnl_attr_get_str(key_attr)) == -1)
865                 return -ENOMEM;
866
867         switch (attr_type) {
868         case RDMA_NLDEV_ATTR_DRIVER_STRING:
869                 ret = print_driver_string(rd, key_str,
870                                           mnl_attr_get_str(val_attr));
871                 break;
872         case RDMA_NLDEV_ATTR_DRIVER_S32:
873                 ret = print_driver_s32(rd, key_str, mnl_attr_get_u32(val_attr),
874                                        print_type);
875                 break;
876         case RDMA_NLDEV_ATTR_DRIVER_U32:
877                 ret = print_driver_u32(rd, key_str, mnl_attr_get_u32(val_attr),
878                                        print_type);
879                 break;
880         case RDMA_NLDEV_ATTR_DRIVER_S64:
881                 ret = print_driver_s64(rd, key_str, mnl_attr_get_u64(val_attr),
882                                        print_type);
883                 break;
884         case RDMA_NLDEV_ATTR_DRIVER_U64:
885                 ret = print_driver_u64(rd, key_str, mnl_attr_get_u64(val_attr),
886                                        print_type);
887                 break;
888         }
889         free(key_str);
890         return ret;
891 }
892
893 void print_driver_table(struct rd *rd, struct nlattr *tb)
894 {
895         int print_type = RDMA_NLDEV_PRINT_TYPE_UNSPEC;
896         struct nlattr *tb_entry, *key = NULL, *val;
897         int type, cc = 0;
898         int ret;
899
900         if (!rd->show_driver_details || !tb)
901                 return;
902
903         if (rd->pretty_output)
904                 newline_indent(rd);
905
906         /*
907          * Driver attrs are tuples of {key, [print-type], value}.
908          * The key must be a string.  If print-type is present, it
909          * defines an alternate printf format type vs the native format
910          * for the attribute.  And the value can be any available
911          * driver type.
912          */
913         mnl_attr_for_each_nested(tb_entry, tb) {
914
915                 if (cc > MAX_LINE_LENGTH) {
916                         if (rd->pretty_output)
917                                 newline_indent(rd);
918                         cc = 0;
919                 }
920                 if (rd_attr_check(tb_entry, &type) != MNL_CB_OK)
921                         return;
922                 if (!key) {
923                         if (type != MNL_TYPE_NUL_STRING)
924                                 return;
925                         key = tb_entry;
926                 } else if (type == MNL_TYPE_U8) {
927                         print_type = mnl_attr_get_u8(tb_entry);
928                 } else {
929                         val = tb_entry;
930                         ret = print_driver_entry(rd, key, val, print_type);
931                         if (ret < 0)
932                                 return;
933                         cc += ret;
934                         print_type = RDMA_NLDEV_PRINT_TYPE_UNSPEC;
935                         key = NULL;
936                 }
937         }
938         return;
939 }