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