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