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_NDEV_INDEX]            = MNL_TYPE_U32,
 439        [RDMA_NLDEV_ATTR_NDEV_NAME]             = MNL_TYPE_NUL_STRING,
 440        [RDMA_NLDEV_ATTR_DRIVER] = MNL_TYPE_NESTED,
 441        [RDMA_NLDEV_ATTR_DRIVER_ENTRY] = MNL_TYPE_NESTED,
 442        [RDMA_NLDEV_ATTR_DRIVER_STRING] = MNL_TYPE_NUL_STRING,
 443        [RDMA_NLDEV_ATTR_DRIVER_PRINT_TYPE] = MNL_TYPE_U8,
 444        [RDMA_NLDEV_ATTR_DRIVER_S32] = MNL_TYPE_U32,
 445        [RDMA_NLDEV_ATTR_DRIVER_U32] = MNL_TYPE_U32,
 446        [RDMA_NLDEV_ATTR_DRIVER_S64] = MNL_TYPE_U64,
 447        [RDMA_NLDEV_ATTR_DRIVER_U64] = MNL_TYPE_U64,
 448        [RDMA_NLDEV_SYS_ATTR_NETNS_MODE] = MNL_TYPE_U8,
 449        [RDMA_NLDEV_ATTR_STAT_COUNTER] = MNL_TYPE_NESTED,
 450        [RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY] = MNL_TYPE_NESTED,
 451        [RDMA_NLDEV_ATTR_STAT_COUNTER_ID] = MNL_TYPE_U32,
 452        [RDMA_NLDEV_ATTR_STAT_HWCOUNTERS] = MNL_TYPE_NESTED,
 453        [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY] = MNL_TYPE_NESTED,
 454        [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME] = MNL_TYPE_NUL_STRING,
 455        [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE] = MNL_TYPE_U64,
 456        [RDMA_NLDEV_ATTR_STAT_MODE] = MNL_TYPE_U32,
 457        [RDMA_NLDEV_ATTR_STAT_RES] = MNL_TYPE_U32,
 458        [RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK] = MNL_TYPE_U32,
 459        [RDMA_NLDEV_ATTR_DEV_DIM] = MNL_TYPE_U8,
 460        [RDMA_NLDEV_ATTR_RES_RAW] = MNL_TYPE_BINARY,
 461};
 462
 463int rd_attr_check(const struct nlattr *attr, int *typep)
 464{
 465        int type;
 466
 467        if (mnl_attr_type_valid(attr, RDMA_NLDEV_ATTR_MAX) < 0)
 468                return MNL_CB_ERROR;
 469
 470        type = mnl_attr_get_type(attr);
 471
 472        if (mnl_attr_validate(attr, nldev_policy[type]) < 0)
 473                return MNL_CB_ERROR;
 474
 475        *typep = nldev_policy[type];
 476        return MNL_CB_OK;
 477}
 478
 479int rd_attr_cb(const struct nlattr *attr, void *data)
 480{
 481        const struct nlattr **tb = data;
 482        int type;
 483
 484        if (mnl_attr_type_valid(attr, RDMA_NLDEV_ATTR_MAX - 1) < 0)
 485                /* We received unknown attribute */
 486                return MNL_CB_OK;
 487
 488        type = mnl_attr_get_type(attr);
 489
 490        if (mnl_attr_validate(attr, nldev_policy[type]) < 0)
 491                return MNL_CB_ERROR;
 492
 493        tb[type] = attr;
 494        return MNL_CB_OK;
 495}
 496
 497int rd_dev_init_cb(const struct nlmsghdr *nlh, void *data)
 498{
 499        struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
 500        struct dev_map *dev_map;
 501        struct rd *rd = data;
 502        const char *dev_name;
 503
 504        mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
 505        if (!tb[RDMA_NLDEV_ATTR_DEV_NAME] || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
 506                return MNL_CB_ERROR;
 507        if (!tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
 508                pr_err("This tool doesn't support switches yet\n");
 509                return MNL_CB_ERROR;
 510        }
 511
 512        dev_name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
 513
 514        dev_map = dev_map_alloc(dev_name);
 515        if (!dev_map)
 516                /* The main function will cleanup the allocations */
 517                return MNL_CB_ERROR;
 518        list_add_tail(&dev_map->list, &rd->dev_map_list);
 519
 520        dev_map->num_ports = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
 521        dev_map->idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
 522        return MNL_CB_OK;
 523}
 524
 525void rd_free(struct rd *rd)
 526{
 527        if (!rd)
 528                return;
 529        free(rd->buff);
 530        dev_map_cleanup(rd);
 531        filters_cleanup(rd);
 532}
 533
 534int rd_set_arg_to_devname(struct rd *rd)
 535{
 536        int ret = 0;
 537
 538        while (!rd_no_arg(rd)) {
 539                if (rd_argv_match(rd, "dev") || rd_argv_match(rd, "link")) {
 540                        rd_arg_inc(rd);
 541                        if (rd_no_arg(rd)) {
 542                                pr_err("No device name was supplied\n");
 543                                ret = -EINVAL;
 544                        }
 545                        goto out;
 546                }
 547                rd_arg_inc(rd);
 548        }
 549out:
 550        return ret;
 551}
 552
 553int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port)
 554{
 555        struct dev_map *dev_map;
 556        uint32_t port;
 557        int ret = 0;
 558
 559        new_json_obj(rd->json_output);
 560        if (rd_no_arg(rd)) {
 561                list_for_each_entry(dev_map, &rd->dev_map_list, list) {
 562                        rd->dev_idx = dev_map->idx;
 563                        port = (strict_port) ? 1 : 0;
 564                        for (; port < dev_map->num_ports + 1; port++) {
 565                                rd->port_idx = port;
 566                                ret = cb(rd);
 567                                if (ret)
 568                                        goto out;
 569                        }
 570                }
 571
 572        } else {
 573                bool is_dump_all;
 574
 575                dev_map = dev_map_lookup(rd, true);
 576                ret = get_port_from_argv(rd, &port, &is_dump_all, strict_port);
 577                if (!dev_map || port > dev_map->num_ports || (!port && ret)) {
 578                        pr_err("Wrong device name\n");
 579                        ret = -ENOENT;
 580                        goto out;
 581                }
 582                rd_arg_inc(rd);
 583                rd->dev_idx = dev_map->idx;
 584                rd->port_idx = port;
 585                for (; rd->port_idx < dev_map->num_ports + 1; rd->port_idx++) {
 586                        ret = cb(rd);
 587                        if (ret)
 588                                goto out;
 589                        if (!is_dump_all)
 590                                /*
 591                                 * We got request to show link for devname
 592                                 * with port index.
 593                                 */
 594                                break;
 595                }
 596        }
 597
 598out:
 599        delete_json_obj();
 600        return ret;
 601}
 602
 603int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd))
 604{
 605        struct dev_map *dev_map;
 606        int ret = 0;
 607
 608        new_json_obj(rd->json_output);
 609        if (rd_no_arg(rd)) {
 610                list_for_each_entry(dev_map, &rd->dev_map_list, list) {
 611                        rd->dev_idx = dev_map->idx;
 612                        ret = cb(rd);
 613                        if (ret)
 614                                goto out;
 615                }
 616        } else {
 617                dev_map = dev_map_lookup(rd, false);
 618                if (!dev_map) {
 619                        pr_err("Wrong device name - %s\n", rd_argv(rd));
 620                        ret = -ENOENT;
 621                        goto out;
 622                }
 623                rd_arg_inc(rd);
 624                rd->dev_idx = dev_map->idx;
 625                ret = cb(rd);
 626        }
 627out:
 628        delete_json_obj();
 629        return ret;
 630}
 631
 632int rd_exec_require_dev(struct rd *rd, int (*cb)(struct rd *rd))
 633{
 634        if (rd_no_arg(rd)) {
 635                pr_err("Please provide device name.\n");
 636                return -EINVAL;
 637        }
 638
 639        return rd_exec_dev(rd, cb);
 640}
 641
 642int rd_exec_cmd(struct rd *rd, const struct rd_cmd *cmds, const char *str)
 643{
 644        const struct rd_cmd *c;
 645
 646        /* First argument in objs table is default variant */
 647        if (rd_no_arg(rd))
 648                return cmds->func(rd);
 649
 650        for (c = cmds + 1; c->cmd; ++c) {
 651                if (rd_argv_match(rd, c->cmd)) {
 652                        /* Move to next argument */
 653                        rd_arg_inc(rd);
 654                        return c->func(rd);
 655                }
 656        }
 657
 658        pr_err("Unknown %s '%s'.\n", str, rd_argv(rd));
 659        return 0;
 660}
 661
 662void rd_prepare_msg(struct rd *rd, uint32_t cmd, uint32_t *seq, uint16_t flags)
 663{
 664        *seq = time(NULL);
 665
 666        rd->nlh = mnl_nlmsg_put_header(rd->buff);
 667        rd->nlh->nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, cmd);
 668        rd->nlh->nlmsg_seq = *seq;
 669        rd->nlh->nlmsg_flags = flags;
 670}
 671
 672int rd_send_msg(struct rd *rd)
 673{
 674        int ret;
 675
 676        rd->nl = mnlu_socket_open(NETLINK_RDMA);
 677        if (!rd->nl) {
 678                pr_err("Failed to open NETLINK_RDMA socket\n");
 679                return -ENODEV;
 680        }
 681
 682        ret = mnl_socket_sendto(rd->nl, rd->nlh, rd->nlh->nlmsg_len);
 683        if (ret < 0) {
 684                pr_err("Failed to send to socket with err %d\n", ret);
 685                goto err;
 686        }
 687        return 0;
 688
 689err:
 690        mnl_socket_close(rd->nl);
 691        return ret;
 692}
 693
 694int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, unsigned int seq)
 695{
 696        char buf[MNL_SOCKET_BUFFER_SIZE];
 697        int ret;
 698
 699        ret = mnlu_socket_recv_run(rd->nl, seq, buf, MNL_SOCKET_BUFFER_SIZE,
 700                                   callback, data);
 701        if (ret < 0 && !rd->suppress_errors)
 702                perror("error");
 703        return ret;
 704}
 705
 706static int null_cb(const struct nlmsghdr *nlh, void *data)
 707{
 708        return MNL_CB_OK;
 709}
 710
 711int rd_sendrecv_msg(struct rd *rd, unsigned int seq)
 712{
 713        int ret;
 714
 715        ret = rd_send_msg(rd);
 716        if (!ret)
 717                ret = rd_recv_msg(rd, null_cb, rd, seq);
 718        return ret;
 719}
 720
 721static struct dev_map *_dev_map_lookup(struct rd *rd, const char *dev_name)
 722{
 723        struct dev_map *dev_map;
 724
 725        list_for_each_entry(dev_map, &rd->dev_map_list, list)
 726                if (strcmp(dev_name, dev_map->dev_name) == 0)
 727                        return dev_map;
 728
 729        return NULL;
 730}
 731
 732struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index)
 733{
 734        struct dev_map *dev_map;
 735        char *dev_name;
 736        char *slash;
 737
 738        if (rd_no_arg(rd))
 739                return NULL;
 740
 741        dev_name = strdup(rd_argv(rd));
 742        if (allow_port_index) {
 743                slash = strrchr(dev_name, '/');
 744                if (slash)
 745                        *slash = '\0';
 746        }
 747
 748        dev_map = _dev_map_lookup(rd, dev_name);
 749        free(dev_name);
 750        return dev_map;
 751}
 752
 753#define nla_type(attr) ((attr)->nla_type & NLA_TYPE_MASK)
 754
 755void newline(struct rd *rd)
 756{
 757        close_json_object();
 758        print_color_string(PRINT_FP, COLOR_NONE, NULL, "\n", NULL);
 759}
 760
 761void newline_indent(struct rd *rd)
 762{
 763        newline(rd);
 764        print_color_string(PRINT_FP, COLOR_NONE, NULL, "    ", NULL);
 765}
 766
 767static int print_driver_string(struct rd *rd, const char *key_str,
 768                                 const char *val_str)
 769{
 770        print_color_string(PRINT_ANY, COLOR_NONE, key_str, key_str, val_str);
 771        print_color_string(PRINT_FP, COLOR_NONE, NULL, " %s ", val_str);
 772        return 0;
 773}
 774
 775static int print_driver_s32(struct rd *rd, const char *key_str, int32_t val,
 776                              enum rdma_nldev_print_type print_type)
 777{
 778        if (!rd->json_output) {
 779                switch (print_type) {
 780                case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
 781                        return pr_out("%s %d ", key_str, val);
 782                case RDMA_NLDEV_PRINT_TYPE_HEX:
 783                        return pr_out("%s 0x%x ", key_str, val);
 784                default:
 785                        return -EINVAL;
 786                }
 787        }
 788        print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
 789        return 0;
 790}
 791
 792static int print_driver_u32(struct rd *rd, const char *key_str, uint32_t val,
 793                              enum rdma_nldev_print_type print_type)
 794{
 795        if (!rd->json_output) {
 796                switch (print_type) {
 797                case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
 798                        return pr_out("%s %u ", key_str, val);
 799                case RDMA_NLDEV_PRINT_TYPE_HEX:
 800                        return pr_out("%s 0x%x ", key_str, val);
 801                default:
 802                        return -EINVAL;
 803                }
 804        }
 805        print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
 806        return 0;
 807}
 808
 809static int print_driver_s64(struct rd *rd, const char *key_str, int64_t val,
 810                              enum rdma_nldev_print_type print_type)
 811{
 812        if (!rd->json_output) {
 813                switch (print_type) {
 814                case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
 815                        return pr_out("%s %" PRId64 " ", key_str, val);
 816                case RDMA_NLDEV_PRINT_TYPE_HEX:
 817                        return pr_out("%s 0x%" PRIx64 " ", key_str, val);
 818                default:
 819                        return -EINVAL;
 820                }
 821        }
 822        print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
 823        return 0;
 824}
 825
 826static int print_driver_u64(struct rd *rd, const char *key_str, uint64_t val,
 827                              enum rdma_nldev_print_type print_type)
 828{
 829        if (!rd->json_output) {
 830                switch (print_type) {
 831                case RDMA_NLDEV_PRINT_TYPE_UNSPEC:
 832                        return pr_out("%s %" PRIu64 " ", key_str, val);
 833                case RDMA_NLDEV_PRINT_TYPE_HEX:
 834                        return pr_out("%s 0x%" PRIx64 " ", key_str, val);
 835                default:
 836                        return -EINVAL;
 837                }
 838        }
 839        print_color_int(PRINT_JSON, COLOR_NONE, key_str, NULL, val);
 840        return 0;
 841}
 842
 843static int print_driver_entry(struct rd *rd, struct nlattr *key_attr,
 844                                struct nlattr *val_attr,
 845                                enum rdma_nldev_print_type print_type)
 846{
 847        int attr_type = nla_type(val_attr);
 848        int ret = -EINVAL;
 849        char *key_str;
 850
 851        if (asprintf(&key_str, "drv_%s", mnl_attr_get_str(key_attr)) == -1)
 852                return -ENOMEM;
 853
 854        switch (attr_type) {
 855        case RDMA_NLDEV_ATTR_DRIVER_STRING:
 856                ret = print_driver_string(rd, key_str,
 857                                          mnl_attr_get_str(val_attr));
 858                break;
 859        case RDMA_NLDEV_ATTR_DRIVER_S32:
 860                ret = print_driver_s32(rd, key_str, mnl_attr_get_u32(val_attr),
 861                                       print_type);
 862                break;
 863        case RDMA_NLDEV_ATTR_DRIVER_U32:
 864                ret = print_driver_u32(rd, key_str, mnl_attr_get_u32(val_attr),
 865                                       print_type);
 866                break;
 867        case RDMA_NLDEV_ATTR_DRIVER_S64:
 868                ret = print_driver_s64(rd, key_str, mnl_attr_get_u64(val_attr),
 869                                       print_type);
 870                break;
 871        case RDMA_NLDEV_ATTR_DRIVER_U64:
 872                ret = print_driver_u64(rd, key_str, mnl_attr_get_u64(val_attr),
 873                                       print_type);
 874                break;
 875        }
 876        free(key_str);
 877        return ret;
 878}
 879
 880void print_raw_data(struct rd *rd, struct nlattr **nla_line)
 881{
 882        uint8_t *data;
 883        uint32_t len;
 884        int i = 0;
 885
 886        if (!rd->show_raw)
 887                return;
 888
 889        len = mnl_attr_get_payload_len(nla_line[RDMA_NLDEV_ATTR_RES_RAW]);
 890        data = mnl_attr_get_payload(nla_line[RDMA_NLDEV_ATTR_RES_RAW]);
 891        open_json_array(PRINT_JSON, "data");
 892        while (i < len) {
 893                print_color_uint(PRINT_ANY, COLOR_NONE, NULL, "%d", data[i]);
 894                i++;
 895        }
 896        close_json_array(PRINT_ANY, ">");
 897}
 898
 899void print_driver_table(struct rd *rd, struct nlattr *tb)
 900{
 901        int print_type = RDMA_NLDEV_PRINT_TYPE_UNSPEC;
 902        struct nlattr *tb_entry, *key = NULL, *val;
 903        int type, cc = 0;
 904        int ret;
 905
 906        if (!rd->show_driver_details || !tb)
 907                return;
 908
 909        if (rd->pretty_output)
 910                newline_indent(rd);
 911
 912        /*
 913         * Driver attrs are tuples of {key, [print-type], value}.
 914         * The key must be a string.  If print-type is present, it
 915         * defines an alternate printf format type vs the native format
 916         * for the attribute.  And the value can be any available
 917         * driver type.
 918         */
 919        mnl_attr_for_each_nested(tb_entry, tb) {
 920
 921                if (cc > MAX_LINE_LENGTH) {
 922                        if (rd->pretty_output)
 923                                newline_indent(rd);
 924                        cc = 0;
 925                }
 926                if (rd_attr_check(tb_entry, &type) != MNL_CB_OK)
 927                        return;
 928                if (!key) {
 929                        if (type != MNL_TYPE_NUL_STRING)
 930                                return;
 931                        key = tb_entry;
 932                } else if (type == MNL_TYPE_U8) {
 933                        print_type = mnl_attr_get_u8(tb_entry);
 934                } else {
 935                        val = tb_entry;
 936                        ret = print_driver_entry(rd, key, val, print_type);
 937                        if (ret < 0)
 938                                return;
 939                        cc += ret;
 940                        print_type = RDMA_NLDEV_PRINT_TYPE_UNSPEC;
 941                        key = NULL;
 942                }
 943        }
 944        return;
 945}
 946