810b8dbee980c112bdbea658958bfb35d3ca6658
[mirror/winof/.git] / tools / infiniband-diags / src / ibnetdiscover.c
1 /*
2  * Copyright (c) 2004-2008 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  *
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 #define _GNU_SOURCE
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <time.h>
45 #include <string.h>
46 #include <getopt.h>
47 #include <inttypes.h>
48
49 #include <infiniband/umad.h>
50 #include <infiniband/mad.h>
51 #include <complib/cl_nodenamemap.h>
52 #include <infiniband/ibnetdisc.h>
53
54 #include "ibdiag_common.h"
55
56 #define LIST_CA_NODE     (1 << IB_NODE_CA)
57 #define LIST_SWITCH_NODE (1 << IB_NODE_SWITCH)
58 #define LIST_ROUTER_NODE (1 << IB_NODE_ROUTER)
59
60 struct ibmad_port *srcport;
61
62 static int timeout = 2000;              /* ms */
63 static FILE *f;
64
65 static char *node_name_map_file = NULL;
66 static nn_map_t *node_name_map = NULL;
67
68 /**
69  * Define our own conversion functions to maintain compatibility with the old
70  * ibnetdiscover which did not use the ibmad conversion functions.
71  */
72 char *dump_linkspeed_compat(uint32_t speed)
73 {
74         switch (speed) {
75         case 1:
76                 return ("SDR");
77                 break;
78         case 2:
79                 return ("DDR");
80                 break;
81         case 4:
82                 return ("QDR");
83                 break;
84         }
85         return ("???");
86 }
87
88 char *dump_linkwidth_compat(uint32_t width)
89 {
90         switch (width) {
91         case 1:
92                 return ("1x");
93                 break;
94         case 2:
95                 return ("4x");
96                 break;
97         case 4:
98                 return ("8x");
99                 break;
100         case 8:
101                 return ("12x");
102                 break;
103         }
104         return ("??");
105 }
106
107 static inline const char*
108 ports_nt_str_compat(ibnd_node_t *node)
109 {
110         switch(node->type) {
111         case IB_NODE_SWITCH: return "SW";
112         case IB_NODE_CA:     return "CA";
113         case IB_NODE_ROUTER: return "RT";
114         }
115         return "??";
116 }
117
118 char *
119 node_name(ibnd_node_t *node)
120 {
121         static char buf[256];
122
123         switch(node->type) {
124         case IB_NODE_SWITCH:
125                 sprintf(buf, "\"%s", "S");
126                 break;
127         case IB_NODE_CA:
128                 sprintf(buf, "\"%s", "H");
129                 break;
130         case IB_NODE_ROUTER:
131                 sprintf(buf, "\"%s", "R");
132                 break;
133         default:
134                 sprintf(buf, "\"%s", "?");
135                 break;
136         }
137         sprintf(buf+2, "-%016" PRIx64 "\"", node->guid);
138
139         return buf;
140 }
141
142 void
143 list_node(ibnd_node_t *node, void *user_data)
144 {
145         char *node_type;
146         char *nodename = remap_node_name(node_name_map, node->guid,
147                                               node->nodedesc);
148
149         switch(node->type) {
150         case IB_NODE_SWITCH:
151                 node_type = "Switch";
152                 break;
153         case IB_NODE_CA:
154                 node_type = "Ca";
155                 break;
156         case IB_NODE_ROUTER:
157                 node_type = "Router";
158                 break;
159         default:
160                 node_type = "???";
161                 break;
162         }
163         fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n",
164                 node_type,
165                 node->guid, node->numports,
166                 mad_get_field(node->info, 0, IB_NODE_DEVID_F),
167                 mad_get_field(node->info, 0, IB_NODE_VENDORID_F),
168                 nodename);
169
170         free(nodename);
171 }
172
173 void
174 list_nodes(ibnd_fabric_t *fabric, int list)
175 {
176         if (list & LIST_CA_NODE) {
177                 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_CA, NULL);
178         }
179         if (list & LIST_SWITCH_NODE) {
180                 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_SWITCH, NULL);
181         }
182         if (list & LIST_ROUTER_NODE) {
183                 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_ROUTER, NULL);
184         }
185 }
186
187 void
188 out_ids(ibnd_node_t *node, int group, char *chname)
189 {
190         uint64_t sysimgguid = mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
191
192         fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n",
193                 mad_get_field(node->info, 0, IB_NODE_VENDORID_F),
194                 mad_get_field(node->info, 0, IB_NODE_DEVID_F));
195         if (sysimgguid)
196                 fprintf(f, "sysimgguid=0x%" PRIx64, sysimgguid);
197         if (group
198             && node->chassis && node->chassis->chassisnum) {
199                 fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum);
200                 if (chname)
201                         fprintf(f, " (%s)", clean_nodedesc(chname));
202                 if (ibnd_is_xsigo_tca(node->guid)
203                                 && node->ports[1]
204                                 && node->ports[1]->remoteport)
205                         fprintf(f, " slot %d", node->ports[1]->remoteport->portnum);
206         }
207         fprintf(f, "\n");
208 }
209
210 uint64_t
211 out_chassis(ibnd_fabric_t *fabric, unsigned char chassisnum)
212 {
213         uint64_t guid;
214
215         fprintf(f, "\nChassis %u", chassisnum);
216         guid = ibnd_get_chassis_guid(fabric, chassisnum);
217         if (guid)
218                 fprintf(f, " (guid 0x%" PRIx64 ")", guid);
219         fprintf(f, "\n");
220         return guid;
221 }
222
223 void
224 out_switch(ibnd_node_t *node, int group, char *chname)
225 {
226         char *str;
227         char  str2[256];
228         char *nodename = NULL;
229
230         out_ids(node, group, chname);
231         fprintf(f, "switchguid=0x%" PRIx64, node->guid);
232         fprintf(f, "(%" PRIx64 ")", mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F));
233         if (group) {
234                 str = ibnd_get_chassis_type(node);
235                 if (str)
236                         fprintf(f, "%s ", str);
237                 str = ibnd_get_chassis_slot_str(node, str2, 256);
238                 if (str)
239                         fprintf(f, "%s", str);
240         }
241
242         nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
243
244         fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n",
245                 node->numports, node_name(node),
246                 nodename,
247                 node->smaenhsp0 ? "enhanced" : "base",
248                 node->smalid, node->smalmc);
249
250         free(nodename);
251 }
252
253 void
254 out_ca(ibnd_node_t *node, int group, char *chname)
255 {
256         char *node_type;
257         char *node_type2;
258
259         out_ids(node, group, chname);
260         switch(node->type) {
261         case IB_NODE_CA:
262                 node_type = "ca";
263                 node_type2 = "Ca";
264                 break;
265         case IB_NODE_ROUTER:
266                 node_type = "rt";
267                 node_type2 = "Rt";
268                 break;
269         default:
270                 node_type = "???";
271                 node_type2 = "???";
272                 break;
273         }
274
275         fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->guid);
276         fprintf(f, "%s\t%d %s\t\t# \"%s\"",
277                 node_type2, node->numports, node_name(node),
278                 clean_nodedesc(node->nodedesc));
279         if (group && ibnd_is_xsigo_hca(node->guid))
280                 fprintf(f, " (scp)");
281         fprintf(f, "\n");
282 }
283
284 #define OUT_BUFFER_SIZE 16
285 static char *
286 out_ext_port(ibnd_port_t *port, int group)
287 {
288         static char mapping[OUT_BUFFER_SIZE];
289
290         if (group && port->ext_portnum != 0) {
291                 snprintf(mapping, OUT_BUFFER_SIZE,
292                         "[ext %d]", port->ext_portnum);
293                 return (mapping);
294         }
295
296         return (NULL);
297 }
298
299 void
300 out_switch_port(ibnd_port_t *port, int group)
301 {
302         char *ext_port_str = NULL;
303         char *rem_nodename = NULL;
304         uint32_t iwidth = mad_get_field(port->info, 0,
305                                         IB_PORT_LINK_WIDTH_ACTIVE_F);
306         uint32_t ispeed = mad_get_field(port->info, 0,
307                                         IB_PORT_LINK_SPEED_ACTIVE_F);
308
309         DEBUG("port %p:%d remoteport %p\n", port, port->portnum, port->remoteport);
310         fprintf(f, "[%d]", port->portnum);
311
312         ext_port_str = out_ext_port(port, group);
313         if (ext_port_str)
314                 fprintf(f, "%s", ext_port_str);
315
316         rem_nodename = remap_node_name(node_name_map,
317                                 port->remoteport->node->guid,
318                                 port->remoteport->node->nodedesc);
319
320         ext_port_str = out_ext_port(port->remoteport, group);
321         fprintf(f, "\t%s[%d]%s",
322                 node_name(port->remoteport->node),
323                 port->remoteport->portnum,
324                 ext_port_str ? ext_port_str : "");
325         if (port->remoteport->node->type != IB_NODE_SWITCH)
326                 fprintf(f, "(%" PRIx64 ") ", port->remoteport->guid);
327         fprintf(f, "\t\t# \"%s\" lid %d %s%s",
328                 rem_nodename,
329                 port->remoteport->node->type == IB_NODE_SWITCH ?
330                         port->remoteport->node->smalid :
331                         port->remoteport->base_lid,
332                         dump_linkwidth_compat(iwidth),
333                         dump_linkspeed_compat(ispeed));
334
335         if (ibnd_is_xsigo_tca(port->remoteport->guid))
336                 fprintf(f, " slot %d", port->portnum);
337         else if (ibnd_is_xsigo_hca(port->remoteport->guid))
338                 fprintf(f, " (scp)");
339         fprintf(f, "\n");
340
341         free(rem_nodename);
342 }
343
344 void
345 out_ca_port(ibnd_port_t *port, int group)
346 {
347         char *str = NULL;
348         char *rem_nodename = NULL;
349         uint32_t iwidth = mad_get_field(port->info, 0,
350                                         IB_PORT_LINK_WIDTH_ACTIVE_F);
351         uint32_t ispeed = mad_get_field(port->info, 0,
352                                         IB_PORT_LINK_SPEED_ACTIVE_F);
353
354         fprintf(f, "[%d]", port->portnum);
355         if (port->node->type != IB_NODE_SWITCH)
356                 fprintf(f, "(%" PRIx64 ") ", port->guid);
357         fprintf(f, "\t%s[%d]",
358                 node_name(port->remoteport->node),
359                 port->remoteport->portnum);
360         str = out_ext_port(port->remoteport, group);
361         if (str)
362                 fprintf(f, "%s", str);
363         if (port->remoteport->node->type != IB_NODE_SWITCH)
364                 fprintf(f, " (%" PRIx64 ") ", port->remoteport->guid);
365
366         rem_nodename = remap_node_name(node_name_map,
367                                 port->remoteport->node->guid,
368                                 port->remoteport->node->nodedesc);
369
370         fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n",
371                 port->base_lid, port->lmc, rem_nodename,
372                 port->remoteport->node->type == IB_NODE_SWITCH ?
373                         port->remoteport->node->smalid :
374                         port->remoteport->base_lid,
375                 dump_linkwidth_compat(iwidth),
376                 dump_linkspeed_compat(ispeed));
377
378         free(rem_nodename);
379 }
380
381
382 struct iter_user_data {
383         int group;
384         int skip_chassis_nodes;
385 };
386
387 static void
388 switch_iter_func(ibnd_node_t *node, void *iter_user_data)
389 {
390         ibnd_port_t *port;
391         int p = 0;
392         struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
393
394         DEBUG("SWITCH: node %p\n", node);
395
396         /* skip chassis based switches if flagged */
397         if (data->skip_chassis_nodes && node->chassis && node->chassis->chassisnum)
398                 return;
399
400         out_switch(node, data->group, NULL);
401         for (p = 1; p <= node->numports; p++) {
402                 port = node->ports[p];
403                 if (port && port->remoteport)
404                         out_switch_port(port, data->group);
405         }
406 }
407
408 static void
409 ca_iter_func(ibnd_node_t *node, void *iter_user_data)
410 {
411         ibnd_port_t *port;
412         int p = 0;
413         struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
414
415         DEBUG("CA: node %p\n", node);
416         /* Now, skip chassis based CAs */
417         if (data->group && node->chassis && node->chassis->chassisnum)
418                 return;
419         out_ca(node, data->group, NULL);
420
421         for (p = 1; p <= node->numports; p++) {
422                 port = node->ports[p];
423                 if (port && port->remoteport)
424                         out_ca_port(port, data->group);
425         }
426 }
427
428 static void
429 router_iter_func(ibnd_node_t *node, void *iter_user_data)
430 {
431         ibnd_port_t *port;
432         int p = 0;
433         struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
434
435         DEBUG("RT: node %p\n", node);
436         /* Now, skip chassis based RTs */
437         if (data->group && node->chassis &&
438             node->chassis->chassisnum)
439                 return;
440         out_ca(node, data->group, NULL);
441         for (p = 1; p <= node->numports; p++) {
442                 port = node->ports[p];
443                 if (port && port->remoteport)
444                         out_ca_port(port, data->group);
445         }
446 }
447
448 int
449 dump_topology(int group, ibnd_fabric_t *fabric)
450 {
451         ibnd_node_t *node;
452         ibnd_port_t *port;
453         int i = 0, p = 0;
454         time_t t = time(0);
455         uint64_t chguid;
456         char *chname = NULL;
457         struct iter_user_data iter_user_data;
458
459         fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));
460         fprintf(f, "# Max of %d hops discovered\n", fabric->maxhops_discovered);
461         fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n",
462                 fabric->from_node->guid,
463                 mad_get_field64(fabric->from_node->info, 0, IB_NODE_PORT_GUID_F));
464
465         /* Make pass on switches */
466         if (group) {
467                 ibnd_chassis_t *ch = NULL;
468
469                 /* Chassis based switches first */
470                 for (ch = fabric->chassis; ch; ch = ch->next) {
471                         int n = 0;
472
473                         if (!ch->chassisnum)
474                                 continue;
475                         chguid = out_chassis(fabric, ch->chassisnum);
476
477                         chname = NULL;
478 /**
479  * Will this work for Xsigo?
480  */
481                         if (ibnd_is_xsigo_guid(chguid)) {
482                                 for (node = ch->nodes; node;
483                                                 node = node->next_chassis_node) {
484                                         if (ibnd_is_xsigo_hca(node->guid)) {
485                                                 chname = node->nodedesc;
486                                                 fprintf(f, "Hostname: %s\n", clean_nodedesc(node->nodedesc));
487                                         }
488                                 }
489                         }
490
491                         fprintf(f, "\n# Spine Nodes");
492                         for (n = 1; n <= SPINES_MAX_NUM; n++) {
493                                 if (ch->spinenode[n]) {
494                                         out_switch(ch->spinenode[n], group, chname);
495                                         for (p = 1; p <= ch->spinenode[n]->numports; p++) {
496                                                 port = ch->spinenode[n]->ports[p];
497                                                 if (port && port->remoteport)
498                                                         out_switch_port(port, group);
499                                         }
500                                 }
501                         }
502                         fprintf(f, "\n# Line Nodes");
503                         for (n = 1; n <= LINES_MAX_NUM; n++) {
504                                 if (ch->linenode[n]) {
505                                         out_switch(ch->linenode[n], group, chname);
506                                         for (p = 1; p <= ch->linenode[n]->numports; p++) {
507                                                 port = ch->linenode[n]->ports[p];
508                                                 if (port && port->remoteport)
509                                                         out_switch_port(port, group);
510                                         }
511                                 }
512                         }
513
514                         fprintf(f, "\n# Chassis Switches");
515                         for (node = ch->nodes; node;
516                                         node = node->next_chassis_node) {
517                                 if (node->type == IB_NODE_SWITCH) {
518                                         out_switch(node, group, chname);
519                                         for (p = 1; p <= node->numports; p++) {
520                                                 port = node->ports[p];
521                                                 if (port && port->remoteport)
522                                                         out_switch_port(port, group);
523                                         }
524                                 }
525
526                         }
527
528                         fprintf(f, "\n# Chassis CAs");
529                         for (node = ch->nodes; node;
530                                         node = node->next_chassis_node) {
531                                 if (node->type == IB_NODE_CA) {
532                                         out_ca(node, group, chname);
533                                         for (p = 1; p <= node->numports; p++) {
534                                                 port = node->ports[p];
535                                                 if (port && port->remoteport)
536                                                         out_ca_port(port, group);
537                                         }
538                                 }
539                         }
540
541                 }
542
543
544         } else { /* !group */
545                 iter_user_data.group = group;
546                 iter_user_data.skip_chassis_nodes = 0;
547                 ibnd_iter_nodes_type(fabric, switch_iter_func,
548                                 IB_NODE_SWITCH, &iter_user_data);
549         }
550
551         chname = NULL;
552         if (group) {
553                 iter_user_data.group = group;
554                 iter_user_data.skip_chassis_nodes = 1;
555
556                 fprintf(f, "\nNon-Chassis Nodes\n");
557
558                 ibnd_iter_nodes_type(fabric, switch_iter_func,
559                                 IB_NODE_SWITCH, &iter_user_data);
560         }
561
562         iter_user_data.group = group;
563         iter_user_data.skip_chassis_nodes = 0;
564         /* Make pass on CAs */
565         ibnd_iter_nodes_type(fabric, ca_iter_func, IB_NODE_CA,
566                         &iter_user_data);
567
568         /* make pass on routers */
569         ibnd_iter_nodes_type(fabric, router_iter_func, IB_NODE_ROUTER,
570                         &iter_user_data);
571
572         return i;
573 }
574
575 void dump_ports_report (ibnd_node_t *node, void *user_data)
576 {
577         int p = 0;
578         ibnd_port_t *port = NULL;
579
580         /* for each port */
581         for (p = node->numports, port = node->ports[p];
582              p > 0;
583              port = node->ports[--p]) {
584                 uint32_t iwidth, ispeed;
585                 if (port == NULL)
586                         continue;
587                 iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
588                 ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
589                 fprintf(stdout,
590                         "%2s %5d %2d 0x%016" PRIx64 " %s %s",
591                         ports_nt_str_compat(node),
592                         node->type == IB_NODE_SWITCH ?
593                                 node->smalid : port->base_lid,
594                         port->portnum,
595                         port->guid,
596                         dump_linkwidth_compat(iwidth),
597                         dump_linkspeed_compat(ispeed));
598                 if (port->remoteport)
599                         fprintf(stdout,
600                                 " - %2s %5d %2d 0x%016" PRIx64
601                                 " ( '%s' - '%s' )\n",
602                                 ports_nt_str_compat(port->remoteport->node),
603                                 port->remoteport->node->type == IB_NODE_SWITCH ?
604                                         port->remoteport->node->smalid :
605                                         port->remoteport->base_lid,
606                                 port->remoteport->portnum,
607                                 port->remoteport->guid,
608                                 port->node->nodedesc,
609                                 port->remoteport->node->nodedesc);
610                 else
611                         fprintf(stdout, "%36s'%s'\n", "",
612                                 port->node->nodedesc);
613         }
614 }
615
616 static int list, group, ports_report;
617
618 static int process_opt(void *context, int ch, char *optarg)
619 {
620         switch (ch) {
621         case 1:
622                 node_name_map_file = strdup(optarg);
623                 break;
624         case 's':
625                 ibnd_show_progress(1);
626                 break;
627         case 'l':
628                 list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
629                 break;
630         case 'g':
631                 group = 1;
632                 break;
633         case 'S':
634                 list = LIST_SWITCH_NODE;
635                 break;
636         case 'H':
637                 list = LIST_CA_NODE;
638                 break;
639         case 'R':
640                 list = LIST_ROUTER_NODE;
641                 break;
642         case 'p':
643                 ports_report = 1;
644                 break;
645         default:
646                 return -1;
647         }
648
649         return 0;
650 }
651
652 int main(int argc, char **argv)
653 {
654         ibnd_fabric_t *fabric = NULL;
655
656         struct ibmad_port *ibmad_port;
657         int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS};
658
659         const struct ibdiag_opt opts[] = {
660                 { "show", 's', 0, NULL, "show more information" },
661                 { "list", 'l', 0, NULL, "list of connected nodes" },
662                 { "grouping", 'g', 0, NULL, "show grouping" },
663                 { "Hca_list", 'H', 0, NULL, "list of connected CAs" },
664                 { "Switch_list", 'S', 0, NULL, "list of connected switches" },
665                 { "Router_list", 'R', 0, NULL, "list of connected routers" },
666                 { "node-name-map", 1, 1, "<file>", "node name map file" },
667                 { "ports", 'p', 0, NULL, "obtain a ports report" },
668                 { 0 }
669         };
670         char usage_args[] = "[topology-file]";
671
672         ibdiag_process_opts(argc, argv, NULL, "sGDL", opts, process_opt,
673                             usage_args, NULL);
674
675         f = stdout;
676
677         argc -= optind;
678         argv += optind;
679
680         if (ibd_timeout)
681                 timeout = ibd_timeout;
682
683         if (ibverbose)
684                 ibnd_debug(1);
685
686         ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 2);
687         if (!ibmad_port)
688                 IBERROR("Failed to open %s port %d", ibd_ca, ibd_ca_port);
689
690         if (argc && !(f = fopen(argv[0], "w")))
691                 IBERROR("can't open file %s for writing", argv[0]);
692
693         node_name_map = open_node_name_map(node_name_map_file);
694
695         if ((fabric = ibnd_discover_fabric(ibmad_port, ibd_timeout, NULL, -1)) == NULL)
696                 IBERROR("discover failed\n");
697
698         if (ports_report)
699                 ibnd_iter_nodes(fabric,
700                                 dump_ports_report,
701                                 NULL);
702         else if (list)
703                 list_nodes(fabric, list);
704         else
705                 dump_topology(group, fabric);
706
707         ibnd_destroy_fabric(fabric);
708         close_node_name_map(node_name_map);
709         mad_rpc_close_port(ibmad_port);
710         exit(0);
711 }