]>
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 | ||
208 | static int link_parse_cb(const struct nlmsghdr *nlh, void *data) | |
209 | { | |
210 | struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {}; | |
211 | struct rd *rd = data; | |
7fc75744 LR |
212 | uint32_t port, idx; |
213 | char name[32]; | |
da990ab4 LR |
214 | |
215 | mnl_attr_parse(nlh, 0, rd_attr_cb, tb); | |
216 | if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME]) | |
217 | return MNL_CB_ERROR; | |
218 | ||
219 | if (!tb[RDMA_NLDEV_ATTR_PORT_INDEX]) { | |
220 | pr_err("This tool doesn't support switches yet\n"); | |
221 | return MNL_CB_ERROR; | |
222 | } | |
223 | ||
7fc75744 LR |
224 | idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); |
225 | port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); | |
226 | snprintf(name, 32, "%s/%u", | |
227 | mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]), port); | |
228 | ||
229 | if (rd->json_output) { | |
230 | jsonw_uint_field(rd->jw, "ifindex", idx); | |
231 | jsonw_uint_field(rd->jw, "port", port); | |
232 | jsonw_string_field(rd->jw, "ifname", name); | |
233 | ||
234 | } else { | |
235 | pr_out("%u/%u: %s: ", idx, port, name); | |
236 | } | |
237 | ||
238 | link_print_subnet_prefix(rd, tb); | |
239 | link_print_lid(rd, tb); | |
240 | link_print_sm_lid(rd, tb); | |
241 | link_print_lmc(rd, tb); | |
242 | link_print_state(rd, tb); | |
243 | link_print_phys_state(rd, tb); | |
da990ab4 | 244 | if (rd->show_details) |
7fc75744 | 245 | link_print_caps(rd, tb); |
da990ab4 | 246 | |
7fc75744 LR |
247 | if (!rd->json_output) |
248 | pr_out("\n"); | |
da990ab4 LR |
249 | return MNL_CB_OK; |
250 | } | |
251 | ||
252 | static int link_no_args(struct rd *rd) | |
253 | { | |
254 | uint32_t seq; | |
255 | int ret; | |
256 | ||
257 | rd_prepare_msg(rd, RDMA_NLDEV_CMD_PORT_GET, &seq, | |
258 | (NLM_F_REQUEST | NLM_F_ACK)); | |
259 | mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); | |
260 | mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx); | |
261 | ret = rd_send_msg(rd); | |
262 | if (ret) | |
263 | return ret; | |
264 | ||
7fc75744 LR |
265 | if (rd->json_output) |
266 | jsonw_start_object(rd->jw); | |
267 | ret = rd_recv_msg(rd, link_parse_cb, rd, seq); | |
268 | if (rd->json_output) | |
269 | jsonw_end_object(rd->jw); | |
270 | return ret; | |
da990ab4 LR |
271 | } |
272 | ||
273 | static int link_one_show(struct rd *rd) | |
274 | { | |
275 | const struct rd_cmd cmds[] = { | |
276 | { NULL, link_no_args}, | |
277 | { 0 } | |
278 | }; | |
279 | ||
e3dee3c8 LR |
280 | if (!rd->port_idx) |
281 | return 0; | |
282 | ||
da990ab4 LR |
283 | return rd_exec_cmd(rd, cmds, "parameter"); |
284 | } | |
285 | ||
286 | static int link_show(struct rd *rd) | |
287 | { | |
874c734c | 288 | return rd_exec_link(rd, link_one_show); |
da990ab4 LR |
289 | } |
290 | ||
291 | int cmd_link(struct rd *rd) | |
292 | { | |
293 | const struct rd_cmd cmds[] = { | |
294 | { NULL, link_show }, | |
295 | { "show", link_show }, | |
296 | { "list", link_show }, | |
297 | { "help", link_help }, | |
298 | { 0 } | |
299 | }; | |
300 | ||
301 | return rd_exec_cmd(rd, cmds, "link command"); | |
302 | } |