iproute2/rdma/dev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2/*
   3 * dev.c        RDMA tool
   4 * Authors:     Leon Romanovsky <leonro@mellanox.com>
   5 */
   6
   7#include <fcntl.h>
   8#include "rdma.h"
   9
  10static int dev_help(struct rd *rd)
  11{
  12        pr_out("Usage: %s dev show [DEV]\n", rd->filename);
  13        pr_out("       %s dev set [DEV] name DEVNAME\n", rd->filename);
  14        pr_out("       %s dev set [DEV] netns NSNAME\n", rd->filename);
  15        pr_out("       %s dev set [DEV] adaptive-moderation [on|off]\n", rd->filename);
  16        return 0;
  17}
  18
  19static const char *dev_caps_to_str(uint32_t idx)
  20{
  21#define RDMA_DEV_FLAGS_LOW(x) \
  22        x(RESIZE_MAX_WR, 0) \
  23        x(BAD_PKEY_CNTR, 1) \
  24        x(BAD_QKEY_CNTR, 2) \
  25        x(RAW_MULTI, 3) \
  26        x(AUTO_PATH_MIG, 4) \
  27        x(CHANGE_PHY_PORT, 5) \
  28        x(UD_AV_PORT_ENFORCE_PORT_ENFORCE, 6) \
  29        x(CURR_QP_STATE_MOD, 7) \
  30        x(SHUTDOWN_PORT, 8) \
  31        x(INIT_TYPE, 9) \
  32        x(PORT_ACTIVE_EVENT, 10) \
  33        x(SYS_IMAGE_GUID, 11) \
  34        x(RC_RNR_NAK_GEN, 12) \
  35        x(SRQ_RESIZE, 13) \
  36        x(N_NOTIFY_CQ, 14) \
  37        x(LOCAL_DMA_LKEY, 15) \
  38        x(MEM_WINDOW, 17) \
  39        x(UD_IP_CSUM, 18) \
  40        x(UD_TSO, 19) \
  41        x(XRC, 20) \
  42        x(MEM_MGT_EXTENSIONS, 21) \
  43        x(BLOCK_MULTICAST_LOOPBACK, 22) \
  44        x(MEM_WINDOW_TYPE_2A, 23) \
  45        x(MEM_WINDOW_TYPE_2B, 24) \
  46        x(RC_IP_CSUM, 25) \
  47        x(RAW_IP_CSUM, 26) \
  48        x(CROSS_CHANNEL, 27) \
  49        x(MANAGED_FLOW_STEERING, 29) \
  50        x(SIGNATURE_HANDOVER, 30) \
  51        x(ON_DEMAND_PAGING, 31)
  52
  53#define RDMA_DEV_FLAGS_HIGH(x) \
  54        x(SG_GAPS_REG, 0) \
  55        x(VIRTUAL_FUNCTION, 1) \
  56        x(RAW_SCATTER_FCS, 2) \
  57        x(RDMA_NETDEV_OPA_VNIC, 3) \
  58        x(PCI_WRITE_END_PADDING, 4)
  59
  60        /*
  61         * Separation below is needed to allow compilation of rdmatool
  62         * on 32bits systems. On such systems, C-enum is limited to be
  63         * int and can't hold more than 32 bits.
  64         */
  65        enum { RDMA_DEV_FLAGS_LOW(RDMA_BITMAP_ENUM) };
  66        enum { RDMA_DEV_FLAGS_HIGH(RDMA_BITMAP_ENUM) };
  67
  68        static const char * const
  69                rdma_dev_names_low[] = { RDMA_DEV_FLAGS_LOW(RDMA_BITMAP_NAMES) };
  70        static const char * const
  71                rdma_dev_names_high[] = { RDMA_DEV_FLAGS_HIGH(RDMA_BITMAP_NAMES) };
  72        uint32_t high_idx;
  73        #undef RDMA_DEV_FLAGS_LOW
  74        #undef RDMA_DEV_FLAGS_HIGH
  75
  76        if (idx < ARRAY_SIZE(rdma_dev_names_low) && rdma_dev_names_low[idx])
  77                return rdma_dev_names_low[idx];
  78
  79        high_idx = idx - ARRAY_SIZE(rdma_dev_names_low);
  80        if (high_idx <  ARRAY_SIZE(rdma_dev_names_high) &&
  81            rdma_dev_names_high[high_idx])
  82                return rdma_dev_names_high[high_idx];
  83
  84        return "UNKNOWN";
  85}
  86
  87static void dev_print_caps(struct rd *rd, struct nlattr **tb)
  88{
  89        uint64_t caps;
  90        uint32_t idx;
  91
  92        if (!tb[RDMA_NLDEV_ATTR_CAP_FLAGS])
  93                return;
  94
  95        caps = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_CAP_FLAGS]);
  96
  97        print_color_string(PRINT_FP, COLOR_NONE, NULL, "\n    caps: <", NULL);
  98        open_json_array(PRINT_JSON, "caps");
  99        for (idx = 0; caps; idx++) {
 100                if (caps & 0x1)
 101                        print_color_string(PRINT_ANY, COLOR_NONE, NULL,
 102                                           caps >> 0x1 ? "%s, " : "%s",
 103                                           dev_caps_to_str(idx));
 104                caps >>= 0x1;
 105        }
 106        close_json_array(PRINT_ANY, ">");
 107}
 108
 109static void dev_print_fw(struct rd *rd, struct nlattr **tb)
 110{
 111        const char *str;
 112        if (!tb[RDMA_NLDEV_ATTR_FW_VERSION])
 113                return;
 114
 115        str = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_FW_VERSION]);
 116        print_color_string(PRINT_ANY, COLOR_NONE, "fw", "fw %s ", str);
 117}
 118
 119static void dev_print_node_guid(struct rd *rd, struct nlattr **tb)
 120{
 121        uint64_t node_guid;
 122        uint16_t vp[4];
 123        char str[32];
 124
 125        if (!tb[RDMA_NLDEV_ATTR_NODE_GUID])
 126                return;
 127
 128        node_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_NODE_GUID]);
 129        memcpy(vp, &node_guid, sizeof(uint64_t));
 130        snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
 131        print_color_string(PRINT_ANY, COLOR_NONE, "node_guid", "node_guid %s ",
 132                           str);
 133}
 134
 135static void dev_print_sys_image_guid(struct rd *rd, struct nlattr **tb)
 136{
 137        uint64_t sys_image_guid;
 138        uint16_t vp[4];
 139        char str[32];
 140
 141        if (!tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID])
 142                return;
 143
 144        sys_image_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID]);
 145        memcpy(vp, &sys_image_guid, sizeof(uint64_t));
 146        snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
 147        print_color_string(PRINT_ANY, COLOR_NONE, "sys_image_guid",
 148                           "sys_image_guid %s ", str);
 149}
 150
 151static void dev_print_dim_setting(struct rd *rd, struct nlattr **tb)
 152{
 153        uint8_t dim_setting;
 154
 155        if (!tb[RDMA_NLDEV_ATTR_DEV_DIM])
 156                return;
 157
 158        dim_setting = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_DIM]);
 159        if (dim_setting > 1)
 160                return;
 161
 162        print_on_off(PRINT_ANY, "adaptive-moderation", "adaptive-moderation %s ", dim_setting);
 163
 164}
 165
 166static const char *node_type_to_str(uint8_t node_type)
 167{
 168        static const char * const node_type_str[] = { "unknown", "ca",
 169                                                      "switch", "router",
 170                                                      "rnic", "usnic",
 171                                                      "usnic_udp",
 172                                                      "unspecified" };
 173        if (node_type < ARRAY_SIZE(node_type_str))
 174                return node_type_str[node_type];
 175        return "unknown";
 176}
 177
 178static void dev_print_node_type(struct rd *rd, struct nlattr **tb)
 179{
 180        const char *node_str;
 181        uint8_t node_type;
 182
 183        if (!tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE])
 184                return;
 185
 186        node_type = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE]);
 187        node_str = node_type_to_str(node_type);
 188        print_color_string(PRINT_ANY, COLOR_NONE, "node_type", "node_type %s ",
 189                           node_str);
 190}
 191
 192static int dev_parse_cb(const struct nlmsghdr *nlh, void *data)
 193{
 194        struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
 195        struct rd *rd = data;
 196        const char *name;
 197        uint32_t idx;
 198
 199        mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
 200        if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
 201                return MNL_CB_ERROR;
 202        open_json_object(NULL);
 203        idx =  mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
 204        name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
 205        print_color_uint(PRINT_ANY, COLOR_NONE, "ifindex", "%u: ", idx);
 206        print_color_string(PRINT_ANY, COLOR_NONE, "ifname", "%s: ", name);
 207
 208        dev_print_node_type(rd, tb);
 209        dev_print_fw(rd, tb);
 210        dev_print_node_guid(rd, tb);
 211        dev_print_sys_image_guid(rd, tb);
 212        if (rd->show_details) {
 213                dev_print_dim_setting(rd, tb);
 214                dev_print_caps(rd, tb);
 215        }
 216
 217        newline(rd);
 218        return MNL_CB_OK;
 219}
 220
 221static int dev_no_args(struct rd *rd)
 222{
 223        uint32_t seq;
 224        int ret;
 225
 226        rd_prepare_msg(rd, RDMA_NLDEV_CMD_GET,
 227                       &seq, (NLM_F_REQUEST | NLM_F_ACK));
 228        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
 229        ret = rd_send_msg(rd);
 230        if (ret)
 231                return ret;
 232
 233        ret = rd_recv_msg(rd, dev_parse_cb, rd, seq);
 234        return ret;
 235}
 236
 237static int dev_one_show(struct rd *rd)
 238{
 239        const struct rd_cmd cmds[] = {
 240                { NULL,         dev_no_args},
 241                { 0 }
 242        };
 243
 244        return rd_exec_cmd(rd, cmds, "parameter");
 245}
 246
 247static int dev_set_name(struct rd *rd)
 248{
 249        uint32_t seq;
 250
 251        if (rd_no_arg(rd)) {
 252                pr_err("Please provide device new name.\n");
 253                return -EINVAL;
 254        }
 255
 256        rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET,
 257                       &seq, (NLM_F_REQUEST | NLM_F_ACK));
 258        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
 259        mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd_argv(rd));
 260
 261        return rd_sendrecv_msg(rd, seq);
 262}
 263
 264static int dev_set_netns(struct rd *rd)
 265{
 266        char *netns_path;
 267        uint32_t seq;
 268        int netns;
 269        int ret;
 270
 271        if (rd_no_arg(rd)) {
 272                pr_err("Please provide device name.\n");
 273                return -EINVAL;
 274        }
 275
 276        if (asprintf(&netns_path, "%s/%s", NETNS_RUN_DIR, rd_argv(rd)) < 0)
 277                return -ENOMEM;
 278
 279        netns = open(netns_path, O_RDONLY | O_CLOEXEC);
 280        if (netns < 0) {
 281                fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
 282                        rd_argv(rd), strerror(errno));
 283                ret = -EINVAL;
 284                goto done;
 285        }
 286
 287        rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET,
 288                       &seq, (NLM_F_REQUEST | NLM_F_ACK));
 289        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
 290        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_NET_NS_FD, netns);
 291        ret = rd_sendrecv_msg(rd, seq);
 292        close(netns);
 293done:
 294        free(netns_path);
 295        return ret;
 296}
 297
 298static int dev_set_dim_sendmsg(struct rd *rd, uint8_t dim_setting)
 299{
 300        uint32_t seq;
 301
 302        rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET, &seq,
 303                       (NLM_F_REQUEST | NLM_F_ACK));
 304        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
 305        mnl_attr_put_u8(rd->nlh, RDMA_NLDEV_ATTR_DEV_DIM, dim_setting);
 306
 307        return rd_sendrecv_msg(rd, seq);
 308}
 309
 310static int dev_set_dim_off(struct rd *rd)
 311{
 312        return dev_set_dim_sendmsg(rd, 0);
 313}
 314
 315static int dev_set_dim_on(struct rd *rd)
 316{
 317        return dev_set_dim_sendmsg(rd, 1);
 318}
 319
 320static int dev_set_dim(struct rd *rd)
 321{
 322        const struct rd_cmd cmds[] = {
 323                { NULL,         dev_help},
 324                { "on",         dev_set_dim_on},
 325                { "off",        dev_set_dim_off},
 326                { 0 }
 327        };
 328
 329        return rd_exec_cmd(rd, cmds, "parameter");
 330}
 331
 332static int dev_one_set(struct rd *rd)
 333{
 334        const struct rd_cmd cmds[] = {
 335                { NULL,         dev_help},
 336                { "name",       dev_set_name},
 337                { "netns",      dev_set_netns},
 338                { "adaptive-moderation",        dev_set_dim},
 339                { 0 }
 340        };
 341
 342        return rd_exec_cmd(rd, cmds, "parameter");
 343}
 344
 345static int dev_show(struct rd *rd)
 346{
 347        return rd_exec_dev(rd, dev_one_show);
 348}
 349
 350static int dev_set(struct rd *rd)
 351{
 352        return rd_exec_require_dev(rd, dev_one_set);
 353}
 354
 355int cmd_dev(struct rd *rd)
 356{
 357        const struct rd_cmd cmds[] = {
 358                { NULL,         dev_show },
 359                { "show",       dev_show },
 360                { "list",       dev_show },
 361                { "set",        dev_set },
 362                { "help",       dev_help },
 363                { 0 }
 364        };
 365
 366        return rd_exec_cmd(rd, cmds, "dev command");
 367}
 368