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