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