]> git.proxmox.com Git - mirror_iproute2.git/blob - rdma/link.c
Merge branch 'master' into next
[mirror_iproute2.git] / rdma / link.c
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
9 static 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
18 static 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
89 static 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 if (rd->json_output) {
100 jsonw_name(rd->jw, "caps");
101 jsonw_start_array(rd->jw);
102 } else {
103 pr_out("\n caps: <");
104 }
105 for (idx = 0; caps; idx++) {
106 if (caps & 0x1) {
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 }
114 }
115 caps >>= 0x1;
116 }
117
118 if (rd->json_output)
119 jsonw_end_array(rd->jw);
120 else
121 pr_out(">");
122 }
123
124 static void link_print_subnet_prefix(struct rd *rd, struct nlattr **tb)
125 {
126 uint64_t subnet_prefix;
127 uint16_t vp[4];
128 char str[32];
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]);
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);
140 }
141
142 static void link_print_lid(struct rd *rd, struct nlattr **tb)
143 {
144 uint32_t lid;
145
146 if (!tb[RDMA_NLDEV_ATTR_LID])
147 return;
148
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);
154 }
155
156 static void link_print_sm_lid(struct rd *rd, struct nlattr **tb)
157 {
158 uint32_t sm_lid;
159
160 if (!tb[RDMA_NLDEV_ATTR_SM_LID])
161 return;
162
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);
168 }
169
170 static void link_print_lmc(struct rd *rd, struct nlattr **tb)
171 {
172 uint8_t lmc;
173
174 if (!tb[RDMA_NLDEV_ATTR_LMC])
175 return;
176
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);
182 }
183
184 static 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
195 static void link_print_state(struct rd *rd, struct nlattr **tb)
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]);
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));
207 }
208
209 static 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
223 static void link_print_phys_state(struct rd *rd, struct nlattr **tb)
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]);
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));
236 }
237
238 static 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
258 static int link_parse_cb(const struct nlmsghdr *nlh, void *data)
259 {
260 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
261 struct rd *rd = data;
262 uint32_t port, idx;
263 char name[32];
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
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);
294 link_print_netdev(rd, tb);
295 if (rd->show_details)
296 link_print_caps(rd, tb);
297
298 if (!rd->json_output)
299 pr_out("\n");
300 return MNL_CB_OK;
301 }
302
303 static 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
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;
322 }
323
324 static int link_one_show(struct rd *rd)
325 {
326 const struct rd_cmd cmds[] = {
327 { NULL, link_no_args},
328 { 0 }
329 };
330
331 if (!rd->port_idx)
332 return 0;
333
334 return rd_exec_cmd(rd, cmds, "parameter");
335 }
336
337 static int link_show(struct rd *rd)
338 {
339 return rd_exec_link(rd, link_one_show, true);
340 }
341
342 static 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
361 static 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
378 static 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
396 static 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
410 static int link_del(struct rd *rd)
411 {
412 return rd_exec_require_dev(rd, _link_del);
413 }
414
415 int cmd_link(struct rd *rd)
416 {
417 const struct rd_cmd cmds[] = {
418 { NULL, link_show },
419 { "add", link_add },
420 { "delete", link_del },
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 }