1/*
2 * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
3 * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4 * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
5 * Copyright (c) 2010,2011 Mellanox Technologies LTD.  All rights reserved.
6 *
7 * This software is available to you under a choice of one of two
8 * licenses.  You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 *     Redistribution and use in source and binary forms, with or
14 *     without modification, are permitted provided that the following
15 *     conditions are met:
16 *
17 *      - Redistributions of source code must retain the above
18 *        copyright notice, this list of conditions and the following
19 *        disclaimer.
20 *
21 *      - Redistributions in binary form must reproduce the above
22 *        copyright notice, this list of conditions and the following
23 *        disclaimer in the documentation and/or other materials
24 *        provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 *
35 */
36
37#if HAVE_CONFIG_H
38#  include <config.h>
39#endif				/* HAVE_CONFIG_H */
40
41#define _GNU_SOURCE
42#include <stdio.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <stdarg.h>
46#include <time.h>
47#include <string.h>
48#include <getopt.h>
49#include <errno.h>
50#include <inttypes.h>
51
52#include <complib/cl_nodenamemap.h>
53#include <infiniband/ibnetdisc.h>
54
55#include "ibdiag_common.h"
56
57#define DIFF_FLAG_PORT_CONNECTION  0x01
58#define DIFF_FLAG_PORT_STATE       0x02
59#define DIFF_FLAG_LID              0x04
60#define DIFF_FLAG_NODE_DESCRIPTION 0x08
61
62#define DIFF_FLAG_DEFAULT (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_PORT_STATE)
63
64static char *node_name_map_file = NULL;
65static nn_map_t *node_name_map = NULL;
66static char *load_cache_file = NULL;
67static char *diff_cache_file = NULL;
68static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT;
69static char *filterdownports_cache_file = NULL;
70static ibnd_fabric_t *filterdownports_fabric = NULL;
71
72static uint64_t guid = 0;
73static char *guid_str = NULL;
74static char *dr_path = NULL;
75static int all = 0;
76
77static int down_links_only = 0;
78static int line_mode = 0;
79static int add_sw_settings = 0;
80static int only_flag = 0;
81static int only_type = 0;
82
83int filterdownport_check(ibnd_node_t * node, ibnd_port_t * port)
84{
85	ibnd_node_t *fsw;
86	ibnd_port_t *fport;
87	int fistate;
88
89	fsw = ibnd_find_node_guid(filterdownports_fabric, node->guid);
90
91	if (!fsw)
92		return 0;
93
94	if (port->portnum > fsw->numports)
95		return 0;
96
97	fport = fsw->ports[port->portnum];
98
99	if (!fport)
100		return 0;
101
102	fistate = mad_get_field(fport->info, 0, IB_PORT_STATE_F);
103
104	return (fistate == IB_LINK_DOWN) ? 1 : 0;
105}
106
107void print_port(ibnd_node_t * node, ibnd_port_t * port, char *out_prefix)
108{
109	char width[64], speed[64], state[64], physstate[64];
110	char remote_guid_str[256];
111	char remote_str[256];
112	char link_str[256];
113	char width_msg[256];
114	char speed_msg[256];
115	char ext_port_str[256];
116	int iwidth, ispeed, fdr10, espeed, istate, iphystate, cap_mask;
117	int n = 0;
118	uint8_t *info = NULL;
119
120	if (!port)
121		return;
122
123	iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
124	ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
125	fdr10 = mad_get_field(port->ext_info, 0,
126			      IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F) & FDR10;
127
128	if (port->node->type == IB_NODE_SWITCH) {
129		if (port->node->ports[0])
130			info = (uint8_t *)&port->node->ports[0]->info;
131	}
132	else
133		info = (uint8_t *)&port->info;
134
135	if (info) {
136		cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
137		if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS))
138			espeed = mad_get_field(port->info, 0,
139					       IB_PORT_LINK_SPEED_EXT_ACTIVE_F);
140		else
141			espeed = 0;
142	} else {
143		ispeed = 0;
144		iwidth = 0;
145		espeed = 0;
146	}
147
148	istate = mad_get_field(port->info, 0, IB_PORT_STATE_F);
149	iphystate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F);
150
151	remote_guid_str[0] = '\0';
152	remote_str[0] = '\0';
153	link_str[0] = '\0';
154	width_msg[0] = '\0';
155	speed_msg[0] = '\0';
156
157	if (istate == IB_LINK_DOWN
158	    && filterdownports_fabric
159	    && filterdownport_check(node, port))
160		return;
161
162	/* C14-24.2.1 states that a down port allows for invalid data to be
163	 * returned for all PortInfo components except PortState and
164	 * PortPhysicalState */
165	if (istate != IB_LINK_DOWN) {
166		if (!espeed) {
167			if (fdr10)
168				sprintf(speed, "10.0 Gbps (FDR10)");
169			else
170				mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed,
171					     64, &ispeed);
172		} else
173			mad_dump_val(IB_PORT_LINK_SPEED_EXT_ACTIVE_F, speed,
174				     64, &espeed);
175
176		n = snprintf(link_str, 256, "(%3s %18s %6s/%8s)",
177		     mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64,
178				  &iwidth),
179		     speed,
180		     mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
181		     mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64,
182				  &iphystate));
183	} else {
184		n = snprintf(link_str, 256, "(              %6s/%8s)",
185		     mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
186		     mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64,
187				  &iphystate));
188	}
189
190	/* again default values due to C14-24.2.1 */
191	if (add_sw_settings && istate != IB_LINK_DOWN) {
192		snprintf(link_str + n, 256 - n,
193			" (HOQ:%d VL_Stall:%d)",
194			mad_get_field(port->info, 0,
195				IB_PORT_HOQ_LIFE_F),
196			mad_get_field(port->info, 0,
197				IB_PORT_VL_STALL_COUNT_F));
198	}
199
200	if (port->remoteport) {
201		char *remap =
202		    remap_node_name(node_name_map, port->remoteport->node->guid,
203				    port->remoteport->node->nodedesc);
204
205		if (port->remoteport->ext_portnum)
206			snprintf(ext_port_str, 256, "%d",
207				 port->remoteport->ext_portnum);
208		else
209			ext_port_str[0] = '\0';
210
211		get_max_msg(width_msg, speed_msg, 256, port);
212
213		if (line_mode) {
214			snprintf(remote_guid_str, 256,
215				 "0x%016" PRIx64 " ",
216				 port->remoteport->guid);
217		}
218
219		snprintf(remote_str, 256, "%s%6d %4d[%2s] \"%s\" (%s %s)\n",
220			 remote_guid_str, port->remoteport->base_lid ?
221			 port->remoteport->base_lid :
222			 port->remoteport->node->smalid,
223			 port->remoteport->portnum, ext_port_str, remap,
224			 width_msg, speed_msg);
225		free(remap);
226	} else {
227		if (istate == IB_LINK_DOWN)
228			snprintf(remote_str, 256, "           [  ] \"\" ( )\n");
229		else
230			snprintf(remote_str, 256, "    \"Port not available\"\n");
231	}
232
233	if (port->ext_portnum)
234		snprintf(ext_port_str, 256, "%d", port->ext_portnum);
235	else
236		ext_port_str[0] = '\0';
237
238	if (line_mode) {
239		char *remap = remap_node_name(node_name_map, node->guid,
240					      node->nodedesc);
241		printf("%s0x%016" PRIx64 " \"%30s\" ",
242		       out_prefix ? out_prefix : "",
243		       port->guid, remap);
244		free(remap);
245	} else
246		printf("%s      ", out_prefix ? out_prefix : "");
247
248	if (port->node->type != IB_NODE_SWITCH) {
249		if (!line_mode)
250			printf("0x%016" PRIx64 " ", port->guid);
251
252		printf("%6d %4d[%2s] ==%s==>  %s",
253			port->base_lid,
254			port->portnum, ext_port_str, link_str, remote_str);
255	} else
256		printf("%6d %4d[%2s] ==%s==>  %s",
257			node->smalid, port->portnum, ext_port_str,
258			link_str, remote_str);
259}
260
261static inline const char *nodetype_str(ibnd_node_t * node)
262{
263	switch (node->type) {
264	case IB_NODE_SWITCH:
265		return "Switch";
266	case IB_NODE_CA:
267		return "CA";
268	case IB_NODE_ROUTER:
269		return "Router";
270	}
271	return "??";
272}
273
274void print_node_header(ibnd_node_t *node, int *out_header_flag,
275			char *out_prefix)
276{
277	uint64_t guid = 0;
278	if ((!out_header_flag || !(*out_header_flag)) && !line_mode) {
279		char *remap =
280			remap_node_name(node_name_map, node->guid, node->nodedesc);
281		if (node->type == IB_NODE_SWITCH) {
282			if (node->ports[0])
283				guid = node->ports[0]->guid;
284			else /* if (node->info) */
285				guid = mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F);
286
287			printf("%s%s: 0x%016" PRIx64 " %s:\n",
288				out_prefix ? out_prefix : "",
289				nodetype_str(node),
290				guid,
291				remap);
292		} else
293			printf("%s%s: %s:\n",
294				out_prefix ? out_prefix : "",
295				nodetype_str(node), remap);
296		if (out_header_flag)
297			(*out_header_flag)++;
298		free(remap);
299	}
300}
301
302void print_node(ibnd_node_t * node, void *user_data)
303{
304	int i = 0;
305	int head_print = 0;
306	char *out_prefix = (char *)user_data;
307
308	for (i = 1; i <= node->numports; i++) {
309		ibnd_port_t *port = node->ports[i];
310		if (!port)
311			continue;
312		if (!down_links_only ||
313		    mad_get_field(port->info, 0,
314				  IB_PORT_STATE_F) == IB_LINK_DOWN) {
315			print_node_header(node, &head_print, out_prefix);
316			print_port(node, port, out_prefix);
317		}
318	}
319}
320
321struct iter_diff_data {
322        uint32_t diff_flags;
323        ibnd_fabric_t *fabric1;
324        ibnd_fabric_t *fabric2;
325        char *fabric1_prefix;
326        char *fabric2_prefix;
327};
328
329void diff_node_ports(ibnd_node_t * fabric1_node, ibnd_node_t * fabric2_node,
330		       int *head_print, struct iter_diff_data *data)
331{
332	int i = 0;
333
334	for (i = 1; i <= fabric1_node->numports; i++) {
335		ibnd_port_t *fabric1_port, *fabric2_port;
336		int output_diff = 0;
337
338		fabric1_port = fabric1_node->ports[i];
339		fabric2_port = fabric2_node->ports[i];
340
341		if (!fabric1_port && !fabric2_port)
342			continue;
343
344		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION) {
345			if ((fabric1_port && !fabric2_port)
346			    || (!fabric1_port && fabric2_port)
347			    || (fabric1_port->remoteport
348				&& !fabric2_port->remoteport)
349			    || (!fabric1_port->remoteport
350				&& fabric2_port->remoteport)
351			    || (fabric1_port->remoteport
352				&& fabric2_port->remoteport
353				&& fabric1_port->remoteport->guid !=
354				fabric2_port->remoteport->guid))
355				output_diff++;
356		}
357
358		/* if either fabric1_port or fabric2_port NULL, should be
359		 * handled by port connection diff code
360		 */
361		if (data->diff_flags & DIFF_FLAG_PORT_STATE
362		    && fabric1_port
363		    && fabric2_port) {
364			int state1, state2;
365
366			state1 = mad_get_field(fabric1_port->info, 0,
367					       IB_PORT_STATE_F);
368			state2 = mad_get_field(fabric2_port->info, 0,
369					       IB_PORT_STATE_F);
370
371			if (state1 != state2)
372				output_diff++;
373		}
374
375		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
376		    && data->diff_flags & DIFF_FLAG_LID
377		    && fabric1_port && fabric2_port
378		    && fabric1_port->remoteport && fabric2_port->remoteport
379		    && fabric1_port->remoteport->base_lid != fabric2_port->remoteport->base_lid)
380			output_diff++;
381
382		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
383		    && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
384		    && fabric1_port && fabric2_port
385		    && fabric1_port->remoteport && fabric2_port->remoteport
386		    && memcmp(fabric1_port->remoteport->node->nodedesc,
387			      fabric2_port->remoteport->node->nodedesc,
388			      IB_SMP_DATA_SIZE))
389			output_diff++;
390
391		if (output_diff && fabric1_port) {
392			print_node_header(fabric1_node,
393					    head_print,
394					    NULL);
395			print_port(fabric1_node,
396				   fabric1_port,
397				   data->fabric1_prefix);
398		}
399
400		if (output_diff && fabric2_port) {
401			print_node_header(fabric2_node,
402					    head_print,
403					    NULL);
404			print_port(fabric2_node,
405				   fabric2_port,
406				   data->fabric2_prefix);
407		}
408	}
409}
410
411void diff_node_iter(ibnd_node_t * fabric1_node, void *iter_user_data)
412{
413	struct iter_diff_data *data = iter_user_data;
414	ibnd_node_t *fabric2_node;
415	int head_print = 0;
416
417	DEBUG("DEBUG: fabric1_node %p\n", fabric1_node);
418
419	fabric2_node = ibnd_find_node_guid(data->fabric2, fabric1_node->guid);
420	if (!fabric2_node)
421		print_node(fabric1_node, data->fabric1_prefix);
422	else if (data->diff_flags &
423		 (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_PORT_STATE
424		  | DIFF_FLAG_LID | DIFF_FLAG_NODE_DESCRIPTION)) {
425
426		if ((fabric1_node->type == IB_NODE_SWITCH
427		     && data->diff_flags & DIFF_FLAG_LID
428		     && fabric1_node->smalid != fabric2_node->smalid) ||
429		    (data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
430		     && memcmp(fabric1_node->nodedesc, fabric2_node->nodedesc,
431			       IB_SMP_DATA_SIZE))) {
432			print_node_header(fabric1_node,
433					    NULL,
434					    data->fabric1_prefix);
435			print_node_header(fabric2_node,
436					    NULL,
437					    data->fabric2_prefix);
438			head_print++;
439		}
440
441		if (fabric1_node->numports != fabric2_node->numports) {
442			print_node_header(fabric1_node,
443					    &head_print,
444					    NULL);
445			printf("%snumports = %d\n", data->fabric1_prefix,
446			       fabric1_node->numports);
447			printf("%snumports = %d\n", data->fabric2_prefix,
448			       fabric2_node->numports);
449			return;
450		}
451
452		diff_node_ports(fabric1_node, fabric2_node,
453				  &head_print, data);
454	}
455}
456
457int diff_node(ibnd_node_t * node, ibnd_fabric_t * orig_fabric,
458		ibnd_fabric_t * new_fabric)
459{
460	struct iter_diff_data iter_diff_data;
461
462	iter_diff_data.diff_flags = diffcheck_flags;
463	iter_diff_data.fabric1 = orig_fabric;
464	iter_diff_data.fabric2 = new_fabric;
465	iter_diff_data.fabric1_prefix = "< ";
466	iter_diff_data.fabric2_prefix = "> ";
467	if (node)
468		diff_node_iter(node, &iter_diff_data);
469	else {
470		if (only_flag)
471			ibnd_iter_nodes_type(orig_fabric, diff_node_iter,
472					     only_type, &iter_diff_data);
473		else
474			ibnd_iter_nodes(orig_fabric, diff_node_iter,
475					&iter_diff_data);
476	}
477
478	/* Do opposite diff to find existence of node types
479	 * in new_fabric but not in orig_fabric.
480	 *
481	 * In this diff, we don't need to check port connections,
482	 * port state, lids, or node descriptions since it has already
483	 * been done (i.e. checks are only done when guid exists on both
484	 * orig and new).
485	 */
486	iter_diff_data.diff_flags = diffcheck_flags & ~DIFF_FLAG_PORT_CONNECTION;
487	iter_diff_data.diff_flags &= ~DIFF_FLAG_PORT_STATE;
488	iter_diff_data.diff_flags &= ~DIFF_FLAG_LID;
489	iter_diff_data.diff_flags &= ~DIFF_FLAG_NODE_DESCRIPTION;
490	iter_diff_data.fabric1 = new_fabric;
491	iter_diff_data.fabric2 = orig_fabric;
492	iter_diff_data.fabric1_prefix = "> ";
493	iter_diff_data.fabric2_prefix = "< ";
494	if (node)
495		diff_node_iter(node, &iter_diff_data);
496	else {
497		if (only_flag)
498			ibnd_iter_nodes_type(new_fabric, diff_node_iter,
499					     only_type, &iter_diff_data);
500		else
501			ibnd_iter_nodes(new_fabric, diff_node_iter,
502					&iter_diff_data);
503	}
504
505	return 0;
506}
507
508static int process_opt(void *context, int ch, char *optarg)
509{
510	struct ibnd_config *cfg = context;
511	char *p;
512
513	switch (ch) {
514	case 1:
515		node_name_map_file = strdup(optarg);
516		break;
517	case 2:
518		load_cache_file = strdup(optarg);
519		break;
520	case 3:
521		diff_cache_file = strdup(optarg);
522		break;
523	case 4:
524		diffcheck_flags = 0;
525		p = strtok(optarg, ",");
526		while (p) {
527			if (!strcasecmp(p, "port"))
528				diffcheck_flags |= DIFF_FLAG_PORT_CONNECTION;
529			else if (!strcasecmp(p, "state"))
530				diffcheck_flags |= DIFF_FLAG_PORT_STATE;
531			else if (!strcasecmp(p, "lid"))
532				diffcheck_flags |= DIFF_FLAG_LID;
533			else if (!strcasecmp(p, "nodedesc"))
534				diffcheck_flags |= DIFF_FLAG_NODE_DESCRIPTION;
535			else {
536				fprintf(stderr, "invalid diff check key: %s\n",
537					p);
538				return -1;
539			}
540			p = strtok(NULL, ",");
541		}
542		break;
543	case 5:
544		filterdownports_cache_file = strdup(optarg);
545		break;
546	case 6:
547		only_flag = 1;
548		only_type = IB_NODE_SWITCH;
549		break;
550	case 7:
551		only_flag = 1;
552		only_type = IB_NODE_CA;
553		break;
554	case 'S':
555	case 'G':
556		guid_str = optarg;
557		guid = (uint64_t) strtoull(guid_str, 0, 0);
558		break;
559	case 'D':
560		dr_path = strdup(optarg);
561		break;
562	case 'a':
563		all = 1;
564		break;
565	case 'n':
566		cfg->max_hops = strtoul(optarg, NULL, 0);
567		break;
568	case 'd':
569		down_links_only = 1;
570		break;
571	case 'l':
572		line_mode = 1;
573		break;
574	case 'p':
575		add_sw_settings = 1;
576		break;
577	case 'R':		/* nop */
578		break;
579	case 'o':
580		cfg->max_smps = strtoul(optarg, NULL, 0);
581		break;
582	default:
583		return -1;
584	}
585
586	return 0;
587}
588
589int main(int argc, char **argv)
590{
591	struct ibnd_config config = { 0 };
592	int rc = 0;
593	int resolved = -1;
594	ibnd_fabric_t *fabric = NULL;
595	ibnd_fabric_t *diff_fabric = NULL;
596	struct ibmad_port *ibmad_port;
597	ib_portid_t port_id = { 0 };
598	uint8_t ni[IB_SMP_DATA_SIZE] = { 0 };
599	int mgmt_classes[3] =
600	    { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS };
601
602	const struct ibdiag_opt opts[] = {
603		{"node-name-map", 1, 1, "<file>", "node name map file"},
604		{"switch", 'S', 1, "<port_guid>",
605		 "start partial scan at the port specified by <port_guid> (hex format)"},
606		{"port-guid", 'G', 1, "<port_guid>",
607		 "(same as -S)"},
608		{"Direct", 'D', 1, "<dr_path>",
609		 "start partial scan at the port specified by <dr_path>"},
610		{"all", 'a', 0, NULL,
611		 "print all nodes found in a partial fabric scan"},
612		{"hops", 'n', 1, "<hops>",
613		 "Number of hops to include away from specified node"},
614		{"down", 'd', 0, NULL, "print only down links"},
615		{"line", 'l', 0, NULL,
616		 "(line mode) print all information for each link on a single line"},
617		{"additional", 'p', 0, NULL,
618		 "print additional port settings (PktLifeTime, HoqLife, VLStallCount)"},
619		{"load-cache", 2, 1, "<file>",
620		 "filename of ibnetdiscover cache to load"},
621		{"diff", 3, 1, "<file>",
622		 "filename of ibnetdiscover cache to diff"},
623		{"diffcheck", 4, 1, "<key(s)>",
624		 "specify checks to execute for --diff"},
625		{"filterdownports", 5, 1, "<file>",
626		 "filename of ibnetdiscover cache to filter downports"},
627		{"outstanding_smps", 'o', 1, NULL,
628		 "specify the number of outstanding SMP's which should be "
629		 "issued during the scan"},
630		{"switches-only", 6, 0, NULL,
631		 "Output only switches"},
632		{"cas-only", 7, 0, NULL,
633		 "Output only CAs"},
634		{0}
635	};
636	char usage_args[] = "";
637
638	ibdiag_process_opts(argc, argv, &config, "aDdGgKLlnpRS", opts,
639			    process_opt, usage_args, NULL);
640
641	argc -= optind;
642	argv += optind;
643
644	ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
645	if (!ibmad_port) {
646		fprintf(stderr, "Failed to open %s port %d\n", ibd_ca,
647			ibd_ca_port);
648		exit(1);
649	}
650
651	smp_mkey_set(ibmad_port, ibd_mkey);
652
653	if (ibd_timeout) {
654		mad_rpc_set_timeout(ibmad_port, ibd_timeout);
655		config.timeout_ms = ibd_timeout;
656	}
657
658	config.flags = ibd_ibnetdisc_flags;
659	config.mkey = ibd_mkey;
660
661	node_name_map = open_node_name_map(node_name_map_file);
662
663	if (dr_path && load_cache_file) {
664		mad_rpc_close_port(ibmad_port);
665		fprintf(stderr, "Cannot specify cache and direct route path\n");
666		exit(1);
667	}
668
669	if (dr_path) {
670		/* only scan part of the fabric */
671		if ((resolved =
672		     resolve_portid_str(ibd_ca, ibd_ca_port, &port_id, dr_path,
673					IB_DEST_DRPATH, NULL, ibmad_port)) < 0)
674			IBWARN("Failed to resolve %s; attempting full scan",
675			       dr_path);
676	} else if (guid_str) {
677		if ((resolved =
678		     resolve_portid_str(ibd_ca, ibd_ca_port, &port_id,
679				        guid_str, IB_DEST_GUID, NULL,
680					ibmad_port)) < 0)
681			IBWARN("Failed to resolve %s; attempting full scan\n",
682			       guid_str);
683	}
684
685	if (!smp_query_via(ni, &port_id, IB_ATTR_NODE_INFO, 0,
686				   ibd_timeout, ibmad_port)){
687			mad_rpc_close_port(ibmad_port);
688			fprintf(stderr,
689				"Failed to get local Node Info\n");
690			exit(1);
691	}
692	mad_rpc_close_port(ibmad_port);
693
694	if (diff_cache_file &&
695	    !(diff_fabric = ibnd_load_fabric(diff_cache_file, 0)))
696		IBEXIT("loading cached fabric for diff failed\n");
697
698	if (filterdownports_cache_file &&
699	    !(filterdownports_fabric = ibnd_load_fabric(filterdownports_cache_file, 0)))
700		IBEXIT("loading cached fabric for filterdownports failed\n");
701
702	if (load_cache_file) {
703		if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) {
704			fprintf(stderr, "loading cached fabric failed\n");
705			exit(1);
706		}
707	} else {
708		if (resolved >= 0) {
709			if (!config.max_hops)
710				config.max_hops = 1;
711			if (!(fabric =
712			    ibnd_discover_fabric(ibd_ca, ibd_ca_port, &port_id, &config)))
713				IBWARN("Partial fabric scan failed;"
714				       " attempting full scan\n");
715		}
716
717		if (!fabric &&
718		    !(fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config))) {
719			fprintf(stderr, "discover failed\n");
720			rc = 1;
721			goto close_port;
722		}
723	}
724
725	if (!all && guid_str) {
726		ibnd_port_t *p = ibnd_find_port_guid(fabric, guid);
727		if (p && (!only_flag || p->node->type == only_type)) {
728			ibnd_node_t *n = p->node;
729			if (diff_fabric)
730				diff_node(n, diff_fabric, fabric);
731			else
732				print_node(n, NULL);
733		}
734		else
735			fprintf(stderr, "Failed to find port: %s\n", guid_str);
736	} else if (!all && dr_path) {
737		ibnd_port_t *p = NULL;
738		mad_decode_field(ni, IB_NODE_PORT_GUID_F, &(guid));
739
740		p = ibnd_find_port_guid(fabric, guid);
741		if (p && (!only_flag || p->node->type == only_type)) {
742			ibnd_node_t *n = p->node;
743			if (diff_fabric)
744				diff_node(n, diff_fabric, fabric);
745			else
746				print_node(n, NULL);
747		}
748		else
749			fprintf(stderr, "Failed to find port: %s\n", dr_path);
750	} else {
751		if (diff_fabric)
752			diff_node(NULL, diff_fabric, fabric);
753		else {
754			if (only_flag)
755				ibnd_iter_nodes_type(fabric, print_node,
756						     only_type, NULL);
757			else
758				ibnd_iter_nodes(fabric, print_node, NULL);
759		}
760	}
761
762	ibnd_destroy_fabric(fabric);
763	if (diff_fabric)
764		ibnd_destroy_fabric(diff_fabric);
765
766close_port:
767	close_node_name_map(node_name_map);
768	exit(rc);
769}
770