1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
3219820Sjeff * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4219820Sjeff *
5219820Sjeff * This software is available to you under a choice of one of two
6219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
7219820Sjeff * General Public License (GPL) Version 2, available from the file
8219820Sjeff * COPYING in the main directory of this source tree, or the
9219820Sjeff * OpenIB.org BSD license below:
10219820Sjeff *
11219820Sjeff *     Redistribution and use in source and binary forms, with or
12219820Sjeff *     without modification, are permitted provided that the following
13219820Sjeff *     conditions are met:
14219820Sjeff *
15219820Sjeff *      - Redistributions of source code must retain the above
16219820Sjeff *        copyright notice, this list of conditions and the following
17219820Sjeff *        disclaimer.
18219820Sjeff *
19219820Sjeff *      - Redistributions in binary form must reproduce the above
20219820Sjeff *        copyright notice, this list of conditions and the following
21219820Sjeff *        disclaimer in the documentation and/or other materials
22219820Sjeff *        provided with the distribution.
23219820Sjeff *
24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31219820Sjeff * SOFTWARE.
32219820Sjeff *
33219820Sjeff */
34219820Sjeff
35219820Sjeff#if HAVE_CONFIG_H
36219820Sjeff#  include <config.h>
37219820Sjeff#endif /* HAVE_CONFIG_H */
38219820Sjeff
39219820Sjeff#define _GNU_SOURCE
40219820Sjeff#include <stdio.h>
41219820Sjeff#include <stdlib.h>
42219820Sjeff#include <unistd.h>
43219820Sjeff#include <stdarg.h>
44219820Sjeff#include <time.h>
45219820Sjeff#include <string.h>
46219820Sjeff#include <getopt.h>
47219820Sjeff#include <errno.h>
48219820Sjeff#include <inttypes.h>
49219820Sjeff
50219820Sjeff#include <infiniband/common.h>
51219820Sjeff#include <infiniband/umad.h>
52219820Sjeff#include <infiniband/mad.h>
53219820Sjeff#include <infiniband/complib/cl_nodenamemap.h>
54219820Sjeff
55219820Sjeff#include "ibnetdiscover.h"
56219820Sjeff#include "grouping.h"
57219820Sjeff#include "ibdiag_common.h"
58219820Sjeff
59219820Sjeffstatic char *node_type_str[] = {
60219820Sjeff	"???",
61219820Sjeff	"ca",
62219820Sjeff	"switch",
63219820Sjeff	"router",
64219820Sjeff	"iwarp rnic"
65219820Sjeff};
66219820Sjeff
67219820Sjeffstatic char *linkwidth_str[] = {
68219820Sjeff	"??",
69219820Sjeff	"1x",
70219820Sjeff	"4x",
71219820Sjeff	"??",
72219820Sjeff	"8x",
73219820Sjeff	"??",
74219820Sjeff	"??",
75219820Sjeff	"??",
76219820Sjeff	"12x"
77219820Sjeff};
78219820Sjeff
79219820Sjeffstatic char *linkspeed_str[] = {
80219820Sjeff	"???",
81219820Sjeff	"SDR",
82219820Sjeff	"DDR",
83219820Sjeff	"???",
84219820Sjeff	"QDR"
85219820Sjeff};
86219820Sjeff
87219820Sjeffstatic int timeout = 2000;		/* ms */
88219820Sjeffstatic int dumplevel = 0;
89219820Sjeffstatic int verbose;
90219820Sjeffstatic FILE *f;
91219820Sjeff
92219820Sjeffchar *argv0 = "ibnetdiscover";
93219820Sjeff
94219820Sjeffstatic char *node_name_map_file = NULL;
95219820Sjeffstatic nn_map_t *node_name_map = NULL;
96219820Sjeff
97219820SjeffNode *nodesdist[MAXHOPS+1];     /* last is Ca list */
98219820SjeffNode *mynode;
99219820Sjeffint maxhops_discovered = 0;
100219820Sjeff
101219820Sjeffstruct ChassisList *chassis = NULL;
102219820Sjeff
103219820Sjeffstatic char *
104219820Sjeffget_linkwidth_str(int linkwidth)
105219820Sjeff{
106219820Sjeff	if (linkwidth > 8)
107219820Sjeff		return linkwidth_str[0];
108219820Sjeff	else
109219820Sjeff		return linkwidth_str[linkwidth];
110219820Sjeff}
111219820Sjeff
112219820Sjeffstatic char *
113219820Sjeffget_linkspeed_str(int linkspeed)
114219820Sjeff{
115219820Sjeff	if (linkspeed > 4)
116219820Sjeff		return linkspeed_str[0];
117219820Sjeff	else
118219820Sjeff		return linkspeed_str[linkspeed];
119219820Sjeff}
120219820Sjeff
121219820Sjeffstatic inline const char*
122219820Sjeffnode_type_str2(Node *node)
123219820Sjeff{
124219820Sjeff	switch(node->type) {
125219820Sjeff	case SWITCH_NODE: return "SW";
126219820Sjeff	case CA_NODE:     return "CA";
127219820Sjeff	case ROUTER_NODE: return "RT";
128219820Sjeff	}
129219820Sjeff	return "??";
130219820Sjeff}
131219820Sjeff
132219820Sjeffvoid
133219820Sjeffdecode_port_info(void *pi, Port *port)
134219820Sjeff{
135219820Sjeff	mad_decode_field(pi, IB_PORT_LID_F, &port->lid);
136219820Sjeff	mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc);
137219820Sjeff	mad_decode_field(pi, IB_PORT_STATE_F, &port->state);
138219820Sjeff	mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate);
139219820Sjeff	mad_decode_field(pi, IB_PORT_LINK_WIDTH_ACTIVE_F, &port->linkwidth);
140219820Sjeff	mad_decode_field(pi, IB_PORT_LINK_SPEED_ACTIVE_F, &port->linkspeed);
141219820Sjeff}
142219820Sjeff
143219820Sjeff
144219820Sjeffint
145219820Sjeffget_port(Port *port, int portnum, ib_portid_t *portid)
146219820Sjeff{
147219820Sjeff	char portinfo[64];
148219820Sjeff	void *pi = portinfo;
149219820Sjeff
150219820Sjeff	port->portnum = portnum;
151219820Sjeff
152219820Sjeff	if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout))
153219820Sjeff		return -1;
154219820Sjeff	decode_port_info(pi, port);
155219820Sjeff
156219820Sjeff	DEBUG("portid %s portnum %d: lid %d state %d physstate %d %s %s",
157219820Sjeff		portid2str(portid), portnum, port->lid, port->state, port->physstate, get_linkwidth_str(port->linkwidth), get_linkspeed_str(port->linkspeed));
158219820Sjeff	return 1;
159219820Sjeff}
160219820Sjeff/*
161219820Sjeff * Returns 0 if non switch node is found, 1 if switch is found, -1 if error.
162219820Sjeff */
163219820Sjeffint
164219820Sjeffget_node(Node *node, Port *port, ib_portid_t *portid)
165219820Sjeff{
166219820Sjeff	char portinfo[64];
167219820Sjeff	char switchinfo[64];
168219820Sjeff	void *pi = portinfo, *ni = node->nodeinfo, *nd = node->nodedesc;
169219820Sjeff	void *si = switchinfo;
170219820Sjeff
171219820Sjeff	if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout))
172219820Sjeff		return -1;
173219820Sjeff
174219820Sjeff	mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid);
175219820Sjeff	mad_decode_field(ni, IB_NODE_TYPE_F, &node->type);
176219820Sjeff	mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports);
177219820Sjeff	mad_decode_field(ni, IB_NODE_DEVID_F, &node->devid);
178219820Sjeff	mad_decode_field(ni, IB_NODE_VENDORID_F, &node->vendid);
179219820Sjeff	mad_decode_field(ni, IB_NODE_SYSTEM_GUID_F, &node->sysimgguid);
180219820Sjeff	mad_decode_field(ni, IB_NODE_PORT_GUID_F, &node->portguid);
181219820Sjeff	mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &node->localport);
182219820Sjeff	port->portnum = node->localport;
183219820Sjeff	port->portguid = node->portguid;
184219820Sjeff
185219820Sjeff	if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout))
186219820Sjeff		return -1;
187219820Sjeff
188219820Sjeff	if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout))
189219820Sjeff		return -1;
190219820Sjeff	decode_port_info(pi, port);
191219820Sjeff
192219820Sjeff	if (node->type != SWITCH_NODE)
193219820Sjeff		return 0;
194219820Sjeff
195219820Sjeff	node->smalid = port->lid;
196219820Sjeff	node->smalmc = port->lmc;
197219820Sjeff
198219820Sjeff	/* after we have the sma information find out the real PortInfo for this port */
199219820Sjeff	if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, node->localport, timeout))
200219820Sjeff	        return -1;
201219820Sjeff	decode_port_info(pi, port);
202219820Sjeff
203219820Sjeff        if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout))
204219820Sjeff                node->smaenhsp0 = 0;	/* assume base SP0 */
205219820Sjeff	else
206219820Sjeff        	mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &node->smaenhsp0);
207219820Sjeff
208219820Sjeff	DEBUG("portid %s: got switch node %" PRIx64 " '%s'",
209219820Sjeff	      portid2str(portid), node->nodeguid, node->nodedesc);
210219820Sjeff	return 1;
211219820Sjeff}
212219820Sjeff
213219820Sjeffstatic int
214219820Sjeffextend_dpath(ib_dr_path_t *path, int nextport)
215219820Sjeff{
216219820Sjeff	if (path->cnt+2 >= sizeof(path->p))
217219820Sjeff		return -1;
218219820Sjeff	++path->cnt;
219219820Sjeff	if (path->cnt > maxhops_discovered)
220219820Sjeff		maxhops_discovered = path->cnt;
221219820Sjeff	path->p[path->cnt] = nextport;
222219820Sjeff	return path->cnt;
223219820Sjeff}
224219820Sjeff
225219820Sjeffstatic void
226219820Sjeffdump_endnode(ib_portid_t *path, char *prompt, Node *node, Port *port)
227219820Sjeff{
228219820Sjeff	if (!dumplevel)
229219820Sjeff		return;
230219820Sjeff
231219820Sjeff	fprintf(f, "%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d\"%s\"\n",
232219820Sjeff		portid2str(path), prompt,
233219820Sjeff		(node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),
234219820Sjeff		node->nodeguid, node->type == SWITCH_NODE ? 0 : port->portnum,
235219820Sjeff		port->lid, port->lid + (1 << port->lmc) - 1,
236219820Sjeff		clean_nodedesc(node->nodedesc));
237219820Sjeff}
238219820Sjeff
239219820Sjeff#define HASHGUID(guid)		((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))
240219820Sjeff#define HTSZ 137
241219820Sjeff
242219820Sjeffstatic Node *nodestbl[HTSZ];
243219820Sjeff
244219820Sjeffstatic Node *
245219820Sjefffind_node(Node *new)
246219820Sjeff{
247219820Sjeff	int hash = HASHGUID(new->nodeguid) % HTSZ;
248219820Sjeff	Node *node;
249219820Sjeff
250219820Sjeff	for (node = nodestbl[hash]; node; node = node->htnext)
251219820Sjeff		if (node->nodeguid == new->nodeguid)
252219820Sjeff			return node;
253219820Sjeff
254219820Sjeff	return NULL;
255219820Sjeff}
256219820Sjeff
257219820Sjeffstatic Node *
258219820Sjeffcreate_node(Node *temp, ib_portid_t *path, int dist)
259219820Sjeff{
260219820Sjeff	Node *node;
261219820Sjeff	int hash = HASHGUID(temp->nodeguid) % HTSZ;
262219820Sjeff
263219820Sjeff	node = malloc(sizeof(*node));
264219820Sjeff	if (!node)
265219820Sjeff		return NULL;
266219820Sjeff
267219820Sjeff	memcpy(node, temp, sizeof(*node));
268219820Sjeff	node->dist = dist;
269219820Sjeff	node->path = *path;
270219820Sjeff
271219820Sjeff	node->htnext = nodestbl[hash];
272219820Sjeff	nodestbl[hash] = node;
273219820Sjeff
274219820Sjeff	if (node->type != SWITCH_NODE)
275219820Sjeff		dist = MAXHOPS; 	/* special Ca list */
276219820Sjeff
277219820Sjeff	node->dnext = nodesdist[dist];
278219820Sjeff	nodesdist[dist] = node;
279219820Sjeff
280219820Sjeff	return node;
281219820Sjeff}
282219820Sjeff
283219820Sjeffstatic Port *
284219820Sjefffind_port(Node *node, Port *port)
285219820Sjeff{
286219820Sjeff	Port *old;
287219820Sjeff
288219820Sjeff	for (old = node->ports; old; old = old->next)
289219820Sjeff		if (old->portnum == port->portnum)
290219820Sjeff			return old;
291219820Sjeff
292219820Sjeff	return NULL;
293219820Sjeff}
294219820Sjeff
295219820Sjeffstatic Port *
296219820Sjeffcreate_port(Node *node, Port *temp)
297219820Sjeff{
298219820Sjeff	Port *port;
299219820Sjeff
300219820Sjeff	port = malloc(sizeof(*port));
301219820Sjeff	if (!port)
302219820Sjeff		return NULL;
303219820Sjeff
304219820Sjeff	memcpy(port, temp, sizeof(*port));
305219820Sjeff	port->node = node;
306219820Sjeff	port->next = node->ports;
307219820Sjeff	node->ports = port;
308219820Sjeff
309219820Sjeff	return port;
310219820Sjeff}
311219820Sjeff
312219820Sjeffstatic void
313219820Sjefflink_ports(Node *node, Port *port, Node *remotenode, Port *remoteport)
314219820Sjeff{
315219820Sjeff	DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u",
316219820Sjeff		node->nodeguid, node, port, port->portnum,
317219820Sjeff		remotenode->nodeguid, remotenode, remoteport, remoteport->portnum);
318219820Sjeff	if (port->remoteport)
319219820Sjeff		port->remoteport->remoteport = NULL;
320219820Sjeff	if (remoteport->remoteport)
321219820Sjeff		remoteport->remoteport->remoteport = NULL;
322219820Sjeff	port->remoteport = remoteport;
323219820Sjeff	remoteport->remoteport = port;
324219820Sjeff}
325219820Sjeff
326219820Sjeffstatic int
327219820Sjeffhandle_port(Node *node, Port *port, ib_portid_t *path, int portnum, int dist)
328219820Sjeff{
329219820Sjeff	Node node_buf;
330219820Sjeff	Port port_buf;
331219820Sjeff	Node *remotenode, *oldnode;
332219820Sjeff	Port *remoteport, *oldport;
333219820Sjeff
334219820Sjeff	memset(&node_buf, 0, sizeof(node_buf));
335219820Sjeff	memset(&port_buf, 0, sizeof(port_buf));
336219820Sjeff
337219820Sjeff	DEBUG("handle node %p port %p:%d dist %d", node, port, portnum, dist);
338219820Sjeff	if (port->physstate != 5)	/* LinkUp */
339219820Sjeff		return -1;
340219820Sjeff
341219820Sjeff	if (extend_dpath(&path->drpath, portnum) < 0)
342219820Sjeff		return -1;
343219820Sjeff
344219820Sjeff	if (get_node(&node_buf, &port_buf, path) < 0) {
345219820Sjeff		IBWARN("NodeInfo on %s failed, skipping port",
346219820Sjeff			portid2str(path));
347219820Sjeff		path->drpath.cnt--;	/* restore path */
348219820Sjeff		return -1;
349219820Sjeff	}
350219820Sjeff
351219820Sjeff	oldnode = find_node(&node_buf);
352219820Sjeff	if (oldnode)
353219820Sjeff		remotenode = oldnode;
354219820Sjeff	else if (!(remotenode = create_node(&node_buf, path, dist + 1)))
355219820Sjeff		IBERROR("no memory");
356219820Sjeff
357219820Sjeff	oldport = find_port(remotenode, &port_buf);
358219820Sjeff	if (oldport) {
359219820Sjeff		remoteport = oldport;
360219820Sjeff		if (node != remotenode || port != remoteport)
361219820Sjeff			IBWARN("port moving...");
362219820Sjeff	} else if (!(remoteport = create_port(remotenode, &port_buf)))
363219820Sjeff		IBERROR("no memory");
364219820Sjeff
365219820Sjeff	dump_endnode(path, oldnode ? "known remote" : "new remote",
366219820Sjeff		     remotenode, remoteport);
367219820Sjeff
368219820Sjeff	link_ports(node, port, remotenode, remoteport);
369219820Sjeff
370219820Sjeff	path->drpath.cnt--;	/* restore path */
371219820Sjeff	return 0;
372219820Sjeff}
373219820Sjeff
374219820Sjeff/*
375219820Sjeff * Return 1 if found, 0 if not, -1 on errors.
376219820Sjeff */
377219820Sjeffstatic int
378219820Sjeffdiscover(ib_portid_t *from)
379219820Sjeff{
380219820Sjeff	Node node_buf;
381219820Sjeff	Port port_buf;
382219820Sjeff	Node *node;
383219820Sjeff	Port *port;
384219820Sjeff	int i;
385219820Sjeff	int dist = 0;
386219820Sjeff	ib_portid_t *path;
387219820Sjeff
388219820Sjeff	DEBUG("from %s", portid2str(from));
389219820Sjeff
390219820Sjeff	memset(&node_buf, 0, sizeof(node_buf));
391219820Sjeff	memset(&port_buf, 0, sizeof(port_buf));
392219820Sjeff
393219820Sjeff	if (get_node(&node_buf, &port_buf, from) < 0) {
394219820Sjeff		IBWARN("can't reach node %s", portid2str(from));
395219820Sjeff		return -1;
396219820Sjeff	}
397219820Sjeff
398219820Sjeff	node = create_node(&node_buf, from, 0);
399219820Sjeff	if (!node)
400219820Sjeff		IBERROR("out of memory");
401219820Sjeff
402219820Sjeff	mynode = node;
403219820Sjeff
404219820Sjeff	port = create_port(node, &port_buf);
405219820Sjeff	if (!port)
406219820Sjeff		IBERROR("out of memory");
407219820Sjeff
408219820Sjeff	if (node->type != SWITCH_NODE &&
409219820Sjeff	    handle_port(node, port, from, node->localport, 0) < 0)
410219820Sjeff		return 0;
411219820Sjeff
412219820Sjeff	for (dist = 0; dist < MAXHOPS; dist++) {
413219820Sjeff
414219820Sjeff		for (node = nodesdist[dist]; node; node = node->dnext) {
415219820Sjeff
416219820Sjeff			path = &node->path;
417219820Sjeff
418219820Sjeff			DEBUG("dist %d node %p", dist, node);
419219820Sjeff			dump_endnode(path, "processing", node, port);
420219820Sjeff
421219820Sjeff			for (i = 1; i <= node->numports; i++) {
422219820Sjeff				if (i == node->localport)
423219820Sjeff					continue;
424219820Sjeff
425219820Sjeff				if (get_port(&port_buf, i, path) < 0) {
426219820Sjeff					IBWARN("can't reach node %s port %d", portid2str(path), i);
427219820Sjeff					continue;
428219820Sjeff				}
429219820Sjeff
430219820Sjeff				port = find_port(node, &port_buf);
431219820Sjeff				if (port)
432219820Sjeff					continue;
433219820Sjeff
434219820Sjeff				port = create_port(node, &port_buf);
435219820Sjeff				if (!port)
436219820Sjeff					IBERROR("out of memory");
437219820Sjeff
438219820Sjeff				/* If switch, set port GUID to node GUID */
439219820Sjeff				if (node->type == SWITCH_NODE)
440219820Sjeff					port->portguid = node->portguid;
441219820Sjeff
442219820Sjeff				handle_port(node, port, path, i, dist);
443219820Sjeff			}
444219820Sjeff		}
445219820Sjeff	}
446219820Sjeff
447219820Sjeff	return 0;
448219820Sjeff}
449219820Sjeff
450219820Sjeffchar *
451219820Sjeffnode_name(Node *node)
452219820Sjeff{
453219820Sjeff	static char buf[256];
454219820Sjeff
455219820Sjeff	switch(node->type) {
456219820Sjeff	case SWITCH_NODE:
457219820Sjeff		sprintf(buf, "\"%s", "S");
458219820Sjeff		break;
459219820Sjeff	case CA_NODE:
460219820Sjeff		sprintf(buf, "\"%s", "H");
461219820Sjeff		break;
462219820Sjeff	case ROUTER_NODE:
463219820Sjeff		sprintf(buf, "\"%s", "R");
464219820Sjeff		break;
465219820Sjeff	default:
466219820Sjeff		sprintf(buf, "\"%s", "?");
467219820Sjeff		break;
468219820Sjeff	}
469219820Sjeff	sprintf(buf+2, "-%016" PRIx64 "\"", node->nodeguid);
470219820Sjeff
471219820Sjeff	return buf;
472219820Sjeff}
473219820Sjeff
474219820Sjeffvoid
475219820Sjefflist_node(Node *node)
476219820Sjeff{
477219820Sjeff	char *node_type;
478219820Sjeff	char *nodename = remap_node_name(node_name_map, node->nodeguid,
479219820Sjeff					      node->nodedesc);
480219820Sjeff
481219820Sjeff	switch(node->type) {
482219820Sjeff	case SWITCH_NODE:
483219820Sjeff		node_type = "Switch";
484219820Sjeff		break;
485219820Sjeff	case CA_NODE:
486219820Sjeff		node_type = "Ca";
487219820Sjeff		break;
488219820Sjeff	case ROUTER_NODE:
489219820Sjeff		node_type = "Router";
490219820Sjeff		break;
491219820Sjeff	default:
492219820Sjeff		node_type = "???";
493219820Sjeff		break;
494219820Sjeff	}
495219820Sjeff	fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n",
496219820Sjeff		node_type,
497219820Sjeff		node->nodeguid, node->numports, node->devid, node->vendid,
498219820Sjeff		nodename);
499219820Sjeff
500219820Sjeff	free(nodename);
501219820Sjeff}
502219820Sjeff
503219820Sjeffvoid
504219820Sjeffout_ids(Node *node, int group, char *chname)
505219820Sjeff{
506219820Sjeff	fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", node->vendid, node->devid);
507219820Sjeff	if (node->sysimgguid)
508219820Sjeff		fprintf(f, "sysimgguid=0x%" PRIx64, node->sysimgguid);
509219820Sjeff	if (group
510219820Sjeff	    && node->chrecord && node->chrecord->chassisnum) {
511219820Sjeff		fprintf(f, "\t\t# Chassis %d", node->chrecord->chassisnum);
512219820Sjeff		if (chname)
513219820Sjeff			fprintf(f, " (%s)", chname);
514219820Sjeff		if (is_xsigo_tca(node->nodeguid) && node->ports->remoteport)
515219820Sjeff			fprintf(f, " slot %d", node->ports->remoteport->portnum);
516219820Sjeff	}
517219820Sjeff	fprintf(f, "\n");
518219820Sjeff}
519219820Sjeff
520219820Sjeffuint64_t
521219820Sjeffout_chassis(int chassisnum)
522219820Sjeff{
523219820Sjeff	uint64_t guid;
524219820Sjeff
525219820Sjeff	fprintf(f, "\nChassis %d", chassisnum);
526219820Sjeff	guid = get_chassis_guid(chassisnum);
527219820Sjeff	if (guid)
528219820Sjeff		fprintf(f, " (guid 0x%" PRIx64 ")", guid);
529219820Sjeff	fprintf(f, "\n");
530219820Sjeff	return guid;
531219820Sjeff}
532219820Sjeff
533219820Sjeffvoid
534219820Sjeffout_switch(Node *node, int group, char *chname)
535219820Sjeff{
536219820Sjeff	char *str;
537219820Sjeff	char *nodename = NULL;
538219820Sjeff
539219820Sjeff	out_ids(node, group, chname);
540219820Sjeff	fprintf(f, "switchguid=0x%" PRIx64, node->nodeguid);
541219820Sjeff	fprintf(f, "(%" PRIx64 ")", node->portguid);
542219820Sjeff	/* Currently, only if Voltaire chassis */
543219820Sjeff	if (group
544219820Sjeff	    && node->chrecord && node->chrecord->chassisnum
545219820Sjeff	    && node->vendid == VTR_VENDOR_ID) {
546219820Sjeff		str = get_chassis_type(node->chrecord->chassistype);
547219820Sjeff		if (str)
548219820Sjeff			fprintf(f, "%s ", str);
549219820Sjeff		str = get_chassis_slot(node->chrecord->chassisslot);
550219820Sjeff		if (str)
551219820Sjeff			fprintf(f, "%s ", str);
552219820Sjeff		fprintf(f, "%d Chip %d", node->chrecord->slotnum, node->chrecord->anafanum);
553219820Sjeff	}
554219820Sjeff
555219820Sjeff	nodename = remap_node_name(node_name_map, node->nodeguid,
556219820Sjeff				node->nodedesc);
557219820Sjeff
558219820Sjeff	fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n",
559219820Sjeff		node->numports, node_name(node),
560219820Sjeff		nodename,
561219820Sjeff		node->smaenhsp0 ? "enhanced" : "base",
562219820Sjeff		node->smalid, node->smalmc);
563219820Sjeff
564219820Sjeff	free(nodename);
565219820Sjeff}
566219820Sjeff
567219820Sjeffvoid
568219820Sjeffout_ca(Node *node, int group, char *chname)
569219820Sjeff{
570219820Sjeff	char *node_type;
571219820Sjeff	char *node_type2;
572219820Sjeff	char *nodename = remap_node_name(node_name_map, node->nodeguid,
573219820Sjeff					      node->nodedesc);
574219820Sjeff
575219820Sjeff	out_ids(node, group, chname);
576219820Sjeff	switch(node->type) {
577219820Sjeff	case CA_NODE:
578219820Sjeff		node_type = "ca";
579219820Sjeff		node_type2 = "Ca";
580219820Sjeff		break;
581219820Sjeff	case ROUTER_NODE:
582219820Sjeff		node_type = "rt";
583219820Sjeff		node_type2 = "Rt";
584219820Sjeff		break;
585219820Sjeff	default:
586219820Sjeff		node_type = "???";
587219820Sjeff		node_type2 = "???";
588219820Sjeff		break;
589219820Sjeff	}
590219820Sjeff
591219820Sjeff	fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->nodeguid);
592219820Sjeff	fprintf(f, "%s\t%d %s\t\t# \"%s\"",
593219820Sjeff		node_type2, node->numports, node_name(node),
594219820Sjeff		nodename);
595219820Sjeff	if (group && is_xsigo_hca(node->nodeguid))
596219820Sjeff		fprintf(f, " (scp)");
597219820Sjeff	fprintf(f, "\n");
598219820Sjeff
599219820Sjeff	free(nodename);
600219820Sjeff}
601219820Sjeff
602219820Sjeffstatic char *
603219820Sjeffout_ext_port(Port *port, int group)
604219820Sjeff{
605219820Sjeff	char *str = NULL;
606219820Sjeff
607219820Sjeff	/* Currently, only if Voltaire chassis */
608219820Sjeff	if (group
609219820Sjeff	    && port->node->chrecord && port->node->vendid == VTR_VENDOR_ID)
610219820Sjeff		str = portmapstring(port);
611219820Sjeff
612219820Sjeff	return (str);
613219820Sjeff}
614219820Sjeff
615219820Sjeffvoid
616219820Sjeffout_switch_port(Port *port, int group)
617219820Sjeff{
618219820Sjeff	char *ext_port_str = NULL;
619219820Sjeff	char *rem_nodename = NULL;
620219820Sjeff
621219820Sjeff	DEBUG("port %p:%d remoteport %p", port, port->portnum, port->remoteport);
622219820Sjeff	fprintf(f, "[%d]", port->portnum);
623219820Sjeff
624219820Sjeff	ext_port_str = out_ext_port(port, group);
625219820Sjeff	if (ext_port_str)
626219820Sjeff		fprintf(f, "%s", ext_port_str);
627219820Sjeff
628219820Sjeff	rem_nodename = remap_node_name(node_name_map,
629219820Sjeff				port->remoteport->node->nodeguid,
630219820Sjeff				port->remoteport->node->nodedesc);
631219820Sjeff
632219820Sjeff	ext_port_str = out_ext_port(port->remoteport, group);
633219820Sjeff	fprintf(f, "\t%s[%d]%s",
634219820Sjeff		node_name(port->remoteport->node),
635219820Sjeff		port->remoteport->portnum,
636219820Sjeff		ext_port_str ? ext_port_str : "");
637219820Sjeff	if (port->remoteport->node->type != SWITCH_NODE)
638219820Sjeff		fprintf(f, "(%" PRIx64 ") ", port->remoteport->portguid);
639219820Sjeff	fprintf(f, "\t\t# \"%s\" lid %d %s%s",
640219820Sjeff		rem_nodename,
641219820Sjeff		port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid,
642219820Sjeff		get_linkwidth_str(port->linkwidth),
643219820Sjeff		get_linkspeed_str(port->linkspeed));
644219820Sjeff
645219820Sjeff	if (is_xsigo_tca(port->remoteport->portguid))
646219820Sjeff		fprintf(f, " slot %d", port->portnum);
647219820Sjeff	else if (is_xsigo_hca(port->remoteport->portguid))
648219820Sjeff		fprintf(f, " (scp)");
649219820Sjeff	fprintf(f, "\n");
650219820Sjeff
651219820Sjeff	free(rem_nodename);
652219820Sjeff}
653219820Sjeff
654219820Sjeffvoid
655219820Sjeffout_ca_port(Port *port, int group)
656219820Sjeff{
657219820Sjeff	char *str = NULL;
658219820Sjeff	char *rem_nodename = NULL;
659219820Sjeff
660219820Sjeff	fprintf(f, "[%d]", port->portnum);
661219820Sjeff	if (port->node->type != SWITCH_NODE)
662219820Sjeff		fprintf(f, "(%" PRIx64 ") ", port->portguid);
663219820Sjeff	fprintf(f, "\t%s[%d]",
664219820Sjeff		node_name(port->remoteport->node),
665219820Sjeff		port->remoteport->portnum);
666219820Sjeff	str = out_ext_port(port->remoteport, group);
667219820Sjeff	if (str)
668219820Sjeff		fprintf(f, "%s", str);
669219820Sjeff	if (port->remoteport->node->type != SWITCH_NODE)
670219820Sjeff		fprintf(f, " (%" PRIx64 ") ", port->remoteport->portguid);
671219820Sjeff
672219820Sjeff	rem_nodename = remap_node_name(node_name_map,
673219820Sjeff				port->remoteport->node->nodeguid,
674219820Sjeff				port->remoteport->node->nodedesc);
675219820Sjeff
676219820Sjeff	fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n",
677219820Sjeff		port->lid, port->lmc, rem_nodename,
678219820Sjeff		port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid,
679219820Sjeff		get_linkwidth_str(port->linkwidth),
680219820Sjeff		get_linkspeed_str(port->linkspeed));
681219820Sjeff
682219820Sjeff	free(rem_nodename);
683219820Sjeff}
684219820Sjeff
685219820Sjeffint
686219820Sjeffdump_topology(int listtype, int group)
687219820Sjeff{
688219820Sjeff	Node *node;
689219820Sjeff	Port *port;
690219820Sjeff	int i = 0, dist = 0;
691219820Sjeff	time_t t = time(0);
692219820Sjeff	uint64_t chguid;
693219820Sjeff	char *chname = NULL;
694219820Sjeff
695219820Sjeff	if (!listtype) {
696219820Sjeff		fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));
697219820Sjeff		fprintf(f, "# Max of %d hops discovered\n", maxhops_discovered);
698219820Sjeff		fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", mynode->nodeguid, mynode->portguid);
699219820Sjeff	}
700219820Sjeff
701219820Sjeff	/* Make pass on switches */
702219820Sjeff	if (group && !listtype) {
703219820Sjeff		ChassisList *ch = NULL;
704219820Sjeff
705219820Sjeff		/* Chassis based switches first */
706219820Sjeff		for (ch = chassis; ch; ch = ch->next) {
707219820Sjeff			int n = 0;
708219820Sjeff
709219820Sjeff			if (!ch->chassisnum)
710219820Sjeff				continue;
711219820Sjeff			chguid = out_chassis(ch->chassisnum);
712219820Sjeff			if (chname)
713219820Sjeff				free(chname);
714219820Sjeff			chname = NULL;
715219820Sjeff			if (is_xsigo_guid(chguid)) {
716219820Sjeff				for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {
717219820Sjeff					if (!node->chrecord ||
718219820Sjeff					    !node->chrecord->chassisnum)
719219820Sjeff						continue;
720219820Sjeff
721219820Sjeff					if (node->chrecord->chassisnum != ch->chassisnum)
722219820Sjeff						continue;
723219820Sjeff
724219820Sjeff					if (is_xsigo_hca(node->nodeguid)) {
725219820Sjeff						chname = remap_node_name(node_name_map,
726219820Sjeff								node->nodeguid,
727219820Sjeff								node->nodedesc);
728219820Sjeff						fprintf(f, "Hostname: %s\n", chname);
729219820Sjeff					}
730219820Sjeff				}
731219820Sjeff			}
732219820Sjeff
733219820Sjeff			fprintf(f, "\n# Spine Nodes");
734219820Sjeff			for (n = 1; n <= (SPINES_MAX_NUM+1); n++) {
735219820Sjeff				if (ch->spinenode[n]) {
736219820Sjeff					out_switch(ch->spinenode[n], group, chname);
737219820Sjeff					for (port = ch->spinenode[n]->ports; port; port = port->next, i++)
738219820Sjeff						if (port->remoteport)
739219820Sjeff							out_switch_port(port, group);
740219820Sjeff				}
741219820Sjeff			}
742219820Sjeff			fprintf(f, "\n# Line Nodes");
743219820Sjeff			for (n = 1; n <= (LINES_MAX_NUM+1); n++) {
744219820Sjeff				if (ch->linenode[n]) {
745219820Sjeff					out_switch(ch->linenode[n], group, chname);
746219820Sjeff					for (port = ch->linenode[n]->ports; port; port = port->next, i++)
747219820Sjeff						if (port->remoteport)
748219820Sjeff							out_switch_port(port, group);
749219820Sjeff				}
750219820Sjeff			}
751219820Sjeff
752219820Sjeff			fprintf(f, "\n# Chassis Switches");
753219820Sjeff			for (dist = 0; dist <= maxhops_discovered; dist++) {
754219820Sjeff
755219820Sjeff				for (node = nodesdist[dist]; node; node = node->dnext) {
756219820Sjeff
757219820Sjeff					/* Non Voltaire chassis */
758219820Sjeff					if (node->vendid == VTR_VENDOR_ID)
759219820Sjeff						continue;
760219820Sjeff					if (!node->chrecord ||
761219820Sjeff					    !node->chrecord->chassisnum)
762219820Sjeff						continue;
763219820Sjeff
764219820Sjeff					if (node->chrecord->chassisnum != ch->chassisnum)
765219820Sjeff						continue;
766219820Sjeff
767219820Sjeff					out_switch(node, group, chname);
768219820Sjeff					for (port = node->ports; port; port = port->next, i++)
769219820Sjeff						if (port->remoteport)
770219820Sjeff							out_switch_port(port, group);
771219820Sjeff
772219820Sjeff				}
773219820Sjeff
774219820Sjeff			}
775219820Sjeff
776219820Sjeff			fprintf(f, "\n# Chassis CAs");
777219820Sjeff			for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {
778219820Sjeff				if (!node->chrecord ||
779219820Sjeff				    !node->chrecord->chassisnum)
780219820Sjeff					continue;
781219820Sjeff
782219820Sjeff				if (node->chrecord->chassisnum != ch->chassisnum)
783219820Sjeff					continue;
784219820Sjeff
785219820Sjeff				out_ca(node, group, chname);
786219820Sjeff				for (port = node->ports; port; port = port->next, i++)
787219820Sjeff					if (port->remoteport)
788219820Sjeff						out_ca_port(port, group);
789219820Sjeff
790219820Sjeff			}
791219820Sjeff
792219820Sjeff		}
793219820Sjeff
794219820Sjeff	} else {
795219820Sjeff		for (dist = 0; dist <= maxhops_discovered; dist++) {
796219820Sjeff
797219820Sjeff			for (node = nodesdist[dist]; node; node = node->dnext) {
798219820Sjeff
799219820Sjeff				DEBUG("SWITCH: dist %d node %p", dist, node);
800219820Sjeff				if (!listtype)
801219820Sjeff					out_switch(node, group, chname);
802219820Sjeff				else {
803219820Sjeff					if (listtype & LIST_SWITCH_NODE)
804219820Sjeff						list_node(node);
805219820Sjeff					continue;
806219820Sjeff				}
807219820Sjeff
808219820Sjeff				for (port = node->ports; port; port = port->next, i++)
809219820Sjeff					if (port->remoteport)
810219820Sjeff						out_switch_port(port, group);
811219820Sjeff			}
812219820Sjeff		}
813219820Sjeff	}
814219820Sjeff
815219820Sjeff	if (chname)
816219820Sjeff		free(chname);
817219820Sjeff	chname = NULL;
818219820Sjeff	if (group && !listtype) {
819219820Sjeff
820219820Sjeff		fprintf(f, "\nNon-Chassis Nodes\n");
821219820Sjeff
822219820Sjeff		for (dist = 0; dist <= maxhops_discovered; dist++) {
823219820Sjeff
824219820Sjeff			for (node = nodesdist[dist]; node; node = node->dnext) {
825219820Sjeff
826219820Sjeff				DEBUG("SWITCH: dist %d node %p", dist, node);
827219820Sjeff				/* Now, skip chassis based switches */
828219820Sjeff				if (node->chrecord &&
829219820Sjeff				    node->chrecord->chassisnum)
830219820Sjeff					continue;
831219820Sjeff				out_switch(node, group, chname);
832219820Sjeff
833219820Sjeff				for (port = node->ports; port; port = port->next, i++)
834219820Sjeff					if (port->remoteport)
835219820Sjeff						out_switch_port(port, group);
836219820Sjeff			}
837219820Sjeff
838219820Sjeff		}
839219820Sjeff
840219820Sjeff	}
841219820Sjeff
842219820Sjeff	/* Make pass on CAs */
843219820Sjeff	for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {
844219820Sjeff
845219820Sjeff		DEBUG("CA: dist %d node %p", dist, node);
846219820Sjeff		if (!listtype) {
847219820Sjeff			/* Now, skip chassis based CAs */
848219820Sjeff			if (group && node->chrecord &&
849219820Sjeff			    node->chrecord->chassisnum)
850219820Sjeff				continue;
851219820Sjeff			out_ca(node, group, chname);
852219820Sjeff		} else {
853219820Sjeff			if (((listtype & LIST_CA_NODE) && (node->type == CA_NODE)) ||
854219820Sjeff			    ((listtype & LIST_ROUTER_NODE) && (node->type == ROUTER_NODE)))
855219820Sjeff				list_node(node);
856219820Sjeff			continue;
857219820Sjeff		}
858219820Sjeff
859219820Sjeff		for (port = node->ports; port; port = port->next, i++)
860219820Sjeff			if (port->remoteport)
861219820Sjeff				out_ca_port(port, group);
862219820Sjeff	}
863219820Sjeff
864219820Sjeff	if (chname)
865219820Sjeff		free(chname);
866219820Sjeff
867219820Sjeff	return i;
868219820Sjeff}
869219820Sjeff
870219820Sjeffvoid dump_ports_report ()
871219820Sjeff{
872219820Sjeff	int b, n = 0, p;
873219820Sjeff	Node *node;
874219820Sjeff	Port *port;
875219820Sjeff
876219820Sjeff	// If switch and LID == 0, search of other switch ports with
877219820Sjeff	// valid LID and assign it to all ports of that switch
878219820Sjeff	for (b = 0; b <= MAXHOPS; b++)
879219820Sjeff		for (node = nodesdist[b]; node; node = node->dnext)
880219820Sjeff			if (node->type == SWITCH_NODE) {
881219820Sjeff				int swlid = 0;
882219820Sjeff				for (p = 0, port = node->ports;
883219820Sjeff				     p < node->numports && port && !swlid;
884219820Sjeff				     port = port->next)
885219820Sjeff					if (port->lid != 0)
886219820Sjeff						swlid = port->lid;
887219820Sjeff				for (p = 0, port = node->ports;
888219820Sjeff				     p < node->numports && port;
889219820Sjeff				     port = port->next)
890219820Sjeff					port->lid = swlid;
891219820Sjeff			}
892219820Sjeff
893219820Sjeff	for (b = 0; b <= MAXHOPS; b++)
894219820Sjeff		for (node = nodesdist[b]; node; node = node->dnext) {
895219820Sjeff			for (p = 0, port = node->ports;
896219820Sjeff			     p < node->numports && port;
897219820Sjeff			     p++, port = port->next) {
898219820Sjeff				fprintf(stdout,
899219820Sjeff					"%2s %5d %2d 0x%016" PRIx64 " %s %s",
900219820Sjeff					node_type_str2(port->node), port->lid,
901219820Sjeff					port->portnum,
902219820Sjeff					port->portguid,
903219820Sjeff					get_linkwidth_str(port->linkwidth),
904219820Sjeff					get_linkspeed_str(port->linkspeed));
905219820Sjeff				if (port->remoteport)
906219820Sjeff					fprintf(stdout,
907219820Sjeff						" - %2s %5d %2d 0x%016" PRIx64
908219820Sjeff						" ( '%s' - '%s' )\n",
909219820Sjeff						node_type_str2(port->remoteport->node),
910219820Sjeff						port->remoteport->lid,
911219820Sjeff						port->remoteport->portnum,
912219820Sjeff						port->remoteport->portguid,
913219820Sjeff						port->node->nodedesc,
914219820Sjeff						port->remoteport->node->nodedesc);
915219820Sjeff				else
916219820Sjeff					fprintf(stdout, "%36s'%s'\n", "",
917219820Sjeff						port->node->nodedesc);
918219820Sjeff			}
919219820Sjeff			n++;
920219820Sjeff		}
921219820Sjeff}
922219820Sjeff
923219820Sjeffvoid
924219820Sjeffusage(void)
925219820Sjeff{
926219820Sjeff	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 "
927219820Sjeff			"-t(imeout) timeout_ms --node-name-map node-name-map] -p(orts) [<topology-file>]\n",
928219820Sjeff			argv0);
929219820Sjeff	fprintf(stderr, "       --node-name-map <node-name-map> specify a node name map file\n");
930219820Sjeff	exit(-1);
931219820Sjeff}
932219820Sjeff
933219820Sjeffint
934219820Sjeffmain(int argc, char **argv)
935219820Sjeff{
936219820Sjeff	int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS};
937219820Sjeff	ib_portid_t my_portid = {0};
938219820Sjeff	int udebug = 0, list = 0;
939219820Sjeff	char *ca = 0;
940219820Sjeff	int ca_port = 0;
941219820Sjeff	int group = 0;
942219820Sjeff	int ports_report = 0;
943219820Sjeff
944219820Sjeff	static char const str_opts[] = "C:P:t:devslgHSRpVhu";
945219820Sjeff	static const struct option long_opts[] = {
946219820Sjeff		{ "C", 1, 0, 'C'},
947219820Sjeff		{ "P", 1, 0, 'P'},
948219820Sjeff		{ "debug", 0, 0, 'd'},
949219820Sjeff		{ "err_show", 0, 0, 'e'},
950219820Sjeff		{ "verbose", 0, 0, 'v'},
951219820Sjeff		{ "show", 0, 0, 's'},
952219820Sjeff		{ "list", 0, 0, 'l'},
953219820Sjeff		{ "grouping", 0, 0, 'g'},
954219820Sjeff		{ "Hca_list", 0, 0, 'H'},
955219820Sjeff		{ "Switch_list", 0, 0, 'S'},
956219820Sjeff		{ "Router_list", 0, 0, 'R'},
957219820Sjeff		{ "timeout", 1, 0, 't'},
958219820Sjeff		{ "node-name-map", 1, 0, 1},
959219820Sjeff		{ "ports", 0, 0, 'p'},
960219820Sjeff		{ "Version", 0, 0, 'V'},
961219820Sjeff		{ "help", 0, 0, 'h'},
962219820Sjeff		{ "usage", 0, 0, 'u'},
963219820Sjeff		{ }
964219820Sjeff	};
965219820Sjeff
966219820Sjeff	f = stdout;
967219820Sjeff
968219820Sjeff	argv0 = argv[0];
969219820Sjeff
970219820Sjeff	while (1) {
971219820Sjeff		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
972219820Sjeff		if ( ch == -1 )
973219820Sjeff			break;
974219820Sjeff		switch(ch) {
975219820Sjeff		case 1:
976219820Sjeff			node_name_map_file = strdup(optarg);
977219820Sjeff			break;
978219820Sjeff		case 'C':
979219820Sjeff			ca = optarg;
980219820Sjeff			break;
981219820Sjeff		case 'P':
982219820Sjeff			ca_port = strtoul(optarg, 0, 0);
983219820Sjeff			break;
984219820Sjeff		case 'd':
985219820Sjeff			ibdebug++;
986219820Sjeff			madrpc_show_errors(1);
987219820Sjeff			umad_debug(udebug);
988219820Sjeff			udebug++;
989219820Sjeff			break;
990219820Sjeff		case 't':
991219820Sjeff			timeout = strtoul(optarg, 0, 0);
992219820Sjeff			break;
993219820Sjeff		case 'v':
994219820Sjeff			verbose++;
995219820Sjeff			dumplevel++;
996219820Sjeff			break;
997219820Sjeff		case 's':
998219820Sjeff			dumplevel = 1;
999219820Sjeff			break;
1000219820Sjeff		case 'e':
1001219820Sjeff			madrpc_show_errors(1);
1002219820Sjeff			break;
1003219820Sjeff		case 'l':
1004219820Sjeff			list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
1005219820Sjeff			break;
1006219820Sjeff		case 'g':
1007219820Sjeff			group = 1;
1008219820Sjeff			break;
1009219820Sjeff		case 'S':
1010219820Sjeff			list = LIST_SWITCH_NODE;
1011219820Sjeff			break;
1012219820Sjeff		case 'H':
1013219820Sjeff			list = LIST_CA_NODE;
1014219820Sjeff			break;
1015219820Sjeff		case 'R':
1016219820Sjeff			list = LIST_ROUTER_NODE;
1017219820Sjeff			break;
1018219820Sjeff		case 'V':
1019219820Sjeff			fprintf(stderr, "%s %s\n", argv0, get_build_version() );
1020219820Sjeff			exit(-1);
1021219820Sjeff		case 'p':
1022219820Sjeff			ports_report = 1;
1023219820Sjeff			break;
1024219820Sjeff		default:
1025219820Sjeff			usage();
1026219820Sjeff			break;
1027219820Sjeff		}
1028219820Sjeff	}
1029219820Sjeff	argc -= optind;
1030219820Sjeff	argv += optind;
1031219820Sjeff
1032219820Sjeff	if (argc && !(f = fopen(argv[0], "w")))
1033219820Sjeff		IBERROR("can't open file %s for writing", argv[0]);
1034219820Sjeff
1035219820Sjeff	madrpc_init(ca, ca_port, mgmt_classes, 2);
1036219820Sjeff	node_name_map = open_node_name_map(node_name_map_file);
1037219820Sjeff
1038219820Sjeff	if (discover(&my_portid) < 0)
1039219820Sjeff		IBERROR("discover");
1040219820Sjeff
1041219820Sjeff	if (group)
1042219820Sjeff		chassis = group_nodes();
1043219820Sjeff
1044219820Sjeff	if (ports_report)
1045219820Sjeff		dump_ports_report();
1046219820Sjeff	else
1047219820Sjeff		dump_topology(list, group);
1048219820Sjeff
1049219820Sjeff	close_node_name_map(node_name_map);
1050219820Sjeff	exit(0);
1051219820Sjeff}
1052