iproute2/rdma/link.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2/*
   3 * link.c       RDMA tool
   4 * Authors:     Leon Romanovsky <leonro@mellanox.com>
   5 */
   6
   7#include "rdma.h"
   8
   9static int link_help(struct rd *rd)
  10{
  11        pr_out("Usage: %s link show [DEV/PORT_INDEX]\n", rd->filename);
  12        pr_out("Usage: %s link add NAME type TYPE netdev NETDEV\n",
  13               rd->filename);
  14        pr_out("Usage: %s link delete NAME\n", rd->filename);
  15        return 0;
  16}
  17
  18static const char *caps_to_str(uint32_t idx)
  19{
  20#define RDMA_PORT_FLAGS_LOW(x) \
  21        x(RESERVED, 0) \
  22        x(SM, 1) \
  23        x(NOTICE, 2) \
  24        x(TRAP, 3) \
  25        x(OPT_IPD, 4) \
  26        x(AUTO_MIGR, 5) \
  27        x(SL_MAP, 6) \
  28        x(MKEY_NVRAM, 7) \
  29        x(PKEY_NVRAM, 8) \
  30        x(LED_INFO, 9) \
  31        x(SM_DISABLED, 10) \
  32        x(SYS_IMAGE_GUID, 11) \
  33        x(PKEY_SW_EXT_PORT_TRAP, 12) \
  34        x(CABLE_INFO, 13) \
  35        x(EXTENDED_SPEEDS, 14) \
  36        x(CAP_MASK2, 15) \
  37        x(CM, 16) \
  38        x(SNMP_TUNNEL, 17) \
  39        x(REINIT, 18) \
  40        x(DEVICE_MGMT, 19) \
  41        x(VENDOR_CLASS, 20) \
  42        x(DR_NOTICE, 21) \
  43        x(CAP_MASK_NOTICE, 22) \
  44        x(BOOT_MGMT, 23) \
  45        x(LINK_LATENCY, 24) \
  46        x(CLIENT_REG, 25) \
  47        x(OTHER_LOCAL_CHANGES, 26) \
  48        x(LINK_SPPED_WIDTH, 27) \
  49        x(VENDOR_SPECIFIC_MADS, 28) \
  50        x(MULT_PKER_TRAP, 29) \
  51        x(MULT_FDB, 30) \
  52        x(HIERARCHY_INFO, 31)
  53
  54#define RDMA_PORT_FLAGS_HIGH(x) \
  55        x(SET_NODE_DESC, 0) \
  56        x(EXT_INFO, 1) \
  57        x(VIRT, 2) \
  58        x(SWITCH_POR_STATE_TABLE, 3) \
  59        x(LINK_WIDTH_2X, 4) \
  60        x(LINK_SPEED_HDR, 5)
  61
  62        /*
  63         * Separation below is needed to allow compilation of rdmatool
  64         * on 32bits systems. On such systems, C-enum is limited to be
  65         * int and can't hold more than 32 bits.
  66         */
  67        enum { RDMA_PORT_FLAGS_LOW(RDMA_BITMAP_ENUM) };
  68        enum { RDMA_PORT_FLAGS_HIGH(RDMA_BITMAP_ENUM) };
  69
  70        static const char * const
  71                rdma_port_names_low[] = { RDMA_PORT_FLAGS_LOW(RDMA_BITMAP_NAMES) };
  72        static const char * const
  73                rdma_port_names_high[] = { RDMA_PORT_FLAGS_HIGH(RDMA_BITMAP_NAMES) };
  74        uint32_t high_idx;
  75        #undef RDMA_PORT_FLAGS_LOW
  76        #undef RDMA_PORT_FLAGS_HIGH
  77
  78        if (idx < ARRAY_SIZE(rdma_port_names_low) && rdma_port_names_low[idx])
  79                return rdma_port_names_low[idx];
  80
  81        high_idx = idx - ARRAY_SIZE(rdma_port_names_low);
  82        if (high_idx < ARRAY_SIZE(rdma_port_names_high) &&
  83            rdma_port_names_high[high_idx])
  84                return rdma_port_names_high[high_idx];
  85
  86        return "UNKNOWN";
  87}
  88
  89static void link_print_caps(struct rd *rd, struct nlattr **tb)
  90{
  91        uint64_t caps;
  92        uint32_t idx;
  93
  94        if (!tb[RDMA_NLDEV_ATTR_CAP_FLAGS])
  95                return;
  96
  97        caps = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_CAP_FLAGS]);
  98
  99        print_color_string(PRINT_FP, COLOR_NONE, NULL, "\n    caps: <", NULL);
 100        open_json_array(PRINT_JSON, "caps");
 101        for (idx = 0; caps; idx++) {
 102                if (caps & 0x1)
 103                        print_color_string(PRINT_ANY, COLOR_NONE, NULL,
 104                                           caps >> 0x1 ? "%s, " : "%s",
 105                                           caps_to_str(idx));
 106                caps >>= 0x1;
 107        }
 108        close_json_array(PRINT_ANY, ">");
 109}
 110
 111static void link_print_subnet_prefix(struct rd *rd, struct nlattr **tb)
 112{
 113        uint64_t subnet_prefix;
 114        uint16_t vp[4];
 115        char str[32];
 116
 117        if (!tb[RDMA_NLDEV_ATTR_SUBNET_PREFIX])
 118                return;
 119
 120        subnet_prefix = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_SUBNET_PREFIX]);
 121        memcpy(vp, &subnet_prefix, sizeof(uint64_t));
 122        snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
 123        print_color_string(PRINT_ANY, COLOR_NONE, "subnet_prefix",
 124                           "subnet_prefix %s ", str);
 125}
 126
 127static void link_print_lid(struct rd *rd, struct nlattr **tb)
 128{
 129        uint32_t lid;
 130
 131        if (!tb[RDMA_NLDEV_ATTR_LID])
 132                return;
 133
 134        lid = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_LID]);
 135        print_color_uint(PRINT_ANY, COLOR_NONE, "lid", "lid %u ", lid);
 136}
 137
 138static void link_print_sm_lid(struct rd *rd, struct nlattr **tb)
 139{
 140        uint32_t sm_lid;
 141
 142        if (!tb[RDMA_NLDEV_ATTR_SM_LID])
 143                return;
 144
 145        sm_lid = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_SM_LID]);
 146        print_color_uint(PRINT_ANY, COLOR_NONE, "sm_lid", "sm_lid %u ", sm_lid);
 147}
 148
 149static void link_print_lmc(struct rd *rd, struct nlattr **tb)
 150{
 151        uint8_t lmc;
 152
 153        if (!tb[RDMA_NLDEV_ATTR_LMC])
 154                return;
 155
 156        lmc = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_LMC]);
 157        print_color_uint(PRINT_ANY, COLOR_NONE, "lmc", "lmc %u ", lmc);
 158}
 159
 160static const char *link_state_to_str(uint8_t link_state)
 161{
 162        static const char * const link_state_str[] = { "NOP", "DOWN",
 163                                                       "INIT", "ARMED",
 164                                                       "ACTIVE",
 165                                                       "ACTIVE_DEFER" };
 166        if (link_state < ARRAY_SIZE(link_state_str))
 167                return link_state_str[link_state];
 168        return "UNKNOWN";
 169}
 170
 171static void link_print_state(struct rd *rd, struct nlattr **tb)
 172{
 173        uint8_t state;
 174
 175        if (!tb[RDMA_NLDEV_ATTR_PORT_STATE])
 176                return;
 177
 178        state = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_PORT_STATE]);
 179        print_color_string(PRINT_ANY, COLOR_NONE, "state", "state %s ",
 180                           link_state_to_str(state));
 181}
 182
 183static const char *phys_state_to_str(uint8_t phys_state)
 184{
 185        static const char * const phys_state_str[] = { "NOP", "SLEEP",
 186                                                       "POLLING", "DISABLED",
 187                                                       "ARMED", "LINK_UP",
 188                                                       "LINK_ERROR_RECOVER",
 189                                                       "PHY_TEST", "UNKNOWN",
 190                                                       "OPA_OFFLINE",
 191                                                       "UNKNOWN", "OPA_TEST" };
 192        if (phys_state < ARRAY_SIZE(phys_state_str))
 193                return phys_state_str[phys_state];
 194        return "UNKNOWN";
 195};
 196
 197static void link_print_phys_state(struct rd *rd, struct nlattr **tb)
 198{
 199        uint8_t phys_state;
 200
 201        if (!tb[RDMA_NLDEV_ATTR_PORT_PHYS_STATE])
 202                return;
 203
 204        phys_state = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_PORT_PHYS_STATE]);
 205        print_color_string(PRINT_ANY, COLOR_NONE, "physical_state",
 206                           "physical_state %s ", phys_state_to_str(phys_state));
 207}
 208
 209static void link_print_netdev(struct rd *rd, struct nlattr **tb)
 210{
 211        const char *netdev_name;
 212        uint32_t idx;
 213
 214        if (!tb[RDMA_NLDEV_ATTR_NDEV_NAME] || !tb[RDMA_NLDEV_ATTR_NDEV_INDEX])
 215                return;
 216
 217        netdev_name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_NDEV_NAME]);
 218        idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_NDEV_INDEX]);
 219        print_color_string(PRINT_ANY, COLOR_NONE, "netdev", "netdev %s ",
 220                           netdev_name);
 221        print_color_uint(PRINT_ANY, COLOR_NONE, "netdev_index",
 222                         rd->show_details ? "netdev_index %u " : "", idx);
 223}
 224
 225static int link_parse_cb(const struct nlmsghdr *nlh, void *data)
 226{
 227        struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
 228        struct rd *rd = data;
 229        uint32_t port, idx;
 230        const char *name;
 231
 232        mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
 233        if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
 234                return MNL_CB_ERROR;
 235
 236        if (!tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
 237                pr_err("This tool doesn't support switches yet\n");
 238                return MNL_CB_ERROR;
 239        }
 240
 241        idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
 242        port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
 243        name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
 244
 245        open_json_object(NULL);
 246        print_color_uint(PRINT_JSON, COLOR_NONE, "ifindex", NULL, idx);
 247        print_color_string(PRINT_ANY, COLOR_NONE, "ifname", "link %s/", name);
 248        print_color_uint(PRINT_ANY, COLOR_NONE, "port", "%u ", port);
 249        link_print_subnet_prefix(rd, tb);
 250        link_print_lid(rd, tb);
 251        link_print_sm_lid(rd, tb);
 252        link_print_lmc(rd, tb);
 253        link_print_state(rd, tb);
 254        link_print_phys_state(rd, tb);
 255        link_print_netdev(rd, tb);
 256        if (rd->show_details)
 257                link_print_caps(rd, tb);
 258
 259        newline(rd);
 260        return MNL_CB_OK;
 261}
 262
 263static int link_no_args(struct rd *rd)
 264{
 265        uint32_t seq;
 266        int ret;
 267
 268        rd_prepare_msg(rd, RDMA_NLDEV_CMD_PORT_GET, &seq,
 269                       (NLM_F_REQUEST | NLM_F_ACK));
 270        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
 271        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
 272        ret = rd_send_msg(rd);
 273        if (ret)
 274                return ret;
 275
 276        ret = rd_recv_msg(rd, link_parse_cb, rd, seq);
 277        return ret;
 278}
 279
 280static int link_one_show(struct rd *rd)
 281{
 282        const struct rd_cmd cmds[] = {
 283                { NULL,         link_no_args},
 284                { 0 }
 285        };
 286
 287        if (!rd->port_idx)
 288                return 0;
 289
 290        return rd_exec_cmd(rd, cmds, "parameter");
 291}
 292
 293static int link_show(struct rd *rd)
 294{
 295        return rd_exec_link(rd, link_one_show, true);
 296}
 297
 298static int link_add_netdev(struct rd *rd)
 299{
 300        char *link_netdev;
 301        uint32_t seq;
 302
 303        if (rd_no_arg(rd)) {
 304                pr_err("Please provide a net device name.\n");
 305                return -EINVAL;
 306        }
 307
 308        link_netdev = rd_argv(rd);
 309        rd_prepare_msg(rd, RDMA_NLDEV_CMD_NEWLINK, &seq,
 310                       (NLM_F_REQUEST | NLM_F_ACK));
 311        mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd->link_name);
 312        mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_LINK_TYPE, rd->link_type);
 313        mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_NDEV_NAME, link_netdev);
 314        return rd_sendrecv_msg(rd, seq);
 315}
 316
 317static int link_add_type(struct rd *rd)
 318{
 319        const struct rd_cmd cmds[] = {
 320                { NULL,         link_help},
 321                { "netdev",     link_add_netdev},
 322                { 0 }
 323        };
 324
 325        if (rd_no_arg(rd)) {
 326                pr_err("Please provide a link type name.\n");
 327                return -EINVAL;
 328        }
 329        rd->link_type = rd_argv(rd);
 330        rd_arg_inc(rd);
 331        return rd_exec_cmd(rd, cmds, "parameter");
 332}
 333
 334static int link_add(struct rd *rd)
 335{
 336        const struct rd_cmd cmds[] = {
 337                { NULL,         link_help},
 338                { "type",       link_add_type},
 339                { 0 }
 340        };
 341
 342        if (rd_no_arg(rd)) {
 343                pr_err("Please provide a link name to add.\n");
 344                return -EINVAL;
 345        }
 346        rd->link_name = rd_argv(rd);
 347        rd_arg_inc(rd);
 348
 349        return rd_exec_cmd(rd, cmds, "parameter");
 350}
 351
 352static int _link_del(struct rd *rd)
 353{
 354        uint32_t seq;
 355
 356        if (!rd_no_arg(rd)) {
 357                pr_err("Unknown parameter %s\n", rd_argv(rd));
 358                return -EINVAL;
 359        }
 360        rd_prepare_msg(rd, RDMA_NLDEV_CMD_DELLINK, &seq,
 361                       (NLM_F_REQUEST | NLM_F_ACK));
 362        mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
 363        return rd_sendrecv_msg(rd, seq);
 364}
 365
 366static int link_del(struct rd *rd)
 367{
 368        return rd_exec_require_dev(rd, _link_del);
 369}
 370
 371int cmd_link(struct rd *rd)
 372{
 373        const struct rd_cmd cmds[] = {
 374                { NULL,         link_show },
 375                { "add",        link_add },
 376                { "delete",     link_del },
 377                { "show",       link_show },
 378                { "list",       link_show },
 379                { "help",       link_help },
 380                { 0 }
 381        };
 382
 383        return rd_exec_cmd(rd, cmds, "link command");
 384}
 385