1 /*
2 * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved.
3 * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved.
4 * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved.
5 * Copyright (c) 2010,2011 Mellanox Technologies LTD. All rights reserved.
6 *
7 * This software is available to you under a choice of one of two
8 * licenses. You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
15 * conditions are met:
16 *
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer.
20 *
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials
24 * provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 *
35 */
36
37 #if HAVE_CONFIG_H
38 #include <config.h>
39 #endif /* HAVE_CONFIG_H */
40
41 #define _GNU_SOURCE
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <time.h>
46 #include <string.h>
47 #include <getopt.h>
48 #include <inttypes.h>
49
50 #include <infiniband/umad.h>
51 #include <infiniband/mad.h>
52 #include <complib/cl_nodenamemap.h>
53 #include <infiniband/ibnetdisc.h>
54
55 #include "ibdiag_common.h"
56
57 #define LIST_CA_NODE (1 << IB_NODE_CA)
58 #define LIST_SWITCH_NODE (1 << IB_NODE_SWITCH)
59 #define LIST_ROUTER_NODE (1 << IB_NODE_ROUTER)
60
61 #define DIFF_FLAG_SWITCH 0x01
62 #define DIFF_FLAG_CA 0x02
63 #define DIFF_FLAG_ROUTER 0x04
64 #define DIFF_FLAG_PORT_CONNECTION 0x08
65 #define DIFF_FLAG_LID 0x10
66 #define DIFF_FLAG_NODE_DESCRIPTION 0x20
67
68 #define DIFF_FLAG_DEFAULT (DIFF_FLAG_SWITCH | DIFF_FLAG_CA | DIFF_FLAG_ROUTER \
69 | DIFF_FLAG_PORT_CONNECTION)
70
71 static FILE *f;
72
73 static char *node_name_map_file = NULL;
74 static nn_map_t *node_name_map = NULL;
75 static char *cache_file = NULL;
76 static char *load_cache_file = NULL;
77 static char *diff_cache_file = NULL;
78 static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT;
79
80 static int report_max_hops = 0;
81 static int full_info;
82
83 /**
84 * Define our own conversion functions to maintain compatibility with the old
85 * ibnetdiscover which did not use the ibmad conversion functions.
86 */
dump_linkspeed_compat(uint32_t speed)87 char *dump_linkspeed_compat(uint32_t speed)
88 {
89 switch (speed) {
90 case 1:
91 return ("SDR");
92 break;
93 case 2:
94 return ("DDR");
95 break;
96 case 4:
97 return ("QDR");
98 break;
99 }
100 return ("???");
101 }
102
dump_linkspeedext_compat(uint32_t espeed,uint32_t speed,uint32_t fdr10)103 char *dump_linkspeedext_compat(uint32_t espeed, uint32_t speed, uint32_t fdr10)
104 {
105 switch (espeed) {
106 case 0:
107 if (fdr10 & FDR10)
108 return ("FDR10");
109 else
110 return dump_linkspeed_compat(speed);
111 break;
112 case 1:
113 return ("FDR");
114 break;
115 case 2:
116 return ("EDR");
117 break;
118 }
119 return ("???");
120 }
121
dump_linkwidth_compat(uint32_t width)122 char *dump_linkwidth_compat(uint32_t width)
123 {
124 switch (width) {
125 case 1:
126 return ("1x");
127 break;
128 case 2:
129 return ("4x");
130 break;
131 case 4:
132 return ("8x");
133 break;
134 case 8:
135 return ("12x");
136 break;
137 case 16:
138 return ("2x");
139 break;
140 }
141 return ("??");
142 }
143
ports_nt_str_compat(ibnd_node_t * node)144 static inline const char *ports_nt_str_compat(ibnd_node_t * node)
145 {
146 switch (node->type) {
147 case IB_NODE_SWITCH:
148 return "SW";
149 case IB_NODE_CA:
150 return "CA";
151 case IB_NODE_ROUTER:
152 return "RT";
153 }
154 return "??";
155 }
156
node_name(ibnd_node_t * node)157 char *node_name(ibnd_node_t * node)
158 {
159 static char buf[256];
160
161 switch (node->type) {
162 case IB_NODE_SWITCH:
163 sprintf(buf, "\"%s", "S");
164 break;
165 case IB_NODE_CA:
166 sprintf(buf, "\"%s", "H");
167 break;
168 case IB_NODE_ROUTER:
169 sprintf(buf, "\"%s", "R");
170 break;
171 default:
172 sprintf(buf, "\"%s", "?");
173 break;
174 }
175 sprintf(buf + 2, "-%016" PRIx64 "\"", node->guid);
176
177 return buf;
178 }
179
list_node(ibnd_node_t * node,void * user_data)180 void list_node(ibnd_node_t * node, void *user_data)
181 {
182 char *node_type;
183 char *nodename = remap_node_name(node_name_map, node->guid,
184 node->nodedesc);
185
186 switch (node->type) {
187 case IB_NODE_SWITCH:
188 node_type = "Switch";
189 break;
190 case IB_NODE_CA:
191 node_type = "Ca";
192 break;
193 case IB_NODE_ROUTER:
194 node_type = "Router";
195 break;
196 default:
197 node_type = "???";
198 break;
199 }
200 fprintf(f,
201 "%s\t : 0x%016" PRIx64
202 " ports %d devid 0x%x vendid 0x%x \"%s\"\n", node_type,
203 node->guid, node->numports, mad_get_field(node->info, 0,
204 IB_NODE_DEVID_F),
205 mad_get_field(node->info, 0, IB_NODE_VENDORID_F), nodename);
206
207 free(nodename);
208 }
209
list_nodes(ibnd_fabric_t * fabric,int list)210 void list_nodes(ibnd_fabric_t * fabric, int list)
211 {
212 if (list & LIST_CA_NODE)
213 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_CA, NULL);
214 if (list & LIST_SWITCH_NODE)
215 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_SWITCH, NULL);
216 if (list & LIST_ROUTER_NODE)
217 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_ROUTER, NULL);
218 }
219
out_ids(ibnd_node_t * node,int group,char * chname,char * out_prefix)220 void out_ids(ibnd_node_t * node, int group, char *chname, char *out_prefix)
221 {
222 uint64_t sysimgguid =
223 mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
224
225 fprintf(f, "\n%svendid=0x%x\n", out_prefix ? out_prefix : "",
226 mad_get_field(node->info, 0, IB_NODE_VENDORID_F));
227 fprintf(f, "%sdevid=0x%x\n", out_prefix ? out_prefix : "",
228 mad_get_field(node->info, 0, IB_NODE_DEVID_F));
229 if (sysimgguid)
230 fprintf(f, "%ssysimgguid=0x%" PRIx64,
231 out_prefix ? out_prefix : "", sysimgguid);
232 if (group && node->chassis && node->chassis->chassisnum) {
233 fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum);
234 if (chname)
235 fprintf(f, " (%s)", clean_nodedesc(chname));
236 if (ibnd_is_xsigo_tca(node->guid) && node->ports[1] &&
237 node->ports[1]->remoteport)
238 fprintf(f, " slot %d",
239 node->ports[1]->remoteport->portnum);
240 }
241 if (sysimgguid ||
242 (group && node->chassis && node->chassis->chassisnum))
243 fprintf(f, "\n");
244 }
245
out_chassis(ibnd_fabric_t * fabric,unsigned char chassisnum)246 uint64_t out_chassis(ibnd_fabric_t * fabric, unsigned char chassisnum)
247 {
248 uint64_t guid;
249
250 fprintf(f, "\nChassis %u", chassisnum);
251 guid = ibnd_get_chassis_guid(fabric, chassisnum);
252 if (guid)
253 fprintf(f, " (guid 0x%" PRIx64 ")", guid);
254 fprintf(f, "\n");
255 return guid;
256 }
257
out_switch_detail(ibnd_node_t * node,char * sw_prefix)258 void out_switch_detail(ibnd_node_t * node, char *sw_prefix)
259 {
260 char *nodename = NULL;
261
262 nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
263
264 fprintf(f, "%sSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d",
265 sw_prefix ? sw_prefix : "", node->numports, node_name(node),
266 nodename, node->smaenhsp0 ? "enhanced" : "base",
267 node->smalid, node->smalmc);
268
269 free(nodename);
270 }
271
out_switch(ibnd_node_t * node,int group,char * chname,char * id_prefix,char * sw_prefix)272 void out_switch(ibnd_node_t * node, int group, char *chname, char *id_prefix,
273 char *sw_prefix)
274 {
275 char *str;
276 char str2[256];
277
278 out_ids(node, group, chname, id_prefix);
279 fprintf(f, "%sswitchguid=0x%" PRIx64,
280 id_prefix ? id_prefix : "", node->guid);
281 fprintf(f, "(%" PRIx64 ")",
282 mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F));
283 if (group) {
284 fprintf(f, "\t# ");
285 str = ibnd_get_chassis_type(node);
286 if (str)
287 fprintf(f, "%s ", str);
288 str = ibnd_get_chassis_slot_str(node, str2, 256);
289 if (str)
290 fprintf(f, "%s", str);
291 }
292 fprintf(f, "\n");
293
294 out_switch_detail(node, sw_prefix);
295 fprintf(f, "\n");
296 }
297
out_ca_detail(ibnd_node_t * node,char * ca_prefix)298 void out_ca_detail(ibnd_node_t * node, char *ca_prefix)
299 {
300 char *node_type;
301
302 switch (node->type) {
303 case IB_NODE_CA:
304 node_type = "Ca";
305 break;
306 case IB_NODE_ROUTER:
307 node_type = "Rt";
308 break;
309 default:
310 node_type = "???";
311 break;
312 }
313
314 fprintf(f, "%s%s\t%d %s\t\t# \"%s\"", ca_prefix ? ca_prefix : "",
315 node_type, node->numports, node_name(node),
316 clean_nodedesc(node->nodedesc));
317 }
318
out_ca(ibnd_node_t * node,int group,char * chname,char * id_prefix,char * ca_prefix)319 void out_ca(ibnd_node_t * node, int group, char *chname, char *id_prefix,
320 char *ca_prefix)
321 {
322 char *node_type;
323
324 out_ids(node, group, chname, id_prefix);
325 switch (node->type) {
326 case IB_NODE_CA:
327 node_type = "ca";
328 break;
329 case IB_NODE_ROUTER:
330 node_type = "rt";
331 break;
332 default:
333 node_type = "???";
334 break;
335 }
336
337 fprintf(f, "%s%sguid=0x%" PRIx64 "\n",
338 id_prefix ? id_prefix : "", node_type, node->guid);
339 out_ca_detail(node, ca_prefix);
340 if (group && ibnd_is_xsigo_hca(node->guid))
341 fprintf(f, " (scp)");
342 fprintf(f, "\n");
343 }
344
345 #define OUT_BUFFER_SIZE 16
out_ext_port(ibnd_port_t * port,int group)346 static char *out_ext_port(ibnd_port_t * port, int group)
347 {
348 static char mapping[OUT_BUFFER_SIZE];
349
350 if (group && port->ext_portnum != 0) {
351 snprintf(mapping, OUT_BUFFER_SIZE,
352 "[ext %d]", port->ext_portnum);
353 return (mapping);
354 }
355
356 return (NULL);
357 }
358
out_switch_port(ibnd_port_t * port,int group,char * out_prefix)359 void out_switch_port(ibnd_port_t * port, int group, char *out_prefix)
360 {
361 char *ext_port_str = NULL;
362 char *rem_nodename = NULL;
363 uint32_t iwidth = mad_get_field(port->info, 0,
364 IB_PORT_LINK_WIDTH_ACTIVE_F);
365 uint32_t ispeed = mad_get_field(port->info, 0,
366 IB_PORT_LINK_SPEED_ACTIVE_F);
367 uint32_t vlcap = mad_get_field(port->info, 0,
368 IB_PORT_VL_CAP_F);
369 uint32_t fdr10 = mad_get_field(port->ext_info, 0,
370 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F);
371 uint32_t cap_mask, espeed;
372
373 DEBUG("port %p:%d remoteport %p\n", port, port->portnum,
374 port->remoteport);
375 fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum);
376
377 ext_port_str = out_ext_port(port, group);
378 if (ext_port_str)
379 fprintf(f, "%s", ext_port_str);
380
381 rem_nodename = remap_node_name(node_name_map,
382 port->remoteport->node->guid,
383 port->remoteport->node->nodedesc);
384
385 ext_port_str = out_ext_port(port->remoteport, group);
386
387 if (!port->node->ports[0]) {
388 cap_mask = 0;
389 ispeed = 0;
390 espeed = 0;
391 } else {
392 cap_mask = mad_get_field(port->node->ports[0]->info, 0,
393 IB_PORT_CAPMASK_F);
394 if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS))
395 espeed = mad_get_field(port->info, 0,
396 IB_PORT_LINK_SPEED_EXT_ACTIVE_F);
397 else
398 espeed = 0;
399 }
400 fprintf(f, "\t%s[%d]%s",
401 node_name(port->remoteport->node), port->remoteport->portnum,
402 ext_port_str ? ext_port_str : "");
403 if (port->remoteport->node->type != IB_NODE_SWITCH)
404 fprintf(f, "(%" PRIx64 ") ", port->remoteport->guid);
405 fprintf(f, "\t\t# \"%s\" lid %d %s%s",
406 rem_nodename,
407 port->remoteport->node->type == IB_NODE_SWITCH ?
408 port->remoteport->node->smalid :
409 port->remoteport->base_lid,
410 dump_linkwidth_compat(iwidth),
411 (ispeed != 4 && !espeed) ?
412 dump_linkspeed_compat(ispeed) :
413 dump_linkspeedext_compat(espeed, ispeed, fdr10));
414
415 if (full_info) {
416 fprintf(f, " s=%d w=%d v=%d", ispeed, iwidth, vlcap);
417 if (espeed)
418 fprintf(f, " e=%d", espeed);
419 }
420
421 if (ibnd_is_xsigo_tca(port->remoteport->guid))
422 fprintf(f, " slot %d", port->portnum);
423 else if (ibnd_is_xsigo_hca(port->remoteport->guid))
424 fprintf(f, " (scp)");
425 fprintf(f, "\n");
426
427 free(rem_nodename);
428 }
429
out_ca_port(ibnd_port_t * port,int group,char * out_prefix)430 void out_ca_port(ibnd_port_t * port, int group, char *out_prefix)
431 {
432 char *str = NULL;
433 char *rem_nodename = NULL;
434 uint32_t iwidth = mad_get_field(port->info, 0,
435 IB_PORT_LINK_WIDTH_ACTIVE_F);
436 uint32_t ispeed = mad_get_field(port->info, 0,
437 IB_PORT_LINK_SPEED_ACTIVE_F);
438 uint32_t vlcap = mad_get_field(port->info, 0,
439 IB_PORT_VL_CAP_F);
440 uint32_t fdr10 = mad_get_field(port->ext_info, 0,
441 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F);
442 uint32_t cap_mask, espeed;
443
444 fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum);
445 if (port->node->type != IB_NODE_SWITCH)
446 fprintf(f, "(%" PRIx64 ") ", port->guid);
447 fprintf(f, "\t%s[%d]",
448 node_name(port->remoteport->node), port->remoteport->portnum);
449 str = out_ext_port(port->remoteport, group);
450 if (str)
451 fprintf(f, "%s", str);
452 if (port->remoteport->node->type != IB_NODE_SWITCH)
453 fprintf(f, " (%" PRIx64 ") ", port->remoteport->guid);
454
455 rem_nodename = remap_node_name(node_name_map,
456 port->remoteport->node->guid,
457 port->remoteport->node->nodedesc);
458
459 cap_mask = mad_get_field(port->info, 0, IB_PORT_CAPMASK_F);
460 if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS))
461 espeed = mad_get_field(port->info, 0,
462 IB_PORT_LINK_SPEED_EXT_ACTIVE_F);
463 else
464 espeed = 0;
465
466 fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s",
467 port->base_lid, port->lmc, rem_nodename,
468 port->remoteport->node->type == IB_NODE_SWITCH ?
469 port->remoteport->node->smalid :
470 port->remoteport->base_lid,
471 dump_linkwidth_compat(iwidth),
472 (ispeed != 4 && !espeed) ?
473 dump_linkspeed_compat(ispeed) :
474 dump_linkspeedext_compat(espeed, ispeed, fdr10));
475
476 if (full_info) {
477 fprintf(f, " s=%d w=%d v=%d", ispeed, iwidth, vlcap);
478 if (espeed)
479 fprintf(f, " e=%d", espeed);
480 }
481
482 fprintf(f, "\n");
483
484 free(rem_nodename);
485 }
486
487 struct iter_user_data {
488 int group;
489 int skip_chassis_nodes;
490 };
491
switch_iter_func(ibnd_node_t * node,void * iter_user_data)492 static void switch_iter_func(ibnd_node_t * node, void *iter_user_data)
493 {
494 ibnd_port_t *port;
495 int p = 0;
496 struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
497
498 DEBUG("SWITCH: node %p\n", node);
499
500 /* skip chassis based switches if flagged */
501 if (data->skip_chassis_nodes && node->chassis
502 && node->chassis->chassisnum)
503 return;
504
505 out_switch(node, data->group, NULL, NULL, NULL);
506 for (p = 1; p <= node->numports; p++) {
507 port = node->ports[p];
508 if (port && port->remoteport)
509 out_switch_port(port, data->group, NULL);
510 }
511 }
512
ca_iter_func(ibnd_node_t * node,void * iter_user_data)513 static void ca_iter_func(ibnd_node_t * node, void *iter_user_data)
514 {
515 ibnd_port_t *port;
516 int p = 0;
517 struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
518
519 DEBUG("CA: node %p\n", node);
520 /* Now, skip chassis based CAs */
521 if (data->group && node->chassis && node->chassis->chassisnum)
522 return;
523 out_ca(node, data->group, NULL, NULL, NULL);
524
525 for (p = 1; p <= node->numports; p++) {
526 port = node->ports[p];
527 if (port && port->remoteport)
528 out_ca_port(port, data->group, NULL);
529 }
530 }
531
router_iter_func(ibnd_node_t * node,void * iter_user_data)532 static void router_iter_func(ibnd_node_t * node, void *iter_user_data)
533 {
534 ibnd_port_t *port;
535 int p = 0;
536 struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
537
538 DEBUG("RT: node %p\n", node);
539 /* Now, skip chassis based RTs */
540 if (data->group && node->chassis && node->chassis->chassisnum)
541 return;
542 out_ca(node, data->group, NULL, NULL, NULL);
543 for (p = 1; p <= node->numports; p++) {
544 port = node->ports[p];
545 if (port && port->remoteport)
546 out_ca_port(port, data->group, NULL);
547 }
548 }
549
dump_topology(int group,ibnd_fabric_t * fabric)550 int dump_topology(int group, ibnd_fabric_t * fabric)
551 {
552 ibnd_node_t *node;
553 ibnd_port_t *port;
554 int i = 0, p = 0;
555 time_t t = time(0);
556 uint64_t chguid;
557 char *chname = NULL;
558 struct iter_user_data iter_user_data;
559
560 fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));
561 if (report_max_hops)
562 fprintf(f, "# Reported max hops discovered: %u\n"
563 "# Total MADs used: %u\n",
564 fabric->maxhops_discovered, fabric->total_mads_used);
565 fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n",
566 fabric->from_node->guid,
567 mad_get_field64(fabric->from_node->info, 0,
568 IB_NODE_PORT_GUID_F));
569
570 /* Make pass on switches */
571 if (group) {
572 ibnd_chassis_t *ch = NULL;
573
574 /* Chassis based switches first */
575 for (ch = fabric->chassis; ch; ch = ch->next) {
576 int n = 0;
577
578 if (!ch->chassisnum)
579 continue;
580 chguid = out_chassis(fabric, ch->chassisnum);
581 chname = NULL;
582 if (ibnd_is_xsigo_guid(chguid)) {
583 for (node = ch->nodes; node;
584 node = node->next_chassis_node) {
585 if (ibnd_is_xsigo_hca(node->guid)) {
586 chname = node->nodedesc;
587 fprintf(f, "Hostname: %s\n",
588 clean_nodedesc
589 (node->nodedesc));
590 }
591 }
592 }
593
594 fprintf(f, "\n# Spine Nodes");
595 for (n = 1; n <= SPINES_MAX_NUM; n++) {
596 if (ch->spinenode[n]) {
597 out_switch(ch->spinenode[n], group,
598 chname, NULL, NULL);
599 for (p = 1;
600 p <= ch->spinenode[n]->numports;
601 p++) {
602 port =
603 ch->spinenode[n]->ports[p];
604 if (port && port->remoteport)
605 out_switch_port(port,
606 group,
607 NULL);
608 }
609 }
610 }
611 fprintf(f, "\n# Line Nodes");
612 for (n = 1; n <= LINES_MAX_NUM; n++) {
613 if (ch->linenode[n]) {
614 out_switch(ch->linenode[n], group,
615 chname, NULL, NULL);
616 for (p = 1;
617 p <= ch->linenode[n]->numports;
618 p++) {
619 port =
620 ch->linenode[n]->ports[p];
621 if (port && port->remoteport)
622 out_switch_port(port,
623 group,
624 NULL);
625 }
626 }
627 }
628
629 fprintf(f, "\n# Chassis Switches");
630 for (node = ch->nodes; node;
631 node = node->next_chassis_node) {
632 if (node->type == IB_NODE_SWITCH) {
633 out_switch(node, group, chname, NULL,
634 NULL);
635 for (p = 1; p <= node->numports; p++) {
636 port = node->ports[p];
637 if (port && port->remoteport)
638 out_switch_port(port,
639 group,
640 NULL);
641 }
642 }
643
644 }
645
646 fprintf(f, "\n# Chassis CAs");
647 for (node = ch->nodes; node;
648 node = node->next_chassis_node) {
649 if (node->type == IB_NODE_CA) {
650 out_ca(node, group, chname, NULL, NULL);
651 for (p = 1; p <= node->numports; p++) {
652 port = node->ports[p];
653 if (port && port->remoteport)
654 out_ca_port(port, group,
655 NULL);
656 }
657 }
658 }
659
660 }
661
662 } else { /* !group */
663 iter_user_data.group = group;
664 iter_user_data.skip_chassis_nodes = 0;
665 ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH,
666 &iter_user_data);
667 }
668
669 chname = NULL;
670 if (group) {
671 iter_user_data.group = group;
672 iter_user_data.skip_chassis_nodes = 1;
673
674 fprintf(f, "\nNon-Chassis Nodes\n");
675
676 ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH,
677 &iter_user_data);
678 }
679
680 iter_user_data.group = group;
681 iter_user_data.skip_chassis_nodes = 0;
682 /* Make pass on CAs */
683 ibnd_iter_nodes_type(fabric, ca_iter_func, IB_NODE_CA, &iter_user_data);
684
685 /* Make pass on routers */
686 ibnd_iter_nodes_type(fabric, router_iter_func, IB_NODE_ROUTER,
687 &iter_user_data);
688
689 return i;
690 }
691
dump_ports_report(ibnd_node_t * node,void * user_data)692 void dump_ports_report(ibnd_node_t * node, void *user_data)
693 {
694 int p = 0;
695 ibnd_port_t *port = NULL;
696 char *nodename = NULL;
697 char *rem_nodename = NULL;
698
699 /* for each port */
700 for (p = node->numports, port = node->ports[p]; p > 0;
701 port = node->ports[--p]) {
702 uint32_t iwidth, ispeed, fdr10, espeed, cap_mask;
703 uint8_t *info = NULL;
704 if (port == NULL)
705 continue;
706 iwidth =
707 mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
708 ispeed =
709 mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
710 if (port->node->type == IB_NODE_SWITCH) {
711 if (port->node->ports[0])
712 info = (uint8_t *)&port->node->ports[0]->info;
713 }
714 else
715 info = (uint8_t *)&port->info;
716 if (info) {
717 cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
718 if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS))
719 espeed = mad_get_field(port->info, 0,
720 IB_PORT_LINK_SPEED_EXT_ACTIVE_F);
721 else
722 espeed = 0;
723 } else {
724 ispeed = 0;
725 iwidth = 0;
726 espeed = 0;
727 }
728 fdr10 = mad_get_field(port->ext_info, 0,
729 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F);
730 nodename = remap_node_name(node_name_map,
731 port->node->guid,
732 port->node->nodedesc);
733 fprintf(stdout, "%2s %5d %2d 0x%016" PRIx64 " %s %s",
734 ports_nt_str_compat(node),
735 node->type ==
736 IB_NODE_SWITCH ? node->smalid : port->base_lid,
737 port->portnum, port->guid,
738 dump_linkwidth_compat(iwidth),
739 (ispeed != 4 && !espeed) ?
740 dump_linkspeed_compat(ispeed) :
741 dump_linkspeedext_compat(espeed, ispeed, fdr10));
742 if (port->remoteport) {
743 rem_nodename = remap_node_name(node_name_map,
744 port->remoteport->node->guid,
745 port->remoteport->node->nodedesc);
746 fprintf(stdout,
747 " - %2s %5d %2d 0x%016" PRIx64
748 " ( '%s' - '%s' )\n",
749 ports_nt_str_compat(port->remoteport->node),
750 port->remoteport->node->type == IB_NODE_SWITCH ?
751 port->remoteport->node->smalid :
752 port->remoteport->base_lid,
753 port->remoteport->portnum,
754 port->remoteport->guid, nodename, rem_nodename);
755 free(rem_nodename);
756 } else
757 fprintf(stdout, "%36s'%s'\n", "", nodename);
758
759 free(nodename);
760 }
761 }
762
763 struct iter_diff_data {
764 uint32_t diff_flags;
765 ibnd_fabric_t *fabric1;
766 ibnd_fabric_t *fabric2;
767 char *fabric1_prefix;
768 char *fabric2_prefix;
769 void (*out_header) (ibnd_node_t *, int, char *, char *, char *);
770 void (*out_header_detail) (ibnd_node_t *, char *);
771 void (*out_port) (ibnd_port_t *, int, char *);
772 };
773
diff_iter_out_header(ibnd_node_t * node,struct iter_diff_data * data,int * out_header_flag)774 static void diff_iter_out_header(ibnd_node_t * node,
775 struct iter_diff_data *data,
776 int *out_header_flag)
777 {
778 if (!(*out_header_flag)) {
779 (*data->out_header) (node, 0, NULL, NULL, NULL);
780 (*out_header_flag)++;
781 }
782 }
783
diff_ports(ibnd_node_t * fabric1_node,ibnd_node_t * fabric2_node,int * out_header_flag,struct iter_diff_data * data)784 static void diff_ports(ibnd_node_t * fabric1_node, ibnd_node_t * fabric2_node,
785 int *out_header_flag, struct iter_diff_data *data)
786 {
787 ibnd_port_t *fabric1_port;
788 ibnd_port_t *fabric2_port;
789 int p;
790
791 for (p = 1; p <= fabric1_node->numports; p++) {
792 int fabric1_out = 0, fabric2_out = 0;
793
794 fabric1_port = fabric1_node->ports[p];
795 fabric2_port = fabric2_node->ports[p];
796
797 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION) {
798 if ((fabric1_port && !fabric2_port)
799 || ((fabric1_port && fabric2_port)
800 && (fabric1_port->remoteport
801 && !fabric2_port->remoteport)))
802 fabric1_out++;
803 else if ((!fabric1_port && fabric2_port)
804 || ((fabric1_port && fabric2_port)
805 && (!fabric1_port->remoteport
806 && fabric2_port->remoteport)))
807 fabric2_out++;
808 else if ((fabric1_port && fabric2_port)
809 && ((fabric1_port->guid != fabric2_port->guid)
810 ||
811 ((fabric1_port->remoteport
812 && fabric2_port->remoteport)
813 && (fabric1_port->remoteport->guid !=
814 fabric2_port->remoteport->guid)))) {
815 fabric1_out++;
816 fabric2_out++;
817 }
818 }
819
820 if ((data->diff_flags & DIFF_FLAG_LID)
821 && fabric1_port && fabric2_port
822 && fabric1_port->base_lid != fabric2_port->base_lid) {
823 fabric1_out++;
824 fabric2_out++;
825 }
826
827 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
828 && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
829 && fabric1_port && fabric2_port
830 && fabric1_port->remoteport && fabric2_port->remoteport
831 && memcmp(fabric1_port->remoteport->node->nodedesc,
832 fabric2_port->remoteport->node->nodedesc,
833 IB_SMP_DATA_SIZE)) {
834 fabric1_out++;
835 fabric2_out++;
836 }
837
838 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
839 && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
840 && fabric1_port && fabric2_port
841 && fabric1_port->remoteport && fabric2_port->remoteport
842 && memcmp(fabric1_port->remoteport->node->nodedesc,
843 fabric2_port->remoteport->node->nodedesc,
844 IB_SMP_DATA_SIZE)) {
845 fabric1_out++;
846 fabric2_out++;
847 }
848
849 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
850 && data->diff_flags & DIFF_FLAG_LID
851 && fabric1_port && fabric2_port
852 && fabric1_port->remoteport && fabric2_port->remoteport
853 && fabric1_port->remoteport->base_lid != fabric2_port->remoteport->base_lid) {
854 fabric1_out++;
855 fabric2_out++;
856 }
857
858 if (fabric1_out) {
859 diff_iter_out_header(fabric1_node, data,
860 out_header_flag);
861 (*data->out_port) (fabric1_port, 0,
862 data->fabric1_prefix);
863 }
864 if (fabric2_out) {
865 diff_iter_out_header(fabric1_node, data,
866 out_header_flag);
867 (*data->out_port) (fabric2_port, 0,
868 data->fabric2_prefix);
869 }
870 }
871 }
872
diff_iter_func(ibnd_node_t * fabric1_node,void * iter_user_data)873 static void diff_iter_func(ibnd_node_t * fabric1_node, void *iter_user_data)
874 {
875 struct iter_diff_data *data = iter_user_data;
876 ibnd_node_t *fabric2_node;
877 ibnd_port_t *fabric1_port;
878 int p;
879
880 DEBUG("DEBUG: fabric1_node %p\n", fabric1_node);
881
882 fabric2_node = ibnd_find_node_guid(data->fabric2, fabric1_node->guid);
883 if (!fabric2_node) {
884 (*data->out_header) (fabric1_node, 0, NULL,
885 data->fabric1_prefix,
886 data->fabric1_prefix);
887 for (p = 1; p <= fabric1_node->numports; p++) {
888 fabric1_port = fabric1_node->ports[p];
889 if (fabric1_port && fabric1_port->remoteport)
890 (*data->out_port) (fabric1_port, 0,
891 data->fabric1_prefix);
892 }
893 } else if (data->diff_flags &
894 (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_LID
895 | DIFF_FLAG_NODE_DESCRIPTION)) {
896 int out_header_flag = 0;
897
898 if ((data->diff_flags & DIFF_FLAG_LID
899 && fabric1_node->smalid != fabric2_node->smalid) ||
900 (data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
901 && memcmp(fabric1_node->nodedesc, fabric2_node->nodedesc,
902 IB_SMP_DATA_SIZE))) {
903 (*data->out_header) (fabric1_node, 0, NULL, NULL,
904 data->fabric1_prefix);
905 (*data->out_header_detail) (fabric2_node,
906 data->fabric2_prefix);
907 fprintf(f, "\n");
908 out_header_flag++;
909 }
910
911 if (fabric1_node->numports != fabric2_node->numports) {
912 diff_iter_out_header(fabric1_node, data,
913 &out_header_flag);
914 fprintf(f, "%snumports = %d\n", data->fabric1_prefix,
915 fabric1_node->numports);
916 fprintf(f, "%snumports = %d\n", data->fabric2_prefix,
917 fabric2_node->numports);
918 return;
919 }
920
921 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
922 || data->diff_flags & DIFF_FLAG_LID)
923 diff_ports(fabric1_node, fabric2_node, &out_header_flag,
924 data);
925 }
926 }
927
diff_common(ibnd_fabric_t * orig_fabric,ibnd_fabric_t * new_fabric,int node_type,uint32_t diff_flags,void (* out_header)(ibnd_node_t *,int,char *,char *,char *),void (* out_header_detail)(ibnd_node_t *,char *),void (* out_port)(ibnd_port_t *,int,char *))928 static int diff_common(ibnd_fabric_t * orig_fabric, ibnd_fabric_t * new_fabric,
929 int node_type, uint32_t diff_flags,
930 void (*out_header) (ibnd_node_t *, int, char *, char *,
931 char *),
932 void (*out_header_detail) (ibnd_node_t *, char *),
933 void (*out_port) (ibnd_port_t *, int, char *))
934 {
935 struct iter_diff_data iter_diff_data;
936
937 iter_diff_data.diff_flags = diff_flags;
938 iter_diff_data.fabric1 = orig_fabric;
939 iter_diff_data.fabric2 = new_fabric;
940 iter_diff_data.fabric1_prefix = "< ";
941 iter_diff_data.fabric2_prefix = "> ";
942 iter_diff_data.out_header = out_header;
943 iter_diff_data.out_header_detail = out_header_detail;
944 iter_diff_data.out_port = out_port;
945 ibnd_iter_nodes_type(orig_fabric, diff_iter_func, node_type,
946 &iter_diff_data);
947
948 /* Do opposite diff to find existence of node types
949 * in new_fabric but not in orig_fabric.
950 *
951 * In this diff, we don't need to check port connections,
952 * lids, or node descriptions since it has already been
953 * done (i.e. checks are only done when guid exists on both
954 * orig and new).
955 */
956 iter_diff_data.diff_flags = diff_flags & ~DIFF_FLAG_PORT_CONNECTION;
957 iter_diff_data.diff_flags &= ~DIFF_FLAG_LID;
958 iter_diff_data.diff_flags &= ~DIFF_FLAG_NODE_DESCRIPTION;
959 iter_diff_data.fabric1 = new_fabric;
960 iter_diff_data.fabric2 = orig_fabric;
961 iter_diff_data.fabric1_prefix = "> ";
962 iter_diff_data.fabric2_prefix = "< ";
963 iter_diff_data.out_header = out_header;
964 iter_diff_data.out_header_detail = out_header_detail;
965 iter_diff_data.out_port = out_port;
966 ibnd_iter_nodes_type(new_fabric, diff_iter_func, node_type,
967 &iter_diff_data);
968
969 return 0;
970 }
971
diff(ibnd_fabric_t * orig_fabric,ibnd_fabric_t * new_fabric)972 int diff(ibnd_fabric_t * orig_fabric, ibnd_fabric_t * new_fabric)
973 {
974 if (diffcheck_flags & DIFF_FLAG_SWITCH)
975 diff_common(orig_fabric, new_fabric, IB_NODE_SWITCH,
976 diffcheck_flags, out_switch, out_switch_detail,
977 out_switch_port);
978
979 if (diffcheck_flags & DIFF_FLAG_CA)
980 diff_common(orig_fabric, new_fabric, IB_NODE_CA,
981 diffcheck_flags, out_ca, out_ca_detail,
982 out_ca_port);
983
984 if (diffcheck_flags & DIFF_FLAG_ROUTER)
985 diff_common(orig_fabric, new_fabric, IB_NODE_ROUTER,
986 diffcheck_flags, out_ca, out_ca_detail,
987 out_ca_port);
988
989 return 0;
990 }
991
992 static int list, group, ports_report;
993
process_opt(void * context,int ch,char * optarg)994 static int process_opt(void *context, int ch, char *optarg)
995 {
996 struct ibnd_config *cfg = context;
997 char *p;
998
999 switch (ch) {
1000 case 1:
1001 node_name_map_file = strdup(optarg);
1002 break;
1003 case 2:
1004 cache_file = strdup(optarg);
1005 break;
1006 case 3:
1007 load_cache_file = strdup(optarg);
1008 break;
1009 case 4:
1010 diff_cache_file = strdup(optarg);
1011 break;
1012 case 5:
1013 diffcheck_flags = 0;
1014 p = strtok(optarg, ",");
1015 while (p) {
1016 if (!strcasecmp(p, "sw"))
1017 diffcheck_flags |= DIFF_FLAG_SWITCH;
1018 else if (!strcasecmp(p, "ca"))
1019 diffcheck_flags |= DIFF_FLAG_CA;
1020 else if (!strcasecmp(p, "router"))
1021 diffcheck_flags |= DIFF_FLAG_ROUTER;
1022 else if (!strcasecmp(p, "port"))
1023 diffcheck_flags |= DIFF_FLAG_PORT_CONNECTION;
1024 else if (!strcasecmp(p, "lid"))
1025 diffcheck_flags |= DIFF_FLAG_LID;
1026 else if (!strcasecmp(p, "nodedesc"))
1027 diffcheck_flags |= DIFF_FLAG_NODE_DESCRIPTION;
1028 else {
1029 fprintf(stderr, "invalid diff check key: %s\n",
1030 p);
1031 return -1;
1032 }
1033 p = strtok(NULL, ",");
1034 }
1035 break;
1036 case 's':
1037 cfg->show_progress = 1;
1038 break;
1039 case 'f':
1040 full_info = 1;
1041 break;
1042 case 'l':
1043 list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
1044 break;
1045 case 'g':
1046 group = 1;
1047 break;
1048 case 'S':
1049 list = LIST_SWITCH_NODE;
1050 break;
1051 case 'H':
1052 list = LIST_CA_NODE;
1053 break;
1054 case 'R':
1055 list = LIST_ROUTER_NODE;
1056 break;
1057 case 'p':
1058 ports_report = 1;
1059 break;
1060 case 'm':
1061 report_max_hops = 1;
1062 break;
1063 case 'o':
1064 cfg->max_smps = strtoul(optarg, NULL, 0);
1065 break;
1066 default:
1067 return -1;
1068 }
1069
1070 return 0;
1071 }
1072
main(int argc,char ** argv)1073 int main(int argc, char **argv)
1074 {
1075 struct ibnd_config config = { 0 };
1076 ibnd_fabric_t *fabric = NULL;
1077 ibnd_fabric_t *diff_fabric = NULL;
1078
1079 const struct ibdiag_opt opts[] = {
1080 {"full", 'f', 0, NULL, "show full information (ports' speed and width, vlcap)"},
1081 {"show", 's', 0, NULL, "show more information"},
1082 {"list", 'l', 0, NULL, "list of connected nodes"},
1083 {"grouping", 'g', 0, NULL, "show grouping"},
1084 {"Hca_list", 'H', 0, NULL, "list of connected CAs"},
1085 {"Switch_list", 'S', 0, NULL, "list of connected switches"},
1086 {"Router_list", 'R', 0, NULL, "list of connected routers"},
1087 {"node-name-map", 1, 1, "<file>", "node name map file"},
1088 {"cache", 2, 1, "<file>",
1089 "filename to cache ibnetdiscover data to"},
1090 {"load-cache", 3, 1, "<file>",
1091 "filename of ibnetdiscover cache to load"},
1092 {"diff", 4, 1, "<file>",
1093 "filename of ibnetdiscover cache to diff"},
1094 {"diffcheck", 5, 1, "<key(s)>",
1095 "specify checks to execute for --diff"},
1096 {"ports", 'p', 0, NULL, "obtain a ports report"},
1097 {"max_hops", 'm', 0, NULL,
1098 "report max hops discovered by the library"},
1099 {"outstanding_smps", 'o', 1, NULL,
1100 "specify the number of outstanding SMP's which should be "
1101 "issued during the scan"},
1102 {0}
1103 };
1104 char usage_args[] = "[topology-file]";
1105
1106 ibdiag_process_opts(argc, argv, &config, "DGKLs", opts, process_opt,
1107 usage_args, NULL);
1108
1109 f = stdout;
1110
1111 argc -= optind;
1112 argv += optind;
1113
1114 if (ibd_timeout)
1115 config.timeout_ms = ibd_timeout;
1116
1117 config.flags = ibd_ibnetdisc_flags;
1118
1119 if (argc && !(f = fopen(argv[0], "w")))
1120 IBEXIT("can't open file %s for writing", argv[0]);
1121
1122 config.mkey = ibd_mkey;
1123
1124 node_name_map = open_node_name_map(node_name_map_file);
1125
1126 if (diff_cache_file &&
1127 !(diff_fabric = ibnd_load_fabric(diff_cache_file, 0)))
1128 IBEXIT("loading cached fabric for diff failed\n");
1129
1130 if (load_cache_file) {
1131 if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL)
1132 IBEXIT("loading cached fabric failed\n");
1133 } else {
1134 if ((fabric =
1135 ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config)) == NULL)
1136 IBEXIT("discover failed\n");
1137 }
1138
1139 if (ports_report)
1140 ibnd_iter_nodes(fabric, dump_ports_report, NULL);
1141 else if (list)
1142 list_nodes(fabric, list);
1143 else if (diff_fabric)
1144 diff(diff_fabric, fabric);
1145 else
1146 dump_topology(group, fabric);
1147
1148 if (cache_file)
1149 if (ibnd_cache_fabric(fabric, cache_file, 0) < 0)
1150 IBEXIT("caching ibnetdiscover data failed\n");
1151
1152 ibnd_destroy_fabric(fabric);
1153 if (diff_fabric)
1154 ibnd_destroy_fabric(diff_fabric);
1155 close_node_name_map(node_name_map);
1156 exit(0);
1157 }
1158