]> git.proxmox.com Git - mirror_iproute2.git/blame - rdma/link.c
rdma: Control CQ adaptive moderation (DIM)
[mirror_iproute2.git] / rdma / link.c
CommitLineData
835d8321 1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
da990ab4
LR
2/*
3 * link.c RDMA tool
da990ab4
LR
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);
4336c582
SW
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);
da990ab4
LR
15 return 0;
16}
17
18static const char *caps_to_str(uint32_t idx)
19{
40fc8c2c 20#define RDMA_PORT_FLAGS_LOW(x) \
d090fbf3 21 x(RESERVED, 0) \
da990ab4
LR
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) \
4e2eb9fd 32 x(SYS_IMAGE_GUID, 11) \
da990ab4 33 x(PKEY_SW_EXT_PORT_TRAP, 12) \
d090fbf3 34 x(CABLE_INFO, 13) \
da990ab4 35 x(EXTENDED_SPEEDS, 14) \
d090fbf3 36 x(CAP_MASK2, 15) \
da990ab4
LR
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) \
8f478ec2 46 x(CLIENT_REG, 25) \
d090fbf3
LR
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)
da990ab4 53
40fc8c2c
MG
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)
da990ab4 61
40fc8c2c
MG
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) };
da990ab4 72 static const char * const
40fc8c2c
MG
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];
da990ab4 85
40fc8c2c 86 return "UNKNOWN";
da990ab4
LR
87}
88
7fc75744 89static void link_print_caps(struct rd *rd, struct nlattr **tb)
da990ab4
LR
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
7fc75744
LR
99 if (rd->json_output) {
100 jsonw_name(rd->jw, "caps");
101 jsonw_start_array(rd->jw);
102 } else {
103 pr_out("\n caps: <");
104 }
da990ab4
LR
105 for (idx = 0; caps; idx++) {
106 if (caps & 0x1) {
7fc75744
LR
107 if (rd->json_output) {
108 jsonw_string(rd->jw, caps_to_str(idx));
109 } else {
110 pr_out("%s", caps_to_str(idx));
111 if (caps >> 0x1)
112 pr_out(", ");
113 }
da990ab4
LR
114 }
115 caps >>= 0x1;
116 }
117
7fc75744
LR
118 if (rd->json_output)
119 jsonw_end_array(rd->jw);
120 else
121 pr_out(">");
da990ab4
LR
122}
123
7fc75744 124static void link_print_subnet_prefix(struct rd *rd, struct nlattr **tb)
da990ab4
LR
125{
126 uint64_t subnet_prefix;
7fc75744
LR
127 uint16_t vp[4];
128 char str[32];
da990ab4
LR
129
130 if (!tb[RDMA_NLDEV_ATTR_SUBNET_PREFIX])
131 return;
132
133 subnet_prefix = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_SUBNET_PREFIX]);
7fc75744
LR
134 memcpy(vp, &subnet_prefix, sizeof(uint64_t));
135 snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
136 if (rd->json_output)
137 jsonw_string_field(rd->jw, "subnet_prefix", str);
138 else
139 pr_out("subnet_prefix %s ", str);
da990ab4
LR
140}
141
7fc75744 142static void link_print_lid(struct rd *rd, struct nlattr **tb)
da990ab4 143{
7fc75744
LR
144 uint32_t lid;
145
da990ab4
LR
146 if (!tb[RDMA_NLDEV_ATTR_LID])
147 return;
148
7fc75744
LR
149 lid = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_LID]);
150 if (rd->json_output)
151 jsonw_uint_field(rd->jw, "lid", lid);
152 else
153 pr_out("lid %u ", lid);
da990ab4
LR
154}
155
7fc75744 156static void link_print_sm_lid(struct rd *rd, struct nlattr **tb)
da990ab4 157{
7fc75744
LR
158 uint32_t sm_lid;
159
da990ab4
LR
160 if (!tb[RDMA_NLDEV_ATTR_SM_LID])
161 return;
162
7fc75744
LR
163 sm_lid = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_SM_LID]);
164 if (rd->json_output)
165 jsonw_uint_field(rd->jw, "sm_lid", sm_lid);
166 else
167 pr_out("sm_lid %u ", sm_lid);
da990ab4
LR
168}
169
7fc75744 170static void link_print_lmc(struct rd *rd, struct nlattr **tb)
da990ab4 171{
7fc75744
LR
172 uint8_t lmc;
173
da990ab4
LR
174 if (!tb[RDMA_NLDEV_ATTR_LMC])
175 return;
176
7fc75744
LR
177 lmc = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_LMC]);
178 if (rd->json_output)
179 jsonw_uint_field(rd->jw, "lmc", lmc);
180 else
181 pr_out("lmc %u ", lmc);
da990ab4
LR
182}
183
184static const char *link_state_to_str(uint8_t link_state)
185{
186 static const char * const link_state_str[] = { "NOP", "DOWN",
187 "INIT", "ARMED",
188 "ACTIVE",
189 "ACTIVE_DEFER" };
190 if (link_state < ARRAY_SIZE(link_state_str))
191 return link_state_str[link_state];
192 return "UNKNOWN";
193}
194
7fc75744 195static void link_print_state(struct rd *rd, struct nlattr **tb)
da990ab4
LR
196{
197 uint8_t state;
198
199 if (!tb[RDMA_NLDEV_ATTR_PORT_STATE])
200 return;
201
202 state = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_PORT_STATE]);
7fc75744
LR
203 if (rd->json_output)
204 jsonw_string_field(rd->jw, "state", link_state_to_str(state));
205 else
206 pr_out("state %s ", link_state_to_str(state));
da990ab4
LR
207}
208
209static const char *phys_state_to_str(uint8_t phys_state)
210{
211 static const char * const phys_state_str[] = { "NOP", "SLEEP",
212 "POLLING", "DISABLED",
213 "ARMED", "LINK_UP",
214 "LINK_ERROR_RECOVER",
215 "PHY_TEST", "UNKNOWN",
216 "OPA_OFFLINE",
217 "UNKNOWN", "OPA_TEST" };
218 if (phys_state < ARRAY_SIZE(phys_state_str))
219 return phys_state_str[phys_state];
220 return "UNKNOWN";
221};
222
7fc75744 223static void link_print_phys_state(struct rd *rd, struct nlattr **tb)
da990ab4
LR
224{
225 uint8_t phys_state;
226
227 if (!tb[RDMA_NLDEV_ATTR_PORT_PHYS_STATE])
228 return;
229
230 phys_state = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_PORT_PHYS_STATE]);
7fc75744
LR
231 if (rd->json_output)
232 jsonw_string_field(rd->jw, "physical_state",
233 phys_state_to_str(phys_state));
234 else
235 pr_out("physical_state %s ", phys_state_to_str(phys_state));
da990ab4
LR
236}
237
15259427
LR
238static void link_print_netdev(struct rd *rd, struct nlattr **tb)
239{
240 const char *netdev_name;
241 uint32_t idx;
242
243 if (!tb[RDMA_NLDEV_ATTR_NDEV_NAME] || !tb[RDMA_NLDEV_ATTR_NDEV_INDEX])
244 return;
245
246 netdev_name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_NDEV_NAME]);
247 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_NDEV_INDEX]);
248 if (rd->json_output) {
249 jsonw_string_field(rd->jw, "netdev", netdev_name);
250 jsonw_uint_field(rd->jw, "netdev_index", idx);
251 } else {
252 pr_out("netdev %s ", netdev_name);
253 if (rd->show_details)
254 pr_out("netdev_index %u ", idx);
255 }
256}
257
da990ab4
LR
258static int link_parse_cb(const struct nlmsghdr *nlh, void *data)
259{
260 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
261 struct rd *rd = data;
7fc75744
LR
262 uint32_t port, idx;
263 char name[32];
da990ab4
LR
264
265 mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
266 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
267 return MNL_CB_ERROR;
268
269 if (!tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
270 pr_err("This tool doesn't support switches yet\n");
271 return MNL_CB_ERROR;
272 }
273
7fc75744
LR
274 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
275 port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
276 snprintf(name, 32, "%s/%u",
277 mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]), port);
278
279 if (rd->json_output) {
280 jsonw_uint_field(rd->jw, "ifindex", idx);
281 jsonw_uint_field(rd->jw, "port", port);
282 jsonw_string_field(rd->jw, "ifname", name);
283
284 } else {
285 pr_out("%u/%u: %s: ", idx, port, name);
286 }
287
288 link_print_subnet_prefix(rd, tb);
289 link_print_lid(rd, tb);
290 link_print_sm_lid(rd, tb);
291 link_print_lmc(rd, tb);
292 link_print_state(rd, tb);
293 link_print_phys_state(rd, tb);
15259427 294 link_print_netdev(rd, tb);
da990ab4 295 if (rd->show_details)
7fc75744 296 link_print_caps(rd, tb);
da990ab4 297
7fc75744
LR
298 if (!rd->json_output)
299 pr_out("\n");
da990ab4
LR
300 return MNL_CB_OK;
301}
302
303static int link_no_args(struct rd *rd)
304{
305 uint32_t seq;
306 int ret;
307
308 rd_prepare_msg(rd, RDMA_NLDEV_CMD_PORT_GET, &seq,
309 (NLM_F_REQUEST | NLM_F_ACK));
310 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
311 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
312 ret = rd_send_msg(rd);
313 if (ret)
314 return ret;
315
7fc75744
LR
316 if (rd->json_output)
317 jsonw_start_object(rd->jw);
318 ret = rd_recv_msg(rd, link_parse_cb, rd, seq);
319 if (rd->json_output)
320 jsonw_end_object(rd->jw);
321 return ret;
da990ab4
LR
322}
323
324static int link_one_show(struct rd *rd)
325{
326 const struct rd_cmd cmds[] = {
327 { NULL, link_no_args},
328 { 0 }
329 };
330
e3dee3c8
LR
331 if (!rd->port_idx)
332 return 0;
333
da990ab4
LR
334 return rd_exec_cmd(rd, cmds, "parameter");
335}
336
337static int link_show(struct rd *rd)
338{
6416d1a0 339 return rd_exec_link(rd, link_one_show, true);
da990ab4
LR
340}
341
4336c582
SW
342static int link_add_netdev(struct rd *rd)
343{
344 char *link_netdev;
345 uint32_t seq;
346
347 if (rd_no_arg(rd)) {
348 pr_err("Please provide a net device name.\n");
349 return -EINVAL;
350 }
351
352 link_netdev = rd_argv(rd);
353 rd_prepare_msg(rd, RDMA_NLDEV_CMD_NEWLINK, &seq,
354 (NLM_F_REQUEST | NLM_F_ACK));
355 mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd->link_name);
356 mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_LINK_TYPE, rd->link_type);
357 mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_NDEV_NAME, link_netdev);
358 return rd_sendrecv_msg(rd, seq);
359}
360
361static int link_add_type(struct rd *rd)
362{
363 const struct rd_cmd cmds[] = {
364 { NULL, link_help},
365 { "netdev", link_add_netdev},
366 { 0 }
367 };
368
369 if (rd_no_arg(rd)) {
370 pr_err("Please provide a link type name.\n");
371 return -EINVAL;
372 }
373 rd->link_type = rd_argv(rd);
374 rd_arg_inc(rd);
375 return rd_exec_cmd(rd, cmds, "parameter");
376}
377
378static int link_add(struct rd *rd)
379{
380 const struct rd_cmd cmds[] = {
381 { NULL, link_help},
382 { "type", link_add_type},
383 { 0 }
384 };
385
386 if (rd_no_arg(rd)) {
387 pr_err("Please provide a link name to add.\n");
388 return -EINVAL;
389 }
390 rd->link_name = rd_argv(rd);
391 rd_arg_inc(rd);
392
393 return rd_exec_cmd(rd, cmds, "parameter");
394}
395
396static int _link_del(struct rd *rd)
397{
398 uint32_t seq;
399
400 if (!rd_no_arg(rd)) {
401 pr_err("Unknown parameter %s\n", rd_argv(rd));
402 return -EINVAL;
403 }
404 rd_prepare_msg(rd, RDMA_NLDEV_CMD_DELLINK, &seq,
405 (NLM_F_REQUEST | NLM_F_ACK));
406 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
407 return rd_sendrecv_msg(rd, seq);
408}
409
410static int link_del(struct rd *rd)
411{
412 return rd_exec_require_dev(rd, _link_del);
413}
414
da990ab4
LR
415int cmd_link(struct rd *rd)
416{
417 const struct rd_cmd cmds[] = {
418 { NULL, link_show },
4336c582
SW
419 { "add", link_add },
420 { "delete", link_del },
da990ab4
LR
421 { "show", link_show },
422 { "list", link_show },
423 { "help", link_help },
424 { 0 }
425 };
426
427 return rd_exec_cmd(rd, cmds, "link command");
428}