iproute2/rdma/res-srq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2/*
   3 * res-srq.c    RDMA tool
   4 * Authors:     Neta Ostrovsky <netao@nvidia.com>
   5 */
   6
   7#include "res.h"
   8#include <inttypes.h>
   9
  10#define MAX_QP_STR_LEN 256
  11
  12static const char *srq_types_to_str(uint8_t idx)
  13{
  14        static const char *const srq_types_str[] = { "BASIC",
  15                                                     "XRC",
  16                                                     "TM" };
  17
  18        if (idx < ARRAY_SIZE(srq_types_str))
  19                return srq_types_str[idx];
  20        return "UNKNOWN";
  21}
  22
  23static void print_type(struct rd *rd, uint32_t val)
  24{
  25        print_color_string(PRINT_ANY, COLOR_NONE, "type", "type %s ",
  26                           srq_types_to_str(val));
  27}
  28
  29static void print_qps(const char *str)
  30{
  31        if (!strlen(str))
  32                return;
  33        print_color_string(PRINT_ANY, COLOR_NONE, "lqpn", "lqpn %s ", str);
  34}
  35
  36static int filter_srq_range_qps(struct rd *rd, struct nlattr **qp_line,
  37                                uint32_t min_range, uint32_t max_range,
  38                                char **delimiter, char *qp_str)
  39{
  40        uint32_t qpn = 0, tmp_min_range = 0, tmp_max_range = 0;
  41        char tmp[16] = {};
  42
  43        for (qpn = min_range; qpn <= max_range; qpn++) {
  44                if (rd_is_filtered_attr(rd, "lqpn", qpn,
  45                                qp_line[RDMA_NLDEV_ATTR_MIN_RANGE])) {
  46                        /* The QPs range contains a LQPN that is filtered */
  47                        if (!tmp_min_range)
  48                                /* There are no QPs previous to
  49                                 * the filtered one
  50                                 */
  51                                continue;
  52                        if (!tmp_max_range)
  53                                snprintf(tmp, sizeof(tmp), "%s%d", *delimiter,
  54                                         tmp_min_range);
  55                        else
  56                                snprintf(tmp, sizeof(tmp), "%s%d-%d",
  57                                         *delimiter, tmp_min_range,
  58                                         tmp_max_range);
  59
  60                        if (strlen(qp_str) + strlen(tmp) >= MAX_QP_STR_LEN)
  61                                return -EINVAL;
  62                        strncat(qp_str, tmp, sizeof(tmp) - 1);
  63
  64                        memset(tmp, 0, strlen(tmp));
  65                        *delimiter = ",";
  66                        tmp_min_range = 0;
  67                        tmp_max_range = 0;
  68                        continue;
  69                }
  70                if (!tmp_min_range)
  71                        tmp_min_range = qpn;
  72                else
  73                        tmp_max_range = qpn;
  74        }
  75
  76        if (!tmp_min_range)
  77                return 0;
  78        if (!tmp_max_range)
  79                snprintf(tmp, sizeof(tmp), "%s%d", *delimiter, tmp_min_range);
  80        else
  81                snprintf(tmp, sizeof(tmp), "%s%d-%d", *delimiter,
  82                         tmp_min_range, tmp_max_range);
  83
  84        if (strlen(qp_str) + strlen(tmp) >= MAX_QP_STR_LEN)
  85                return -EINVAL;
  86        strncat(qp_str, tmp, sizeof(tmp) - 1);
  87        *delimiter = ",";
  88        return 0;
  89}
  90
  91static int get_srq_qps(struct rd *rd, struct nlattr *qp_table,  char *qp_str)
  92{
  93        uint32_t qpn = 0, min_range = 0, max_range = 0;
  94        struct nlattr *nla_entry;
  95        struct filter_entry *fe;
  96        char *delimiter = "";
  97        char tmp[16] = {};
  98
  99        if (!qp_table)
 100                return MNL_CB_ERROR;
 101
 102        /* If there are no QPs associated with the SRQ, return */
 103        if (!(mnl_attr_get_payload_len(qp_table))) {
 104                list_for_each_entry(fe, &rd->filter_list, list) {
 105                        if (!strcmpx(fe->key, "lqpn"))
 106                                /* We found the key -
 107                                 * user requested to filter by LQPN
 108                                 */
 109                                return -EINVAL;
 110                }
 111                return MNL_CB_OK;
 112        }
 113
 114        mnl_attr_for_each_nested(nla_entry, qp_table) {
 115                struct nlattr *qp_line[RDMA_NLDEV_ATTR_MAX] = {};
 116
 117                if (mnl_attr_parse_nested(nla_entry, rd_attr_cb, qp_line) !=
 118                    MNL_CB_OK)
 119                        goto out;
 120
 121                if (qp_line[RDMA_NLDEV_ATTR_RES_LQPN]) {
 122                        qpn = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_RES_LQPN]);
 123                        if (rd_is_filtered_attr(rd, "lqpn", qpn,
 124                                        qp_line[RDMA_NLDEV_ATTR_RES_LQPN]))
 125                                continue;
 126                        snprintf(tmp, sizeof(tmp), "%s%d", delimiter, qpn);
 127                        if (strlen(qp_str) + strlen(tmp) >= MAX_QP_STR_LEN)
 128                                goto out;
 129                        strncat(qp_str, tmp, sizeof(tmp) - 1);
 130                        delimiter = ",";
 131                } else if (qp_line[RDMA_NLDEV_ATTR_MIN_RANGE] &&
 132                           qp_line[RDMA_NLDEV_ATTR_MAX_RANGE]) {
 133                        min_range = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_MIN_RANGE]);
 134                        max_range = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_MAX_RANGE]);
 135
 136                        if (filter_srq_range_qps(rd, qp_line, min_range,
 137                                                 max_range, &delimiter,
 138                                                 qp_str))
 139                                goto out;
 140                } else {
 141                        goto out;
 142                }
 143        }
 144
 145        if (!strlen(qp_str))
 146                /* Check if there are no QPs to display after filter */
 147                goto out;
 148
 149        return MNL_CB_OK;
 150
 151out:
 152        memset(qp_str, 0, strlen(qp_str));
 153        return -EINVAL;
 154}
 155
 156static int res_srq_line(struct rd *rd, const char *name, int idx,
 157                        struct nlattr **nla_line)
 158{
 159        uint32_t srqn = 0, pid = 0, pdn = 0, cqn = 0;
 160        char qp_str[MAX_QP_STR_LEN] = {};
 161        char *comm = NULL;
 162        uint8_t type = 0;
 163
 164        if (!nla_line[RDMA_NLDEV_ATTR_RES_SRQN])
 165                return MNL_CB_ERROR;
 166
 167        if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
 168                pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
 169                comm = get_task_name(pid);
 170        }
 171        if (rd_is_filtered_attr(rd, "pid", pid,
 172                                nla_line[RDMA_NLDEV_ATTR_RES_PID]))
 173                goto out;
 174
 175        if (nla_line[RDMA_NLDEV_ATTR_RES_SRQN])
 176                srqn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_SRQN]);
 177        if (rd_is_filtered_attr(rd, "srqn", srqn,
 178                                nla_line[RDMA_NLDEV_ATTR_RES_SRQN]))
 179                goto out;
 180
 181        if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
 182                type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
 183        if (rd_is_string_filtered_attr(rd, "type", srq_types_to_str(type),
 184                                       nla_line[RDMA_NLDEV_ATTR_RES_TYPE]))
 185                goto out;
 186
 187        if (nla_line[RDMA_NLDEV_ATTR_RES_PDN])
 188                pdn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
 189        if (rd_is_filtered_attr(rd, "pdn", pdn,
 190                                nla_line[RDMA_NLDEV_ATTR_RES_PDN]))
 191                goto out;
 192
 193        if (nla_line[RDMA_NLDEV_ATTR_RES_CQN])
 194                cqn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQN]);
 195        if (rd_is_filtered_attr(rd, "cqn", cqn,
 196                                nla_line[RDMA_NLDEV_ATTR_RES_CQN]))
 197                goto out;
 198
 199        if (get_srq_qps(rd, nla_line[RDMA_NLDEV_ATTR_RES_QP], qp_str) !=
 200                        MNL_CB_OK)
 201                goto out;
 202
 203        if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
 204                /* discard const from mnl_attr_get_str */
 205                comm = (char *)mnl_attr_get_str(
 206                        nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
 207
 208        open_json_object(NULL);
 209        print_dev(rd, idx, name);
 210        res_print_uint(rd, "srqn", srqn, nla_line[RDMA_NLDEV_ATTR_RES_SRQN]);
 211        print_type(rd, type);
 212        print_qps(qp_str);
 213        res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
 214        res_print_uint(rd, "cqn", cqn, nla_line[RDMA_NLDEV_ATTR_RES_CQN]);
 215        res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
 216        print_comm(rd, comm, nla_line);
 217
 218        print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
 219        newline(rd);
 220
 221out:
 222        if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
 223                free(comm);
 224        return MNL_CB_OK;
 225}
 226
 227int res_srq_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
 228{
 229        struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
 230        struct rd *rd = data;
 231        const char *name;
 232        uint32_t idx;
 233
 234        mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
 235        if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
 236                return MNL_CB_ERROR;
 237
 238        name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
 239        idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
 240
 241        return res_srq_line(rd, name, idx, tb);
 242}
 243
 244int res_srq_parse_cb(const struct nlmsghdr *nlh, void *data)
 245{
 246        struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
 247        struct nlattr *nla_table, *nla_entry;
 248        struct rd *rd = data;
 249        int ret = MNL_CB_OK;
 250        const char *name;
 251        uint32_t idx;
 252
 253        mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
 254        if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
 255            !tb[RDMA_NLDEV_ATTR_RES_SRQ])
 256                return MNL_CB_ERROR;
 257
 258        name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
 259        idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
 260        nla_table = tb[RDMA_NLDEV_ATTR_RES_SRQ];
 261
 262        mnl_attr_for_each_nested(nla_entry, nla_table) {
 263                struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
 264
 265                ret = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
 266                if (ret != MNL_CB_OK)
 267                        break;
 268
 269                ret = res_srq_line(rd, name, idx, nla_line);
 270                if (ret != MNL_CB_OK)
 271                        break;
 272        }
 273        return ret;
 274}
 275