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 
64 static char *node_name_map_file = NULL;
65 static nn_map_t *node_name_map = NULL;
66 static char *load_cache_file = NULL;
67 static char *diff_cache_file = NULL;
68 static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT;
69 static char *filterdownports_cache_file = NULL;
70 static ibnd_fabric_t *filterdownports_fabric = NULL;
71 
72 static uint64_t guid = 0;
73 static char *guid_str = NULL;
74 static char *dr_path = NULL;
75 static int all = 0;
76 
77 static int down_links_only = 0;
78 static int line_mode = 0;
79 static int add_sw_settings = 0;
80 static int only_flag = 0;
81 static int only_type = 0;
82 
83 int 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 
107 void 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 
261 static 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 
274 void 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 		(*out_header_flag)++;
297 		free(remap);
298 	}
299 }
300 
301 void print_node(ibnd_node_t * node, void *user_data)
302 {
303 	int i = 0;
304 	int head_print = 0;
305 	char *out_prefix = (char *)user_data;
306 
307 	for (i = 1; i <= node->numports; i++) {
308 		ibnd_port_t *port = node->ports[i];
309 		if (!port)
310 			continue;
311 		if (!down_links_only ||
312 		    mad_get_field(port->info, 0,
313 				  IB_PORT_STATE_F) == IB_LINK_DOWN) {
314 			print_node_header(node, &head_print, out_prefix);
315 			print_port(node, port, out_prefix);
316 		}
317 	}
318 }
319 
320 struct iter_diff_data {
321         uint32_t diff_flags;
322         ibnd_fabric_t *fabric1;
323         ibnd_fabric_t *fabric2;
324         char *fabric1_prefix;
325         char *fabric2_prefix;
326 };
327 
328 void diff_node_ports(ibnd_node_t * fabric1_node, ibnd_node_t * fabric2_node,
329 		       int *head_print, struct iter_diff_data *data)
330 {
331 	int i = 0;
332 
333 	for (i = 1; i <= fabric1_node->numports; i++) {
334 		ibnd_port_t *fabric1_port, *fabric2_port;
335 		int output_diff = 0;
336 
337 		fabric1_port = fabric1_node->ports[i];
338 		fabric2_port = fabric2_node->ports[i];
339 
340 		if (!fabric1_port && !fabric2_port)
341 			continue;
342 
343 		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION) {
344 			if ((fabric1_port && !fabric2_port)
345 			    || (!fabric1_port && fabric2_port)
346 			    || (fabric1_port->remoteport
347 				&& !fabric2_port->remoteport)
348 			    || (!fabric1_port->remoteport
349 				&& fabric2_port->remoteport)
350 			    || (fabric1_port->remoteport
351 				&& fabric2_port->remoteport
352 				&& fabric1_port->remoteport->guid !=
353 				fabric2_port->remoteport->guid))
354 				output_diff++;
355 		}
356 
357 		/* if either fabric1_port or fabric2_port NULL, should be
358 		 * handled by port connection diff code
359 		 */
360 		if (data->diff_flags & DIFF_FLAG_PORT_STATE
361 		    && fabric1_port
362 		    && fabric2_port) {
363 			int state1, state2;
364 
365 			state1 = mad_get_field(fabric1_port->info, 0,
366 					       IB_PORT_STATE_F);
367 			state2 = mad_get_field(fabric2_port->info, 0,
368 					       IB_PORT_STATE_F);
369 
370 			if (state1 != state2)
371 				output_diff++;
372 		}
373 
374 		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
375 		    && data->diff_flags & DIFF_FLAG_LID
376 		    && fabric1_port && fabric2_port
377 		    && fabric1_port->remoteport && fabric2_port->remoteport
378 		    && fabric1_port->remoteport->base_lid != fabric2_port->remoteport->base_lid)
379 			output_diff++;
380 
381 		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
382 		    && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
383 		    && fabric1_port && fabric2_port
384 		    && fabric1_port->remoteport && fabric2_port->remoteport
385 		    && memcmp(fabric1_port->remoteport->node->nodedesc,
386 			      fabric2_port->remoteport->node->nodedesc,
387 			      IB_SMP_DATA_SIZE))
388 			output_diff++;
389 
390 		if (output_diff && fabric1_port) {
391 			print_node_header(fabric1_node,
392 					    head_print,
393 					    NULL);
394 			print_port(fabric1_node,
395 				   fabric1_port,
396 				   data->fabric1_prefix);
397 		}
398 
399 		if (output_diff && fabric2_port) {
400 			print_node_header(fabric1_node,
401 					    head_print,
402 					    NULL);
403 			print_port(fabric2_node,
404 				   fabric2_port,
405 				   data->fabric2_prefix);
406 		}
407 	}
408 }
409 
410 void diff_node_iter(ibnd_node_t * fabric1_node, void *iter_user_data)
411 {
412 	struct iter_diff_data *data = iter_user_data;
413 	ibnd_node_t *fabric2_node;
414 	int head_print = 0;
415 
416 	DEBUG("DEBUG: fabric1_node %p\n", fabric1_node);
417 
418 	fabric2_node = ibnd_find_node_guid(data->fabric2, fabric1_node->guid);
419 	if (!fabric2_node)
420 		print_node(fabric1_node, data->fabric1_prefix);
421 	else if (data->diff_flags &
422 		 (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_PORT_STATE
423 		  | DIFF_FLAG_LID | DIFF_FLAG_NODE_DESCRIPTION)) {
424 
425 		if ((fabric1_node->type == IB_NODE_SWITCH
426 		     && data->diff_flags & DIFF_FLAG_LID
427 		     && fabric1_node->smalid != fabric2_node->smalid) ||
428 		    (data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
429 		     && memcmp(fabric1_node->nodedesc, fabric2_node->nodedesc,
430 			       IB_SMP_DATA_SIZE))) {
431 			print_node_header(fabric1_node,
432 					    NULL,
433 					    data->fabric1_prefix);
434 			print_node_header(fabric2_node,
435 					    NULL,
436 					    data->fabric2_prefix);
437 			head_print++;
438 		}
439 
440 		if (fabric1_node->numports != fabric2_node->numports) {
441 			print_node_header(fabric1_node,
442 					    &head_print,
443 					    NULL);
444 			printf("%snumports = %d\n", data->fabric1_prefix,
445 			       fabric1_node->numports);
446 			printf("%snumports = %d\n", data->fabric2_prefix,
447 			       fabric2_node->numports);
448 			return;
449 		}
450 
451 		diff_node_ports(fabric1_node, fabric2_node,
452 				  &head_print, data);
453 	}
454 }
455 
456 int diff_node(ibnd_node_t * node, ibnd_fabric_t * orig_fabric,
457 		ibnd_fabric_t * new_fabric)
458 {
459 	struct iter_diff_data iter_diff_data;
460 
461 	iter_diff_data.diff_flags = diffcheck_flags;
462 	iter_diff_data.fabric1 = orig_fabric;
463 	iter_diff_data.fabric2 = new_fabric;
464 	iter_diff_data.fabric1_prefix = "< ";
465 	iter_diff_data.fabric2_prefix = "> ";
466 	if (node)
467 		diff_node_iter(node, &iter_diff_data);
468 	else {
469 		if (only_flag)
470 			ibnd_iter_nodes_type(orig_fabric, diff_node_iter,
471 					     only_type, &iter_diff_data);
472 		else
473 			ibnd_iter_nodes(orig_fabric, diff_node_iter,
474 					&iter_diff_data);
475 	}
476 
477 	/* Do opposite diff to find existence of node types
478 	 * in new_fabric but not in orig_fabric.
479 	 *
480 	 * In this diff, we don't need to check port connections,
481 	 * port state, lids, or node descriptions since it has already
482 	 * been done (i.e. checks are only done when guid exists on both
483 	 * orig and new).
484 	 */
485 	iter_diff_data.diff_flags = diffcheck_flags & ~DIFF_FLAG_PORT_CONNECTION;
486 	iter_diff_data.diff_flags &= ~DIFF_FLAG_PORT_STATE;
487 	iter_diff_data.diff_flags &= ~DIFF_FLAG_LID;
488 	iter_diff_data.diff_flags &= ~DIFF_FLAG_NODE_DESCRIPTION;
489 	iter_diff_data.fabric1 = new_fabric;
490 	iter_diff_data.fabric2 = orig_fabric;
491 	iter_diff_data.fabric1_prefix = "> ";
492 	iter_diff_data.fabric2_prefix = "< ";
493 	if (node)
494 		diff_node_iter(node, &iter_diff_data);
495 	else {
496 		if (only_flag)
497 			ibnd_iter_nodes_type(new_fabric, diff_node_iter,
498 					     only_type, &iter_diff_data);
499 		else
500 			ibnd_iter_nodes(new_fabric, diff_node_iter,
501 					&iter_diff_data);
502 	}
503 
504 	return 0;
505 }
506 
507 static int process_opt(void *context, int ch, char *optarg)
508 {
509 	struct ibnd_config *cfg = context;
510 	char *p;
511 
512 	switch (ch) {
513 	case 1:
514 		node_name_map_file = strdup(optarg);
515 		break;
516 	case 2:
517 		load_cache_file = strdup(optarg);
518 		break;
519 	case 3:
520 		diff_cache_file = strdup(optarg);
521 		break;
522 	case 4:
523 		diffcheck_flags = 0;
524 		p = strtok(optarg, ",");
525 		while (p) {
526 			if (!strcasecmp(p, "port"))
527 				diffcheck_flags |= DIFF_FLAG_PORT_CONNECTION;
528 			else if (!strcasecmp(p, "state"))
529 				diffcheck_flags |= DIFF_FLAG_PORT_STATE;
530 			else if (!strcasecmp(p, "lid"))
531 				diffcheck_flags |= DIFF_FLAG_LID;
532 			else if (!strcasecmp(p, "nodedesc"))
533 				diffcheck_flags |= DIFF_FLAG_NODE_DESCRIPTION;
534 			else {
535 				fprintf(stderr, "invalid diff check key: %s\n",
536 					p);
537 				return -1;
538 			}
539 			p = strtok(NULL, ",");
540 		}
541 		break;
542 	case 5:
543 		filterdownports_cache_file = strdup(optarg);
544 		break;
545 	case 6:
546 		only_flag = 1;
547 		only_type = IB_NODE_SWITCH;
548 		break;
549 	case 7:
550 		only_flag = 1;
551 		only_type = IB_NODE_CA;
552 		break;
553 	case 'S':
554 	case 'G':
555 		guid_str = optarg;
556 		guid = (uint64_t) strtoull(guid_str, 0, 0);
557 		break;
558 	case 'D':
559 		dr_path = strdup(optarg);
560 		break;
561 	case 'a':
562 		all = 1;
563 		break;
564 	case 'n':
565 		cfg->max_hops = strtoul(optarg, NULL, 0);
566 		break;
567 	case 'd':
568 		down_links_only = 1;
569 		break;
570 	case 'l':
571 		line_mode = 1;
572 		break;
573 	case 'p':
574 		add_sw_settings = 1;
575 		break;
576 	case 'R':		/* nop */
577 		break;
578 	case 'o':
579 		cfg->max_smps = strtoul(optarg, NULL, 0);
580 		break;
581 	default:
582 		return -1;
583 	}
584 
585 	return 0;
586 }
587 
588 int main(int argc, char **argv)
589 {
590 	struct ibnd_config config = { 0 };
591 	int rc = 0;
592 	int resolved = -1;
593 	ibnd_fabric_t *fabric = NULL;
594 	ibnd_fabric_t *diff_fabric = NULL;
595 	struct ibmad_port *ibmad_port;
596 	ib_portid_t port_id = { 0 };
597 	uint8_t ni[IB_SMP_DATA_SIZE] = { 0 };
598 	int mgmt_classes[3] =
599 	    { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS };
600 
601 	const struct ibdiag_opt opts[] = {
602 		{"node-name-map", 1, 1, "<file>", "node name map file"},
603 		{"switch", 'S', 1, "<port_guid>",
604 		 "start partial scan at the port specified by <port_guid> (hex format)"},
605 		{"port-guid", 'G', 1, "<port_guid>",
606 		 "(same as -S)"},
607 		{"Direct", 'D', 1, "<dr_path>",
608 		 "start partial scan at the port specified by <dr_path>"},
609 		{"all", 'a', 0, NULL,
610 		 "print all nodes found in a partial fabric scan"},
611 		{"hops", 'n', 1, "<hops>",
612 		 "Number of hops to include away from specified node"},
613 		{"down", 'd', 0, NULL, "print only down links"},
614 		{"line", 'l', 0, NULL,
615 		 "(line mode) print all information for each link on a single line"},
616 		{"additional", 'p', 0, NULL,
617 		 "print additional port settings (PktLifeTime, HoqLife, VLStallCount)"},
618 		{"load-cache", 2, 1, "<file>",
619 		 "filename of ibnetdiscover cache to load"},
620 		{"diff", 3, 1, "<file>",
621 		 "filename of ibnetdiscover cache to diff"},
622 		{"diffcheck", 4, 1, "<key(s)>",
623 		 "specify checks to execute for --diff"},
624 		{"filterdownports", 5, 1, "<file>",
625 		 "filename of ibnetdiscover cache to filter downports"},
626 		{"outstanding_smps", 'o', 1, NULL,
627 		 "specify the number of outstanding SMP's which should be "
628 		 "issued during the scan"},
629 		{"switches-only", 6, 0, NULL,
630 		 "Output only switches"},
631 		{"cas-only", 7, 0, NULL,
632 		 "Output only CAs"},
633 		{0}
634 	};
635 	char usage_args[] = "";
636 
637 	ibdiag_process_opts(argc, argv, &config, "aDdGgKLlnpRS", opts,
638 			    process_opt, usage_args, NULL);
639 
640 	argc -= optind;
641 	argv += optind;
642 
643 	ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
644 	if (!ibmad_port) {
645 		fprintf(stderr, "Failed to open %s port %d\n", ibd_ca,
646 			ibd_ca_port);
647 		exit(1);
648 	}
649 
650 	smp_mkey_set(ibmad_port, ibd_mkey);
651 
652 	if (ibd_timeout) {
653 		mad_rpc_set_timeout(ibmad_port, ibd_timeout);
654 		config.timeout_ms = ibd_timeout;
655 	}
656 
657 	config.flags = ibd_ibnetdisc_flags;
658 	config.mkey = ibd_mkey;
659 
660 	node_name_map = open_node_name_map(node_name_map_file);
661 
662 	if (dr_path && load_cache_file) {
663 		mad_rpc_close_port(ibmad_port);
664 		fprintf(stderr, "Cannot specify cache and direct route path\n");
665 		exit(1);
666 	}
667 
668 	if (dr_path) {
669 		/* only scan part of the fabric */
670 		if ((resolved =
671 		     resolve_portid_str(ibd_ca, ibd_ca_port, &port_id, dr_path,
672 					IB_DEST_DRPATH, NULL, ibmad_port)) < 0)
673 			IBWARN("Failed to resolve %s; attempting full scan",
674 			       dr_path);
675 	} else if (guid_str) {
676 		if ((resolved =
677 		     resolve_portid_str(ibd_ca, ibd_ca_port, &port_id,
678 				        guid_str, IB_DEST_GUID, NULL,
679 					ibmad_port)) < 0)
680 			IBWARN("Failed to resolve %s; attempting full scan\n",
681 			       guid_str);
682 	}
683 
684 	if (!smp_query_via(ni, &port_id, IB_ATTR_NODE_INFO, 0,
685 				   ibd_timeout, ibmad_port)){
686 			mad_rpc_close_port(ibmad_port);
687 			fprintf(stderr,
688 				"Failed to get local Node Info\n");
689 			exit(1);
690 	}
691 	mad_rpc_close_port(ibmad_port);
692 
693 	if (diff_cache_file &&
694 	    !(diff_fabric = ibnd_load_fabric(diff_cache_file, 0)))
695 		IBEXIT("loading cached fabric for diff failed\n");
696 
697 	if (filterdownports_cache_file &&
698 	    !(filterdownports_fabric = ibnd_load_fabric(filterdownports_cache_file, 0)))
699 		IBEXIT("loading cached fabric for filterdownports failed\n");
700 
701 	if (load_cache_file) {
702 		if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) {
703 			fprintf(stderr, "loading cached fabric failed\n");
704 			exit(1);
705 		}
706 	} else {
707 		if (resolved >= 0) {
708 			if (!config.max_hops)
709 				config.max_hops = 1;
710 			if (!(fabric =
711 			    ibnd_discover_fabric(ibd_ca, ibd_ca_port, &port_id, &config)))
712 				IBWARN("Partial fabric scan failed;"
713 				       " attempting full scan\n");
714 		}
715 
716 		if (!fabric &&
717 		    !(fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config))) {
718 			fprintf(stderr, "discover failed\n");
719 			rc = 1;
720 			goto close_port;
721 		}
722 	}
723 
724 	if (!all && guid_str) {
725 		ibnd_port_t *p = ibnd_find_port_guid(fabric, guid);
726 		if (p && (!only_flag || p->node->type == only_type)) {
727 			ibnd_node_t *n = p->node;
728 			if (diff_fabric)
729 				diff_node(n, diff_fabric, fabric);
730 			else
731 				print_node(n, NULL);
732 		}
733 		else
734 			fprintf(stderr, "Failed to find port: %s\n", guid_str);
735 	} else if (!all && dr_path) {
736 		ibnd_port_t *p = NULL;
737 		mad_decode_field(ni, IB_NODE_PORT_GUID_F, &(guid));
738 
739 		p = ibnd_find_port_guid(fabric, guid);
740 		if (p && (!only_flag || p->node->type == only_type)) {
741 			ibnd_node_t *n = p->node;
742 			if (diff_fabric)
743 				diff_node(n, diff_fabric, fabric);
744 			else
745 				print_node(n, NULL);
746 		}
747 		else
748 			fprintf(stderr, "Failed to find port: %s\n", dr_path);
749 	} else {
750 		if (diff_fabric)
751 			diff_node(NULL, diff_fabric, fabric);
752 		else {
753 			if (only_flag)
754 				ibnd_iter_nodes_type(fabric, print_node,
755 						     only_type, NULL);
756 			else
757 				ibnd_iter_nodes(fabric, print_node, NULL);
758 		}
759 	}
760 
761 	ibnd_destroy_fabric(fabric);
762 	if (diff_fabric)
763 		ibnd_destroy_fabric(diff_fabric);
764 
765 close_port:
766 	close_node_name_map(node_name_map);
767 	exit(rc);
768 }
769