1 /*
2 * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved.
3 * Copyright (c) 2009-2011 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 2013 Lawrence Livermore National Security. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 *
34 */
35
36 #if HAVE_CONFIG_H
37 # include <config.h>
38 #endif /* HAVE_CONFIG_H */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <inttypes.h>
45 #include <getopt.h>
46 #include <netinet/in.h>
47 #include <assert.h>
48
49 #include <infiniband/umad.h>
50 #include <infiniband/mad.h>
51 #include <complib/cl_nodenamemap.h>
52
53 #include <infiniband/ibnetdisc.h>
54
55 #include "ibdiag_common.h"
56
57 struct ibmad_port *srcport;
58
59 unsigned startlid = 0, endlid = 0;
60
61 static int brief, dump_all, multicast;
62
63 static char *node_name_map_file = NULL;
64 static nn_map_t *node_name_map = NULL;
65
66 #define IB_MLIDS_IN_BLOCK (IB_SMP_DATA_SIZE/2)
67
dump_mlid(char * str,int strlen,unsigned mlid,unsigned nports,uint16_t mft[16][IB_MLIDS_IN_BLOCK])68 int dump_mlid(char *str, int strlen, unsigned mlid, unsigned nports,
69 uint16_t mft[16][IB_MLIDS_IN_BLOCK])
70 {
71 uint16_t mask;
72 unsigned i, chunk, bit, nonzero = 0;
73
74 if (brief) {
75 int n = 0;
76 unsigned chunks = ALIGN(nports + 1, 16) / 16;
77 for (i = 0; i < chunks; i++) {
78 mask = ntohs(mft[i][mlid % IB_MLIDS_IN_BLOCK]);
79 if (mask)
80 nonzero++;
81 n += snprintf(str + n, strlen - n, "%04hx", mask);
82 if (n >= strlen) {
83 n = strlen;
84 break;
85 }
86 }
87 if (!nonzero && !dump_all) {
88 str[0] = 0;
89 return 0;
90 }
91 return n;
92 }
93 for (i = 0; i <= nports; i++) {
94 chunk = i / 16;
95 bit = i % 16;
96
97 mask = ntohs(mft[chunk][mlid % IB_MLIDS_IN_BLOCK]);
98 if (mask)
99 nonzero++;
100 str[i * 2] = (mask & (1 << bit)) ? 'x' : ' ';
101 str[i * 2 + 1] = ' ';
102 }
103 if (!nonzero && !dump_all) {
104 str[0] = 0;
105 return 0;
106 }
107 str[i * 2] = 0;
108 return i * 2;
109 }
110
111 uint16_t mft[16][IB_MLIDS_IN_BLOCK] = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0}, { 0 }, { 0 } };
112
dump_multicast_tables(ibnd_node_t * node,unsigned startlid,unsigned endlid,struct ibmad_port * mad_port)113 void dump_multicast_tables(ibnd_node_t * node, unsigned startlid,
114 unsigned endlid, struct ibmad_port * mad_port)
115 {
116 ib_portid_t *portid = &node->path_portid;
117 char nd[IB_SMP_DATA_SIZE] = { 0 };
118 char str[512];
119 char *s;
120 uint64_t nodeguid;
121 uint32_t mod;
122 unsigned block, i, j, e, nports, cap, chunks, startblock, lastblock,
123 top;
124 char *mapnd = NULL;
125 int n = 0;
126
127 memcpy(nd, node->nodedesc, strlen(node->nodedesc));
128 nports = node->numports;
129 nodeguid = node->guid;
130
131 mad_decode_field(node->switchinfo, IB_SW_MCAST_FDB_CAP_F, &cap);
132 mad_decode_field(node->switchinfo, IB_SW_MCAST_FDB_TOP_F, &top);
133
134 if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1)
135 endlid = IB_MIN_MCAST_LID + cap - 1;
136 if (!dump_all && top && top < endlid) {
137 if (top < IB_MIN_MCAST_LID - 1)
138 IBWARN("illegal top mlid %x", top);
139 else
140 endlid = top;
141 }
142
143 if (!startlid)
144 startlid = IB_MIN_MCAST_LID;
145 else if (startlid < IB_MIN_MCAST_LID) {
146 IBWARN("illegal start mlid %x, set to %x", startlid,
147 IB_MIN_MCAST_LID);
148 startlid = IB_MIN_MCAST_LID;
149 }
150
151 if (endlid > IB_MAX_MCAST_LID) {
152 IBWARN("illegal end mlid %x, truncate to %x", endlid,
153 IB_MAX_MCAST_LID);
154 endlid = IB_MAX_MCAST_LID;
155 }
156
157 mapnd = remap_node_name(node_name_map, nodeguid, nd);
158
159 printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64
160 " (%s):\n", startlid, endlid, portid2str(portid), nodeguid,
161 mapnd);
162
163 if (brief)
164 printf(" MLid Port Mask\n");
165 else {
166 if (nports > 9) {
167 for (i = 0, s = str; i <= nports; i++) {
168 *s++ = (i % 10) ? ' ' : '0' + i / 10;
169 *s++ = ' ';
170 }
171 *s = 0;
172 printf(" %s\n", str);
173 }
174 for (i = 0, s = str; i <= nports; i++)
175 s += sprintf(s, "%d ", i % 10);
176 printf(" Ports: %s\n", str);
177 printf(" MLid\n");
178 }
179 if (ibverbose)
180 printf("Switch multicast mlid capability is %d top is 0x%x\n",
181 cap, top);
182
183 chunks = ALIGN(nports + 1, 16) / 16;
184
185 startblock = startlid / IB_MLIDS_IN_BLOCK;
186 lastblock = endlid / IB_MLIDS_IN_BLOCK;
187 for (block = startblock; block <= lastblock; block++) {
188 for (j = 0; j < chunks; j++) {
189 int status;
190 mod = (block - IB_MIN_MCAST_LID / IB_MLIDS_IN_BLOCK)
191 | (j << 28);
192
193 DEBUG("reading block %x chunk %d mod %x", block, j,
194 mod);
195 if (!smp_query_status_via
196 (mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0,
197 &status, mad_port)) {
198 fprintf(stderr, "SubnGet(MFT) failed on switch "
199 "'%s' %s Node GUID 0x%"PRIx64
200 " SMA LID %d; MAD status 0x%x "
201 "AM 0x%x\n",
202 mapnd, portid2str(portid),
203 node->guid, node->smalid,
204 status, mod);
205 }
206 }
207
208 i = block * IB_MLIDS_IN_BLOCK;
209 e = i + IB_MLIDS_IN_BLOCK;
210 if (i < startlid)
211 i = startlid;
212 if (e > endlid + 1)
213 e = endlid + 1;
214
215 for (; i < e; i++) {
216 if (dump_mlid(str, sizeof str, i, nports, mft) == 0)
217 continue;
218 printf("0x%04x %s\n", i, str);
219 n++;
220 }
221 }
222
223 printf("%d %smlids dumped \n", n, dump_all ? "" : "valid ");
224
225 free(mapnd);
226 }
227
dump_lid(char * str,int str_len,int lid,int valid,ibnd_fabric_t * fabric,int * last_port_lid,int * base_port_lid,uint64_t * portguid)228 int dump_lid(char *str, int str_len, int lid, int valid,
229 ibnd_fabric_t *fabric,
230 int * last_port_lid, int * base_port_lid,
231 uint64_t * portguid)
232 {
233 char nd[IB_SMP_DATA_SIZE] = { 0 };
234
235 ibnd_port_t *port = NULL;
236
237 char ntype[50], sguid[30];
238 uint64_t nodeguid;
239 int baselid, lmc, type;
240 char *mapnd = NULL;
241 int rc;
242
243 if (brief) {
244 str[0] = 0;
245 return 0;
246 }
247
248 if (lid <= *last_port_lid) {
249 if (!valid)
250 return snprintf(str, str_len,
251 ": (path #%d - illegal port)",
252 lid - *base_port_lid);
253 else if (!*portguid)
254 return snprintf(str, str_len,
255 ": (path #%d out of %d)",
256 lid - *base_port_lid + 1,
257 *last_port_lid - *base_port_lid + 1);
258 else {
259 return snprintf(str, str_len,
260 ": (path #%d out of %d: portguid %s)",
261 lid - *base_port_lid + 1,
262 *last_port_lid - *base_port_lid + 1,
263 mad_dump_val(IB_NODE_PORT_GUID_F, sguid,
264 sizeof sguid, portguid));
265 }
266 }
267
268 if (!valid)
269 return snprintf(str, str_len, ": (illegal port)");
270
271 *portguid = 0;
272
273 port = ibnd_find_port_lid(fabric, lid);
274 if (!port) {
275 return snprintf(str, str_len, ": (node info not available fabric scan)");
276 }
277
278 nodeguid = port->node->guid;
279 *portguid = port->guid;
280 type = port->node->type;
281
282 baselid = port->base_lid;
283 lmc = port->lmc;
284
285 memcpy(nd, port->node->nodedesc, strlen(port->node->nodedesc));
286
287 if (lmc > 0) {
288 *base_port_lid = baselid;
289 *last_port_lid = baselid + (1 << lmc) - 1;
290 }
291
292 mapnd = remap_node_name(node_name_map, nodeguid, nd);
293
294 rc = snprintf(str, str_len, ": (%s portguid %s: '%s')",
295 mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype,
296 &type), mad_dump_val(IB_NODE_PORT_GUID_F,
297 sguid, sizeof sguid,
298 portguid),
299 mapnd);
300
301 free(mapnd);
302 return rc;
303 }
304
dump_unicast_tables(ibnd_node_t * node,int startlid,int endlid,struct ibmad_port * mad_port,ibnd_fabric_t * fabric)305 void dump_unicast_tables(ibnd_node_t * node, int startlid, int endlid,
306 struct ibmad_port *mad_port, ibnd_fabric_t *fabric)
307 {
308 ib_portid_t * portid = &node->path_portid;
309 char lft[IB_SMP_DATA_SIZE] = { 0 };
310 char nd[IB_SMP_DATA_SIZE] = { 0 };
311 char str[200];
312 uint64_t nodeguid;
313 int block, i, e, top;
314 unsigned nports;
315 int n = 0, startblock, endblock;
316 char *mapnd = NULL;
317 int last_port_lid = 0, base_port_lid = 0;
318 uint64_t portguid = 0;
319
320 mad_decode_field(node->switchinfo, IB_SW_LINEAR_FDB_TOP_F, &top);
321 nodeguid = node->guid;
322 nports = node->numports;
323 memcpy(nd, node->nodedesc, strlen(node->nodedesc));
324
325 if (!endlid || endlid > top)
326 endlid = top;
327
328 if (endlid > IB_MAX_UCAST_LID) {
329 IBWARN("illegal lft top %d, truncate to %d", endlid,
330 IB_MAX_UCAST_LID);
331 endlid = IB_MAX_UCAST_LID;
332 }
333
334 mapnd = remap_node_name(node_name_map, nodeguid, nd);
335
336 printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64
337 " (%s):\n", startlid, endlid, portid2str(portid), nodeguid,
338 mapnd);
339
340 DEBUG("Switch top is 0x%x\n", top);
341
342 printf(" Lid Out Destination\n");
343 printf(" Port Info \n");
344 startblock = startlid / IB_SMP_DATA_SIZE;
345 endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE;
346 for (block = startblock; block < endblock; block++) {
347 int status;
348 DEBUG("reading block %d", block);
349 if (!smp_query_status_via(lft, portid, IB_ATTR_LINEARFORWTBL, block,
350 0, &status, mad_port)) {
351 fprintf(stderr, "SubnGet(LFT) failed on switch "
352 "'%s' %s Node GUID 0x%"PRIx64
353 " SMA LID %d; MAD status 0x%x AM 0x%x\n",
354 mapnd, portid2str(portid),
355 node->guid, node->smalid,
356 status, block);
357 }
358 i = block * IB_SMP_DATA_SIZE;
359 e = i + IB_SMP_DATA_SIZE;
360 if (i < startlid)
361 i = startlid;
362 if (e > endlid + 1)
363 e = endlid + 1;
364
365 for (; i < e; i++) {
366 unsigned outport = lft[i % IB_SMP_DATA_SIZE];
367 unsigned valid = (outport <= nports);
368
369 if (!valid && !dump_all)
370 continue;
371 dump_lid(str, sizeof str, i, valid, fabric,
372 &last_port_lid, &base_port_lid, &portguid);
373 printf("0x%04x %03u %s\n", i, outport & 0xff, str);
374 n++;
375 }
376 }
377
378 printf("%d %slids dumped \n", n, dump_all ? "" : "valid ");
379 free(mapnd);
380 }
381
dump_node(ibnd_node_t * node,struct ibmad_port * mad_port,ibnd_fabric_t * fabric)382 void dump_node(ibnd_node_t *node, struct ibmad_port *mad_port,
383 ibnd_fabric_t *fabric)
384 {
385 if (multicast)
386 dump_multicast_tables(node, startlid, endlid, mad_port);
387 else
388 dump_unicast_tables(node, startlid, endlid,
389 mad_port, fabric);
390 }
391
process_switch(ibnd_node_t * node,void * fabric)392 void process_switch(ibnd_node_t * node, void *fabric)
393 {
394 dump_node(node, srcport, (ibnd_fabric_t *)fabric);
395 }
396
process_opt(void * context,int ch,char * optarg)397 static int process_opt(void *context, int ch, char *optarg)
398 {
399 switch (ch) {
400 case 'a':
401 dump_all++;
402 break;
403 case 'M':
404 multicast++;
405 break;
406 case 'n':
407 brief++;
408 break;
409 case 1:
410 node_name_map_file = strdup(optarg);
411 break;
412 default:
413 return -1;
414 }
415 return 0;
416 }
417
main(int argc,char ** argv)418 int main(int argc, char **argv)
419 {
420 int rc = 0;
421 int mgmt_classes[3] =
422 { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS };
423
424 struct ibnd_config config = { 0 };
425 ibnd_fabric_t *fabric = NULL;
426
427 const struct ibdiag_opt opts[] = {
428 {"all", 'a', 0, NULL, "show all lids, even invalid entries"},
429 {"no_dests", 'n', 0, NULL,
430 "do not try to resolve destinations"},
431 {"Multicast", 'M', 0, NULL, "show multicast forwarding tables"},
432 {"node-name-map", 1, 1, "<file>", "node name map file"},
433 {0}
434 };
435 char usage_args[] = "[<dest dr_path|lid|guid> [<startlid> [<endlid>]]]";
436 const char *usage_examples[] = {
437 " -- Unicast examples:",
438 "-a\t# same, but dump all lids, even with invalid out ports",
439 "-n\t# simple dump format - no destination resolving",
440 "10\t# dump lids starting from 10",
441 "0x10 0x20\t# dump lid range",
442 " -- Multicast examples:",
443 "-M\t# dump all non empty mlids of switch with lid 4",
444 "-M 0xc010 0xc020\t# same, but with range",
445 "-M -n\t# simple dump format",
446 NULL,
447 };
448
449 ibdiag_process_opts(argc, argv, &config, "KGDLs", opts, process_opt,
450 usage_args, usage_examples);
451
452 argc -= optind;
453 argv += optind;
454
455 if (argc > 0)
456 startlid = strtoul(argv[0], 0, 0);
457 if (argc > 1)
458 endlid = strtoul(argv[1], 0, 0);
459
460 node_name_map = open_node_name_map(node_name_map_file);
461
462 if (ibd_timeout)
463 config.timeout_ms = ibd_timeout;
464
465 config.flags = ibd_ibnetdisc_flags;
466 config.mkey = ibd_mkey;
467
468 if ((fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL,
469 &config)) != NULL) {
470
471 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
472 if (!srcport) {
473 fprintf(stderr,
474 "Failed to open '%s' port '%d'\n", ibd_ca, ibd_ca_port);
475 rc = -1;
476 goto Exit;
477 }
478 smp_mkey_set(srcport, ibd_mkey);
479
480 if (ibd_timeout) {
481 mad_rpc_set_timeout(srcport, ibd_timeout);
482 }
483
484 ibnd_iter_nodes_type(fabric, process_switch, IB_NODE_SWITCH, fabric);
485
486 mad_rpc_close_port(srcport);
487
488 } else {
489 fprintf(stderr, "Failed to discover fabric\n");
490 rc = -1;
491 }
492 Exit:
493 ibnd_destroy_fabric(fabric);
494
495 close_node_name_map(node_name_map);
496 exit(rc);
497 }
498