]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ofed / management / 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  *
5  * This software is available to you under a choice of one of two
6  * licenses.  You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * OpenIB.org BSD license below:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      - Redistributions of source code must retain the above
16  *        copyright notice, this list of conditions and the following
17  *        disclaimer.
18  *
19  *      - Redistributions in binary form must reproduce the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer in the documentation and/or other materials
22  *        provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  *
33  */
34
35 #if HAVE_CONFIG_H
36 #  include <config.h>
37 #endif /* HAVE_CONFIG_H */
38
39 #define _GNU_SOURCE
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <stdarg.h>
44 #include <time.h>
45 #include <string.h>
46 #include <getopt.h>
47 #include <errno.h>
48 #include <inttypes.h>
49
50 #include <infiniband/common.h>
51 #include <infiniband/umad.h>
52 #include <infiniband/mad.h>
53 #include <infiniband/complib/cl_nodenamemap.h>
54
55 #include "ibnetdiscover.h"
56 #include "grouping.h"
57 #include "ibdiag_common.h"
58
59 static char *node_type_str[] = {
60         "???",
61         "ca",
62         "switch",
63         "router",
64         "iwarp rnic"
65 };
66
67 static char *linkwidth_str[] = {
68         "??",
69         "1x",
70         "4x",
71         "??",
72         "8x",
73         "??",
74         "??",
75         "??",
76         "12x"
77 };
78
79 static char *linkspeed_str[] = {
80         "???",
81         "SDR",
82         "DDR",
83         "???",
84         "QDR"
85 };
86
87 static int timeout = 2000;              /* ms */
88 static int dumplevel = 0;
89 static int verbose;
90 static FILE *f;
91
92 char *argv0 = "ibnetdiscover";
93
94 static char *node_name_map_file = NULL;
95 static nn_map_t *node_name_map = NULL;
96
97 Node *nodesdist[MAXHOPS+1];     /* last is Ca list */
98 Node *mynode;
99 int maxhops_discovered = 0;
100
101 struct ChassisList *chassis = NULL;
102
103 static char *
104 get_linkwidth_str(int linkwidth)
105 {
106         if (linkwidth > 8)
107                 return linkwidth_str[0];
108         else
109                 return linkwidth_str[linkwidth];
110 }
111
112 static char *
113 get_linkspeed_str(int linkspeed)
114 {
115         if (linkspeed > 4)
116                 return linkspeed_str[0];
117         else
118                 return linkspeed_str[linkspeed];
119 }
120
121 static inline const char*
122 node_type_str2(Node *node)
123 {
124         switch(node->type) {
125         case SWITCH_NODE: return "SW";
126         case CA_NODE:     return "CA";
127         case ROUTER_NODE: return "RT";
128         }
129         return "??";
130 }
131
132 void
133 decode_port_info(void *pi, Port *port)
134 {
135         mad_decode_field(pi, IB_PORT_LID_F, &port->lid);
136         mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc);
137         mad_decode_field(pi, IB_PORT_STATE_F, &port->state);
138         mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate);
139         mad_decode_field(pi, IB_PORT_LINK_WIDTH_ACTIVE_F, &port->linkwidth);
140         mad_decode_field(pi, IB_PORT_LINK_SPEED_ACTIVE_F, &port->linkspeed);
141 }
142
143
144 int
145 get_port(Port *port, int portnum, ib_portid_t *portid)
146 {
147         char portinfo[64];
148         void *pi = portinfo;
149
150         port->portnum = portnum;
151
152         if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout))
153                 return -1;
154         decode_port_info(pi, port);
155
156         DEBUG("portid %s portnum %d: lid %d state %d physstate %d %s %s",
157                 portid2str(portid), portnum, port->lid, port->state, port->physstate, get_linkwidth_str(port->linkwidth), get_linkspeed_str(port->linkspeed));
158         return 1;
159 }
160 /*
161  * Returns 0 if non switch node is found, 1 if switch is found, -1 if error.
162  */
163 int
164 get_node(Node *node, Port *port, ib_portid_t *portid)
165 {
166         char portinfo[64];
167         char switchinfo[64];
168         void *pi = portinfo, *ni = node->nodeinfo, *nd = node->nodedesc;
169         void *si = switchinfo;
170
171         if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout))
172                 return -1;
173
174         mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid);
175         mad_decode_field(ni, IB_NODE_TYPE_F, &node->type);
176         mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports);
177         mad_decode_field(ni, IB_NODE_DEVID_F, &node->devid);
178         mad_decode_field(ni, IB_NODE_VENDORID_F, &node->vendid);
179         mad_decode_field(ni, IB_NODE_SYSTEM_GUID_F, &node->sysimgguid);
180         mad_decode_field(ni, IB_NODE_PORT_GUID_F, &node->portguid);
181         mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &node->localport);
182         port->portnum = node->localport;
183         port->portguid = node->portguid;
184
185         if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout))
186                 return -1;
187
188         if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout))
189                 return -1;
190         decode_port_info(pi, port);
191
192         if (node->type != SWITCH_NODE)
193                 return 0;
194
195         node->smalid = port->lid;
196         node->smalmc = port->lmc;
197
198         /* after we have the sma information find out the real PortInfo for this port */
199         if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, node->localport, timeout))
200                 return -1;
201         decode_port_info(pi, port);
202
203         if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout))
204                 node->smaenhsp0 = 0;    /* assume base SP0 */
205         else
206                 mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &node->smaenhsp0);
207
208         DEBUG("portid %s: got switch node %" PRIx64 " '%s'",
209               portid2str(portid), node->nodeguid, node->nodedesc);
210         return 1;
211 }
212
213 static int
214 extend_dpath(ib_dr_path_t *path, int nextport)
215 {
216         if (path->cnt+2 >= sizeof(path->p))
217                 return -1;
218         ++path->cnt;
219         if (path->cnt > maxhops_discovered)
220                 maxhops_discovered = path->cnt;
221         path->p[path->cnt] = nextport;
222         return path->cnt;
223 }
224
225 static void
226 dump_endnode(ib_portid_t *path, char *prompt, Node *node, Port *port)
227 {
228         if (!dumplevel)
229                 return;
230
231         fprintf(f, "%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d\"%s\"\n",
232                 portid2str(path), prompt,
233                 (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),
234                 node->nodeguid, node->type == SWITCH_NODE ? 0 : port->portnum,
235                 port->lid, port->lid + (1 << port->lmc) - 1,
236                 clean_nodedesc(node->nodedesc));
237 }
238
239 #define HASHGUID(guid)          ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))
240 #define HTSZ 137
241
242 static Node *nodestbl[HTSZ];
243
244 static Node *
245 find_node(Node *new)
246 {
247         int hash = HASHGUID(new->nodeguid) % HTSZ;
248         Node *node;
249
250         for (node = nodestbl[hash]; node; node = node->htnext)
251                 if (node->nodeguid == new->nodeguid)
252                         return node;
253
254         return NULL;
255 }
256
257 static Node *
258 create_node(Node *temp, ib_portid_t *path, int dist)
259 {
260         Node *node;
261         int hash = HASHGUID(temp->nodeguid) % HTSZ;
262
263         node = malloc(sizeof(*node));
264         if (!node)
265                 return NULL;
266
267         memcpy(node, temp, sizeof(*node));
268         node->dist = dist;
269         node->path = *path;
270
271         node->htnext = nodestbl[hash];
272         nodestbl[hash] = node;
273
274         if (node->type != SWITCH_NODE)
275                 dist = MAXHOPS;         /* special Ca list */
276
277         node->dnext = nodesdist[dist];
278         nodesdist[dist] = node;
279
280         return node;
281 }
282
283 static Port *
284 find_port(Node *node, Port *port)
285 {
286         Port *old;
287
288         for (old = node->ports; old; old = old->next)
289                 if (old->portnum == port->portnum)
290                         return old;
291
292         return NULL;
293 }
294
295 static Port *
296 create_port(Node *node, Port *temp)
297 {
298         Port *port;
299
300         port = malloc(sizeof(*port));
301         if (!port)
302                 return NULL;
303
304         memcpy(port, temp, sizeof(*port));
305         port->node = node;
306         port->next = node->ports;
307         node->ports = port;
308
309         return port;
310 }
311
312 static void
313 link_ports(Node *node, Port *port, Node *remotenode, Port *remoteport)
314 {
315         DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u",
316                 node->nodeguid, node, port, port->portnum,
317                 remotenode->nodeguid, remotenode, remoteport, remoteport->portnum);
318         if (port->remoteport)
319                 port->remoteport->remoteport = NULL;
320         if (remoteport->remoteport)
321                 remoteport->remoteport->remoteport = NULL;
322         port->remoteport = remoteport;
323         remoteport->remoteport = port;
324 }
325
326 static int
327 handle_port(Node *node, Port *port, ib_portid_t *path, int portnum, int dist)
328 {
329         Node node_buf;
330         Port port_buf;
331         Node *remotenode, *oldnode;
332         Port *remoteport, *oldport;
333
334         memset(&node_buf, 0, sizeof(node_buf));
335         memset(&port_buf, 0, sizeof(port_buf));
336
337         DEBUG("handle node %p port %p:%d dist %d", node, port, portnum, dist);
338         if (port->physstate != 5)       /* LinkUp */
339                 return -1;
340
341         if (extend_dpath(&path->drpath, portnum) < 0)
342                 return -1;
343
344         if (get_node(&node_buf, &port_buf, path) < 0) {
345                 IBWARN("NodeInfo on %s failed, skipping port",
346                         portid2str(path));
347                 path->drpath.cnt--;     /* restore path */
348                 return -1;
349         }
350
351         oldnode = find_node(&node_buf);
352         if (oldnode)
353                 remotenode = oldnode;
354         else if (!(remotenode = create_node(&node_buf, path, dist + 1)))
355                 IBERROR("no memory");
356
357         oldport = find_port(remotenode, &port_buf);
358         if (oldport) {
359                 remoteport = oldport;
360                 if (node != remotenode || port != remoteport)
361                         IBWARN("port moving...");
362         } else if (!(remoteport = create_port(remotenode, &port_buf)))
363                 IBERROR("no memory");
364
365         dump_endnode(path, oldnode ? "known remote" : "new remote",
366                      remotenode, remoteport);
367
368         link_ports(node, port, remotenode, remoteport);
369
370         path->drpath.cnt--;     /* restore path */
371         return 0;
372 }
373
374 /*
375  * Return 1 if found, 0 if not, -1 on errors.
376  */
377 static int
378 discover(ib_portid_t *from)
379 {
380         Node node_buf;
381         Port port_buf;
382         Node *node;
383         Port *port;
384         int i;
385         int dist = 0;
386         ib_portid_t *path;
387
388         DEBUG("from %s", portid2str(from));
389
390         memset(&node_buf, 0, sizeof(node_buf));
391         memset(&port_buf, 0, sizeof(port_buf));
392
393         if (get_node(&node_buf, &port_buf, from) < 0) {
394                 IBWARN("can't reach node %s", portid2str(from));
395                 return -1;
396         }
397
398         node = create_node(&node_buf, from, 0);
399         if (!node)
400                 IBERROR("out of memory");
401
402         mynode = node;
403
404         port = create_port(node, &port_buf);
405         if (!port)
406                 IBERROR("out of memory");
407
408         if (node->type != SWITCH_NODE &&
409             handle_port(node, port, from, node->localport, 0) < 0)
410                 return 0;
411
412         for (dist = 0; dist < MAXHOPS; dist++) {
413
414                 for (node = nodesdist[dist]; node; node = node->dnext) {
415
416                         path = &node->path;
417
418                         DEBUG("dist %d node %p", dist, node);
419                         dump_endnode(path, "processing", node, port);
420
421                         for (i = 1; i <= node->numports; i++) {
422                                 if (i == node->localport)
423                                         continue;
424
425                                 if (get_port(&port_buf, i, path) < 0) {
426                                         IBWARN("can't reach node %s port %d", portid2str(path), i);
427                                         continue;
428                                 }
429
430                                 port = find_port(node, &port_buf);
431                                 if (port)
432                                         continue;
433
434                                 port = create_port(node, &port_buf);
435                                 if (!port)
436                                         IBERROR("out of memory");
437
438                                 /* If switch, set port GUID to node GUID */
439                                 if (node->type == SWITCH_NODE)
440                                         port->portguid = node->portguid;
441
442                                 handle_port(node, port, path, i, dist);
443                         }
444                 }
445         }
446
447         return 0;
448 }
449
450 char *
451 node_name(Node *node)
452 {
453         static char buf[256];
454
455         switch(node->type) {
456         case SWITCH_NODE:
457                 sprintf(buf, "\"%s", "S");
458                 break;
459         case CA_NODE:
460                 sprintf(buf, "\"%s", "H");
461                 break;
462         case ROUTER_NODE:
463                 sprintf(buf, "\"%s", "R");
464                 break;
465         default:
466                 sprintf(buf, "\"%s", "?");
467                 break;
468         }
469         sprintf(buf+2, "-%016" PRIx64 "\"", node->nodeguid);
470
471         return buf;
472 }
473
474 void
475 list_node(Node *node)
476 {
477         char *node_type;
478         char *nodename = remap_node_name(node_name_map, node->nodeguid,
479                                               node->nodedesc);
480
481         switch(node->type) {
482         case SWITCH_NODE:
483                 node_type = "Switch";
484                 break;
485         case CA_NODE:
486                 node_type = "Ca";
487                 break;
488         case ROUTER_NODE:
489                 node_type = "Router";
490                 break;
491         default:
492                 node_type = "???";
493                 break;
494         }
495         fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n",
496                 node_type,
497                 node->nodeguid, node->numports, node->devid, node->vendid,
498                 nodename);
499
500         free(nodename);
501 }
502
503 void
504 out_ids(Node *node, int group, char *chname)
505 {
506         fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", node->vendid, node->devid);
507         if (node->sysimgguid)
508                 fprintf(f, "sysimgguid=0x%" PRIx64, node->sysimgguid);
509         if (group
510             && node->chrecord && node->chrecord->chassisnum) {
511                 fprintf(f, "\t\t# Chassis %d", node->chrecord->chassisnum);
512                 if (chname)
513                         fprintf(f, " (%s)", chname);
514                 if (is_xsigo_tca(node->nodeguid) && node->ports->remoteport)
515                         fprintf(f, " slot %d", node->ports->remoteport->portnum);
516         }
517         fprintf(f, "\n");
518 }
519
520 uint64_t
521 out_chassis(int chassisnum)
522 {
523         uint64_t guid;
524
525         fprintf(f, "\nChassis %d", chassisnum);
526         guid = get_chassis_guid(chassisnum);
527         if (guid)
528                 fprintf(f, " (guid 0x%" PRIx64 ")", guid);
529         fprintf(f, "\n");
530         return guid;
531 }
532
533 void
534 out_switch(Node *node, int group, char *chname)
535 {
536         char *str;
537         char *nodename = NULL;
538
539         out_ids(node, group, chname);
540         fprintf(f, "switchguid=0x%" PRIx64, node->nodeguid);
541         fprintf(f, "(%" PRIx64 ")", node->portguid);
542         /* Currently, only if Voltaire chassis */
543         if (group
544             && node->chrecord && node->chrecord->chassisnum
545             && node->vendid == VTR_VENDOR_ID) {
546                 str = get_chassis_type(node->chrecord->chassistype);
547                 if (str)
548                         fprintf(f, "%s ", str);
549                 str = get_chassis_slot(node->chrecord->chassisslot);
550                 if (str)
551                         fprintf(f, "%s ", str);
552                 fprintf(f, "%d Chip %d", node->chrecord->slotnum, node->chrecord->anafanum);
553         }
554
555         nodename = remap_node_name(node_name_map, node->nodeguid,
556                                 node->nodedesc);
557
558         fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n",
559                 node->numports, node_name(node),
560                 nodename,
561                 node->smaenhsp0 ? "enhanced" : "base",
562                 node->smalid, node->smalmc);
563
564         free(nodename);
565 }
566
567 void
568 out_ca(Node *node, int group, char *chname)
569 {
570         char *node_type;
571         char *node_type2;
572         char *nodename = remap_node_name(node_name_map, node->nodeguid,
573                                               node->nodedesc);
574
575         out_ids(node, group, chname);
576         switch(node->type) {
577         case CA_NODE:
578                 node_type = "ca";
579                 node_type2 = "Ca";
580                 break;
581         case ROUTER_NODE:
582                 node_type = "rt";
583                 node_type2 = "Rt";
584                 break;
585         default:
586                 node_type = "???";
587                 node_type2 = "???";
588                 break;
589         }
590
591         fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->nodeguid);
592         fprintf(f, "%s\t%d %s\t\t# \"%s\"",
593                 node_type2, node->numports, node_name(node),
594                 nodename);
595         if (group && is_xsigo_hca(node->nodeguid))
596                 fprintf(f, " (scp)");
597         fprintf(f, "\n");
598
599         free(nodename);
600 }
601
602 static char *
603 out_ext_port(Port *port, int group)
604 {
605         char *str = NULL;
606
607         /* Currently, only if Voltaire chassis */
608         if (group
609             && port->node->chrecord && port->node->vendid == VTR_VENDOR_ID)
610                 str = portmapstring(port);
611
612         return (str);
613 }
614
615 void
616 out_switch_port(Port *port, int group)
617 {
618         char *ext_port_str = NULL;
619         char *rem_nodename = NULL;
620
621         DEBUG("port %p:%d remoteport %p", port, port->portnum, port->remoteport);
622         fprintf(f, "[%d]", port->portnum);
623
624         ext_port_str = out_ext_port(port, group);
625         if (ext_port_str)
626                 fprintf(f, "%s", ext_port_str);
627
628         rem_nodename = remap_node_name(node_name_map,
629                                 port->remoteport->node->nodeguid,
630                                 port->remoteport->node->nodedesc);
631
632         ext_port_str = out_ext_port(port->remoteport, group);
633         fprintf(f, "\t%s[%d]%s",
634                 node_name(port->remoteport->node),
635                 port->remoteport->portnum,
636                 ext_port_str ? ext_port_str : "");
637         if (port->remoteport->node->type != SWITCH_NODE)
638                 fprintf(f, "(%" PRIx64 ") ", port->remoteport->portguid);
639         fprintf(f, "\t\t# \"%s\" lid %d %s%s",
640                 rem_nodename,
641                 port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid,
642                 get_linkwidth_str(port->linkwidth),
643                 get_linkspeed_str(port->linkspeed));
644
645         if (is_xsigo_tca(port->remoteport->portguid))
646                 fprintf(f, " slot %d", port->portnum);
647         else if (is_xsigo_hca(port->remoteport->portguid))
648                 fprintf(f, " (scp)");
649         fprintf(f, "\n");
650
651         free(rem_nodename);
652 }
653
654 void
655 out_ca_port(Port *port, int group)
656 {
657         char *str = NULL;
658         char *rem_nodename = NULL;
659
660         fprintf(f, "[%d]", port->portnum);
661         if (port->node->type != SWITCH_NODE)
662                 fprintf(f, "(%" PRIx64 ") ", port->portguid);
663         fprintf(f, "\t%s[%d]",
664                 node_name(port->remoteport->node),
665                 port->remoteport->portnum);
666         str = out_ext_port(port->remoteport, group);
667         if (str)
668                 fprintf(f, "%s", str);
669         if (port->remoteport->node->type != SWITCH_NODE)
670                 fprintf(f, " (%" PRIx64 ") ", port->remoteport->portguid);
671
672         rem_nodename = remap_node_name(node_name_map,
673                                 port->remoteport->node->nodeguid,
674                                 port->remoteport->node->nodedesc);
675
676         fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n",
677                 port->lid, port->lmc, rem_nodename,
678                 port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid,
679                 get_linkwidth_str(port->linkwidth),
680                 get_linkspeed_str(port->linkspeed));
681
682         free(rem_nodename);
683 }
684
685 int
686 dump_topology(int listtype, int group)
687 {
688         Node *node;
689         Port *port;
690         int i = 0, dist = 0;
691         time_t t = time(0);
692         uint64_t chguid;
693         char *chname = NULL;
694
695         if (!listtype) {
696                 fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));
697                 fprintf(f, "# Max of %d hops discovered\n", maxhops_discovered);
698                 fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", mynode->nodeguid, mynode->portguid);
699         }
700
701         /* Make pass on switches */
702         if (group && !listtype) {
703                 ChassisList *ch = NULL;
704
705                 /* Chassis based switches first */
706                 for (ch = chassis; ch; ch = ch->next) {
707                         int n = 0;
708
709                         if (!ch->chassisnum)
710                                 continue;
711                         chguid = out_chassis(ch->chassisnum);
712                         if (chname)
713                                 free(chname);
714                         chname = NULL;
715                         if (is_xsigo_guid(chguid)) {
716                                 for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {
717                                         if (!node->chrecord ||
718                                             !node->chrecord->chassisnum)
719                                                 continue;
720
721                                         if (node->chrecord->chassisnum != ch->chassisnum)
722                                                 continue;
723
724                                         if (is_xsigo_hca(node->nodeguid)) {
725                                                 chname = remap_node_name(node_name_map,
726                                                                 node->nodeguid,
727                                                                 node->nodedesc);
728                                                 fprintf(f, "Hostname: %s\n", chname);
729                                         }
730                                 }
731                         }
732
733                         fprintf(f, "\n# Spine Nodes");
734                         for (n = 1; n <= (SPINES_MAX_NUM+1); n++) {
735                                 if (ch->spinenode[n]) {
736                                         out_switch(ch->spinenode[n], group, chname);
737                                         for (port = ch->spinenode[n]->ports; port; port = port->next, i++)
738                                                 if (port->remoteport)
739                                                         out_switch_port(port, group);
740                                 }
741                         }
742                         fprintf(f, "\n# Line Nodes");
743                         for (n = 1; n <= (LINES_MAX_NUM+1); n++) {
744                                 if (ch->linenode[n]) {
745                                         out_switch(ch->linenode[n], group, chname);
746                                         for (port = ch->linenode[n]->ports; port; port = port->next, i++)
747                                                 if (port->remoteport)
748                                                         out_switch_port(port, group);
749                                 }
750                         }
751
752                         fprintf(f, "\n# Chassis Switches");
753                         for (dist = 0; dist <= maxhops_discovered; dist++) {
754
755                                 for (node = nodesdist[dist]; node; node = node->dnext) {
756
757                                         /* Non Voltaire chassis */
758                                         if (node->vendid == VTR_VENDOR_ID)
759                                                 continue;
760                                         if (!node->chrecord ||
761                                             !node->chrecord->chassisnum)
762                                                 continue;
763
764                                         if (node->chrecord->chassisnum != ch->chassisnum)
765                                                 continue;
766
767                                         out_switch(node, group, chname);
768                                         for (port = node->ports; port; port = port->next, i++)
769                                                 if (port->remoteport)
770                                                         out_switch_port(port, group);
771
772                                 }
773
774                         }
775
776                         fprintf(f, "\n# Chassis CAs");
777                         for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {
778                                 if (!node->chrecord ||
779                                     !node->chrecord->chassisnum)
780                                         continue;
781
782                                 if (node->chrecord->chassisnum != ch->chassisnum)
783                                         continue;
784
785                                 out_ca(node, group, chname);
786                                 for (port = node->ports; port; port = port->next, i++)
787                                         if (port->remoteport)
788                                                 out_ca_port(port, group);
789
790                         }
791
792                 }
793
794         } else {
795                 for (dist = 0; dist <= maxhops_discovered; dist++) {
796
797                         for (node = nodesdist[dist]; node; node = node->dnext) {
798
799                                 DEBUG("SWITCH: dist %d node %p", dist, node);
800                                 if (!listtype)
801                                         out_switch(node, group, chname);
802                                 else {
803                                         if (listtype & LIST_SWITCH_NODE)
804                                                 list_node(node);
805                                         continue;
806                                 }
807
808                                 for (port = node->ports; port; port = port->next, i++)
809                                         if (port->remoteport)
810                                                 out_switch_port(port, group);
811                         }
812                 }
813         }
814
815         if (chname)
816                 free(chname);
817         chname = NULL;
818         if (group && !listtype) {
819
820                 fprintf(f, "\nNon-Chassis Nodes\n");
821
822                 for (dist = 0; dist <= maxhops_discovered; dist++) {
823
824                         for (node = nodesdist[dist]; node; node = node->dnext) {
825
826                                 DEBUG("SWITCH: dist %d node %p", dist, node);
827                                 /* Now, skip chassis based switches */
828                                 if (node->chrecord &&
829                                     node->chrecord->chassisnum)
830                                         continue;
831                                 out_switch(node, group, chname);
832
833                                 for (port = node->ports; port; port = port->next, i++)
834                                         if (port->remoteport)
835                                                 out_switch_port(port, group);
836                         }
837
838                 }
839
840         }
841
842         /* Make pass on CAs */
843         for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {
844
845                 DEBUG("CA: dist %d node %p", dist, node);
846                 if (!listtype) {
847                         /* Now, skip chassis based CAs */
848                         if (group && node->chrecord &&
849                             node->chrecord->chassisnum)
850                                 continue;
851                         out_ca(node, group, chname);
852                 } else {
853                         if (((listtype & LIST_CA_NODE) && (node->type == CA_NODE)) ||
854                             ((listtype & LIST_ROUTER_NODE) && (node->type == ROUTER_NODE)))
855                                 list_node(node);
856                         continue;
857                 }
858
859                 for (port = node->ports; port; port = port->next, i++)
860                         if (port->remoteport)
861                                 out_ca_port(port, group);
862         }
863
864         if (chname)
865                 free(chname);
866
867         return i;
868 }
869
870 void dump_ports_report ()
871 {
872         int b, n = 0, p;
873         Node *node;
874         Port *port;
875
876         // If switch and LID == 0, search of other switch ports with
877         // valid LID and assign it to all ports of that switch
878         for (b = 0; b <= MAXHOPS; b++)
879                 for (node = nodesdist[b]; node; node = node->dnext)
880                         if (node->type == SWITCH_NODE) {
881                                 int swlid = 0;
882                                 for (p = 0, port = node->ports;
883                                      p < node->numports && port && !swlid;
884                                      port = port->next)
885                                         if (port->lid != 0)
886                                                 swlid = port->lid;
887                                 for (p = 0, port = node->ports;
888                                      p < node->numports && port;
889                                      port = port->next)
890                                         port->lid = swlid;
891                         }
892
893         for (b = 0; b <= MAXHOPS; b++)
894                 for (node = nodesdist[b]; node; node = node->dnext) {
895                         for (p = 0, port = node->ports;
896                              p < node->numports && port;
897                              p++, port = port->next) {
898                                 fprintf(stdout,
899                                         "%2s %5d %2d 0x%016" PRIx64 " %s %s",
900                                         node_type_str2(port->node), port->lid,
901                                         port->portnum,
902                                         port->portguid,
903                                         get_linkwidth_str(port->linkwidth),
904                                         get_linkspeed_str(port->linkspeed));
905                                 if (port->remoteport)
906                                         fprintf(stdout,
907                                                 " - %2s %5d %2d 0x%016" PRIx64
908                                                 " ( '%s' - '%s' )\n",
909                                                 node_type_str2(port->remoteport->node),
910                                                 port->remoteport->lid,
911                                                 port->remoteport->portnum,
912                                                 port->remoteport->portguid,
913                                                 port->node->nodedesc,
914                                                 port->remoteport->node->nodedesc);
915                                 else
916                                         fprintf(stdout, "%36s'%s'\n", "",
917                                                 port->node->nodedesc);
918                         }
919                         n++;
920                 }
921 }
922
923 void
924 usage(void)
925 {
926         fprintf(stderr, "Usage: %s [-d(ebug)] -e(rr_show) -v(erbose) -s(how) -l(ist) -g(rouping) -H(ca_list) -S(witch_list) -R(outer_list) -V(ersion) -C ca_name -P ca_port "
927                         "-t(imeout) timeout_ms --node-name-map node-name-map] -p(orts) [<topology-file>]\n",
928                         argv0);
929         fprintf(stderr, "       --node-name-map <node-name-map> specify a node name map file\n");
930         exit(-1);
931 }
932
933 int
934 main(int argc, char **argv)
935 {
936         int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS};
937         ib_portid_t my_portid = {0};
938         int udebug = 0, list = 0;
939         char *ca = 0;
940         int ca_port = 0;
941         int group = 0;
942         int ports_report = 0;
943
944         static char const str_opts[] = "C:P:t:devslgHSRpVhu";
945         static const struct option long_opts[] = {
946                 { "C", 1, 0, 'C'},
947                 { "P", 1, 0, 'P'},
948                 { "debug", 0, 0, 'd'},
949                 { "err_show", 0, 0, 'e'},
950                 { "verbose", 0, 0, 'v'},
951                 { "show", 0, 0, 's'},
952                 { "list", 0, 0, 'l'},
953                 { "grouping", 0, 0, 'g'},
954                 { "Hca_list", 0, 0, 'H'},
955                 { "Switch_list", 0, 0, 'S'},
956                 { "Router_list", 0, 0, 'R'},
957                 { "timeout", 1, 0, 't'},
958                 { "node-name-map", 1, 0, 1},
959                 { "ports", 0, 0, 'p'},
960                 { "Version", 0, 0, 'V'},
961                 { "help", 0, 0, 'h'},
962                 { "usage", 0, 0, 'u'},
963                 { }
964         };
965
966         f = stdout;
967
968         argv0 = argv[0];
969
970         while (1) {
971                 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
972                 if ( ch == -1 )
973                         break;
974                 switch(ch) {
975                 case 1:
976                         node_name_map_file = strdup(optarg);
977                         break;
978                 case 'C':
979                         ca = optarg;
980                         break;
981                 case 'P':
982                         ca_port = strtoul(optarg, 0, 0);
983                         break;
984                 case 'd':
985                         ibdebug++;
986                         madrpc_show_errors(1);
987                         umad_debug(udebug);
988                         udebug++;
989                         break;
990                 case 't':
991                         timeout = strtoul(optarg, 0, 0);
992                         break;
993                 case 'v':
994                         verbose++;
995                         dumplevel++;
996                         break;
997                 case 's':
998                         dumplevel = 1;
999                         break;
1000                 case 'e':
1001                         madrpc_show_errors(1);
1002                         break;
1003                 case 'l':
1004                         list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
1005                         break;
1006                 case 'g':
1007                         group = 1;
1008                         break;
1009                 case 'S':
1010                         list = LIST_SWITCH_NODE;
1011                         break;
1012                 case 'H':
1013                         list = LIST_CA_NODE;
1014                         break;
1015                 case 'R':
1016                         list = LIST_ROUTER_NODE;
1017                         break;
1018                 case 'V':
1019                         fprintf(stderr, "%s %s\n", argv0, get_build_version() );
1020                         exit(-1);
1021                 case 'p':
1022                         ports_report = 1;
1023                         break;
1024                 default:
1025                         usage();
1026                         break;
1027                 }
1028         }
1029         argc -= optind;
1030         argv += optind;
1031
1032         if (argc && !(f = fopen(argv[0], "w")))
1033                 IBERROR("can't open file %s for writing", argv[0]);
1034
1035         madrpc_init(ca, ca_port, mgmt_classes, 2);
1036         node_name_map = open_node_name_map(node_name_map_file);
1037
1038         if (discover(&my_portid) < 0)
1039                 IBERROR("discover");
1040
1041         if (group)
1042                 chassis = group_nodes();
1043
1044         if (ports_report)
1045                 dump_ports_report();
1046         else
1047                 dump_topology(list, group);
1048
1049         close_node_name_map(node_name_map);
1050         exit(0);
1051 }