Blame src/ibnetdiscover.c

Packit db064d
/*
Packit db064d
 * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
Packit db064d
 * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
Packit db064d
 * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
Packit db064d
 * Copyright (c) 2010,2011 Mellanox Technologies LTD.  All rights reserved.
Packit db064d
 *
Packit db064d
 * This software is available to you under a choice of one of two
Packit db064d
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit db064d
 * General Public License (GPL) Version 2, available from the file
Packit db064d
 * COPYING in the main directory of this source tree, or the
Packit db064d
 * OpenIB.org BSD license below:
Packit db064d
 *
Packit db064d
 *     Redistribution and use in source and binary forms, with or
Packit db064d
 *     without modification, are permitted provided that the following
Packit db064d
 *     conditions are met:
Packit db064d
 *
Packit db064d
 *      - Redistributions of source code must retain the above
Packit db064d
 *        copyright notice, this list of conditions and the following
Packit db064d
 *        disclaimer.
Packit db064d
 *
Packit db064d
 *      - Redistributions in binary form must reproduce the above
Packit db064d
 *        copyright notice, this list of conditions and the following
Packit db064d
 *        disclaimer in the documentation and/or other materials
Packit db064d
 *        provided with the distribution.
Packit db064d
 *
Packit db064d
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit db064d
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit db064d
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit db064d
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit db064d
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit db064d
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit db064d
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit db064d
 * SOFTWARE.
Packit db064d
 *
Packit db064d
 */
Packit db064d
Packit db064d
#if HAVE_CONFIG_H
Packit db064d
#include <config.h>
Packit db064d
#endif				/* HAVE_CONFIG_H */
Packit db064d
Packit db064d
#define _GNU_SOURCE
Packit db064d
#include <stdio.h>
Packit db064d
#include <stdlib.h>
Packit db064d
#include <unistd.h>
Packit db064d
#include <time.h>
Packit db064d
#include <string.h>
Packit db064d
#include <inttypes.h>
Packit db064d
Packit db064d
#include <infiniband/umad.h>
Packit db064d
#include <infiniband/mad.h>
Packit db064d
#include <complib/cl_nodenamemap.h>
Packit db064d
#include <infiniband/ibnetdisc.h>
Packit db064d
Packit db064d
#include "ibdiag_common.h"
Packit db064d
Packit db064d
#define LIST_CA_NODE	 (1 << IB_NODE_CA)
Packit db064d
#define LIST_SWITCH_NODE (1 << IB_NODE_SWITCH)
Packit db064d
#define LIST_ROUTER_NODE (1 << IB_NODE_ROUTER)
Packit db064d
Packit db064d
#define DIFF_FLAG_SWITCH           0x01
Packit db064d
#define DIFF_FLAG_CA               0x02
Packit db064d
#define DIFF_FLAG_ROUTER           0x04
Packit db064d
#define DIFF_FLAG_PORT_CONNECTION  0x08
Packit db064d
#define DIFF_FLAG_LID              0x10
Packit db064d
#define DIFF_FLAG_NODE_DESCRIPTION 0x20
Packit db064d
Packit db064d
#define DIFF_FLAG_DEFAULT (DIFF_FLAG_SWITCH | DIFF_FLAG_CA | DIFF_FLAG_ROUTER \
Packit db064d
			   | DIFF_FLAG_PORT_CONNECTION)
Packit db064d
Packit db064d
static FILE *f;
Packit db064d
Packit db064d
static char *node_name_map_file = NULL;
Packit db064d
static nn_map_t *node_name_map = NULL;
Packit db064d
static char *cache_file = NULL;
Packit db064d
static char *load_cache_file = NULL;
Packit db064d
static char *diff_cache_file = NULL;
Packit db064d
static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT;
Packit db064d
Packit db064d
static int report_max_hops = 0;
Packit db064d
static int full_info;
Packit db064d
Packit db064d
/**
Packit db064d
 * Define our own conversion functions to maintain compatibility with the old
Packit db064d
 * ibnetdiscover which did not use the ibmad conversion functions.
Packit db064d
 */
Packit db064d
static const char *dump_linkspeed_compat(uint32_t speed)
Packit db064d
{
Packit db064d
	switch (speed) {
Packit db064d
	case 1:
Packit db064d
		return ("SDR");
Packit db064d
		break;
Packit db064d
	case 2:
Packit db064d
		return ("DDR");
Packit db064d
		break;
Packit db064d
	case 4:
Packit db064d
		return ("QDR");
Packit db064d
		break;
Packit db064d
	}
Packit db064d
	return ("???");
Packit db064d
}
Packit db064d
Packit db064d
static const char *dump_linkspeedext_compat(uint32_t espeed, uint32_t speed,
Packit db064d
					    uint32_t fdr10)
Packit db064d
{
Packit db064d
	switch (espeed) {
Packit db064d
	case 0:
Packit db064d
		if (fdr10 & FDR10)
Packit db064d
			return ("FDR10");
Packit db064d
		else
Packit db064d
			return dump_linkspeed_compat(speed);
Packit db064d
		break;
Packit db064d
	case 1:
Packit db064d
		return ("FDR");
Packit db064d
		break;
Packit db064d
	case 2:
Packit db064d
		return ("EDR");
Packit db064d
		break;
Packit db064d
	case 4:
Packit db064d
		return ("HDR");
Packit db064d
		break;
Packit db064d
	}
Packit db064d
	return ("???");
Packit db064d
}
Packit db064d
Packit db064d
static const char *dump_linkwidth_compat(uint32_t width)
Packit db064d
{
Packit db064d
	switch (width) {
Packit db064d
	case 1:
Packit db064d
		return ("1x");
Packit db064d
		break;
Packit db064d
	case 2:
Packit db064d
		return ("4x");
Packit db064d
		break;
Packit db064d
	case 4:
Packit db064d
		return ("8x");
Packit db064d
		break;
Packit db064d
	case 8:
Packit db064d
		return ("12x");
Packit db064d
		break;
Packit db064d
	case 16:
Packit db064d
		return ("2x");
Packit db064d
		break;
Packit db064d
	}
Packit db064d
	return ("??");
Packit db064d
}
Packit db064d
Packit db064d
static inline const char *ports_nt_str_compat(ibnd_node_t * node)
Packit db064d
{
Packit db064d
	switch (node->type) {
Packit db064d
	case IB_NODE_SWITCH:
Packit db064d
		return "SW";
Packit db064d
	case IB_NODE_CA:
Packit db064d
		return "CA";
Packit db064d
	case IB_NODE_ROUTER:
Packit db064d
		return "RT";
Packit db064d
	}
Packit db064d
	return "??";
Packit db064d
}
Packit db064d
Packit db064d
static char *node_name(ibnd_node_t * node)
Packit db064d
{
Packit db064d
	static char buf[256];
Packit db064d
Packit db064d
	switch (node->type) {
Packit db064d
	case IB_NODE_SWITCH:
Packit db064d
		sprintf(buf, "\"%s", "S");
Packit db064d
		break;
Packit db064d
	case IB_NODE_CA:
Packit db064d
		sprintf(buf, "\"%s", "H");
Packit db064d
		break;
Packit db064d
	case IB_NODE_ROUTER:
Packit db064d
		sprintf(buf, "\"%s", "R");
Packit db064d
		break;
Packit db064d
	default:
Packit db064d
		sprintf(buf, "\"%s", "?");
Packit db064d
		break;
Packit db064d
	}
Packit db064d
	sprintf(buf + 2, "-%016" PRIx64 "\"", node->guid);
Packit db064d
Packit db064d
	return buf;
Packit db064d
}
Packit db064d
Packit db064d
static void list_node(ibnd_node_t *node, void *user_data)
Packit db064d
{
Packit db064d
	const char *node_type;
Packit db064d
	char *nodename = remap_node_name(node_name_map, node->guid,
Packit db064d
					 node->nodedesc);
Packit db064d
Packit db064d
	switch (node->type) {
Packit db064d
	case IB_NODE_SWITCH:
Packit db064d
		node_type = "Switch";
Packit db064d
		break;
Packit db064d
	case IB_NODE_CA:
Packit db064d
		node_type = "Ca";
Packit db064d
		break;
Packit db064d
	case IB_NODE_ROUTER:
Packit db064d
		node_type = "Router";
Packit db064d
		break;
Packit db064d
	default:
Packit db064d
		node_type = "???";
Packit db064d
		break;
Packit db064d
	}
Packit db064d
	fprintf(f,
Packit db064d
		"%s\t : 0x%016" PRIx64
Packit db064d
		" ports %d devid 0x%x vendid 0x%x \"%s\"\n", node_type,
Packit db064d
		node->guid, node->numports, mad_get_field(node->info, 0,
Packit db064d
							  IB_NODE_DEVID_F),
Packit db064d
		mad_get_field(node->info, 0, IB_NODE_VENDORID_F), nodename);
Packit db064d
Packit db064d
	free(nodename);
Packit db064d
}
Packit db064d
Packit db064d
static void list_nodes(ibnd_fabric_t *fabric, int list)
Packit db064d
{
Packit db064d
	if (list & LIST_CA_NODE)
Packit db064d
		ibnd_iter_nodes_type(fabric, list_node, IB_NODE_CA, NULL);
Packit db064d
	if (list & LIST_SWITCH_NODE)
Packit db064d
		ibnd_iter_nodes_type(fabric, list_node, IB_NODE_SWITCH, NULL);
Packit db064d
	if (list & LIST_ROUTER_NODE)
Packit db064d
		ibnd_iter_nodes_type(fabric, list_node, IB_NODE_ROUTER, NULL);
Packit db064d
}
Packit db064d
Packit db064d
static void out_ids(ibnd_node_t *node, int group, char *chname,
Packit db064d
		    const char *out_prefix)
Packit db064d
{
Packit db064d
	uint64_t sysimgguid =
Packit db064d
	    mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
Packit db064d
Packit db064d
	fprintf(f, "\n%svendid=0x%x\n", out_prefix ? out_prefix : "",
Packit db064d
		mad_get_field(node->info, 0, IB_NODE_VENDORID_F));
Packit db064d
	fprintf(f, "%sdevid=0x%x\n", out_prefix ? out_prefix : "",
Packit db064d
		mad_get_field(node->info, 0, IB_NODE_DEVID_F));
Packit db064d
	if (sysimgguid)
Packit db064d
		fprintf(f, "%ssysimgguid=0x%" PRIx64,
Packit db064d
			out_prefix ? out_prefix : "", sysimgguid);
Packit db064d
	if (group && node->chassis && node->chassis->chassisnum) {
Packit db064d
		fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum);
Packit db064d
		if (chname)
Packit db064d
			fprintf(f, " (%s)", clean_nodedesc(chname));
Packit db064d
		if (ibnd_is_xsigo_tca(node->guid) && node->ports[1] &&
Packit db064d
		    node->ports[1]->remoteport)
Packit db064d
			fprintf(f, " slot %d",
Packit db064d
				node->ports[1]->remoteport->portnum);
Packit db064d
	}
Packit db064d
	if (sysimgguid ||
Packit db064d
	    (group && node->chassis && node->chassis->chassisnum))
Packit db064d
		fprintf(f, "\n");
Packit db064d
}
Packit db064d
Packit db064d
static uint64_t out_chassis(ibnd_fabric_t *fabric, unsigned char chassisnum)
Packit db064d
{
Packit db064d
	uint64_t guid;
Packit db064d
Packit db064d
	fprintf(f, "\nChassis %u", chassisnum);
Packit db064d
	guid = ibnd_get_chassis_guid(fabric, chassisnum);
Packit db064d
	if (guid)
Packit db064d
		fprintf(f, " (guid 0x%" PRIx64 ")", guid);
Packit db064d
	fprintf(f, "\n");
Packit db064d
	return guid;
Packit db064d
}
Packit db064d
Packit db064d
static void out_switch_detail(ibnd_node_t *node, const char *sw_prefix)
Packit db064d
{
Packit db064d
	char *nodename = NULL;
Packit db064d
Packit db064d
	nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
Packit db064d
Packit db064d
	fprintf(f, "%sSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d",
Packit db064d
		sw_prefix ? sw_prefix : "", node->numports, node_name(node),
Packit db064d
		nodename, node->smaenhsp0 ? "enhanced" : "base",
Packit db064d
		node->smalid, node->smalmc);
Packit db064d
Packit db064d
	free(nodename);
Packit db064d
}
Packit db064d
Packit db064d
static void out_switch(ibnd_node_t *node, int group, char *chname,
Packit db064d
		       const char *id_prefix, const char *sw_prefix)
Packit db064d
{
Packit db064d
	const char *str;
Packit db064d
	char str2[256];
Packit db064d
Packit db064d
	out_ids(node, group, chname, id_prefix);
Packit db064d
	fprintf(f, "%sswitchguid=0x%" PRIx64,
Packit db064d
		id_prefix ? id_prefix : "", node->guid);
Packit db064d
	fprintf(f, "(%" PRIx64 ")",
Packit db064d
		mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F));
Packit db064d
	if (group) {
Packit db064d
		fprintf(f, "\t# ");
Packit db064d
		str = ibnd_get_chassis_type(node);
Packit db064d
		if (str)
Packit db064d
			fprintf(f, "%s ", str);
Packit db064d
		str = ibnd_get_chassis_slot_str(node, str2, 256);
Packit db064d
		if (str)
Packit db064d
			fprintf(f, "%s", str);
Packit db064d
	}
Packit db064d
	fprintf(f, "\n");
Packit db064d
Packit db064d
	out_switch_detail(node, sw_prefix);
Packit db064d
	fprintf(f, "\n");
Packit db064d
}
Packit db064d
Packit db064d
static void out_ca_detail(ibnd_node_t *node, const char *ca_prefix)
Packit db064d
{
Packit db064d
	const char *node_type;
Packit db064d
Packit db064d
	switch (node->type) {
Packit db064d
	case IB_NODE_CA:
Packit db064d
		node_type = "Ca";
Packit db064d
		break;
Packit db064d
	case IB_NODE_ROUTER:
Packit db064d
		node_type = "Rt";
Packit db064d
		break;
Packit db064d
	default:
Packit db064d
		node_type = "???";
Packit db064d
		break;
Packit db064d
	}
Packit db064d
Packit db064d
	fprintf(f, "%s%s\t%d %s\t\t# \"%s\"", ca_prefix ? ca_prefix : "",
Packit db064d
		node_type, node->numports, node_name(node),
Packit db064d
		clean_nodedesc(node->nodedesc));
Packit db064d
}
Packit db064d
Packit db064d
static void out_ca(ibnd_node_t *node, int group, char *chname,
Packit db064d
		   const char *id_prefix, const char *ca_prefix)
Packit db064d
{
Packit db064d
	const char *node_type;
Packit db064d
Packit db064d
	out_ids(node, group, chname, id_prefix);
Packit db064d
	switch (node->type) {
Packit db064d
	case IB_NODE_CA:
Packit db064d
		node_type = "ca";
Packit db064d
		break;
Packit db064d
	case IB_NODE_ROUTER:
Packit db064d
		node_type = "rt";
Packit db064d
		break;
Packit db064d
	default:
Packit db064d
		node_type = "???";
Packit db064d
		break;
Packit db064d
	}
Packit db064d
Packit db064d
	fprintf(f, "%s%sguid=0x%" PRIx64 "\n",
Packit db064d
		id_prefix ? id_prefix : "", node_type, node->guid);
Packit db064d
	out_ca_detail(node, ca_prefix);
Packit db064d
	if (group && ibnd_is_xsigo_hca(node->guid))
Packit db064d
		fprintf(f, " (scp)");
Packit db064d
	fprintf(f, "\n");
Packit db064d
}
Packit db064d
Packit db064d
#define OUT_BUFFER_SIZE 16
Packit db064d
static char *out_ext_port(ibnd_port_t * port, int group)
Packit db064d
{
Packit db064d
	static char mapping[OUT_BUFFER_SIZE];
Packit db064d
Packit db064d
	if (group && port->ext_portnum != 0) {
Packit db064d
		snprintf(mapping, OUT_BUFFER_SIZE,
Packit db064d
			 "[ext %d]", port->ext_portnum);
Packit db064d
		return (mapping);
Packit db064d
	}
Packit db064d
Packit db064d
	return (NULL);
Packit db064d
}
Packit db064d
Packit db064d
static void out_switch_port(ibnd_port_t *port, int group,
Packit db064d
			    const char *out_prefix)
Packit db064d
{
Packit db064d
	char *ext_port_str = NULL;
Packit db064d
	char *rem_nodename = NULL;
Packit db064d
	uint32_t iwidth = mad_get_field(port->info, 0,
Packit db064d
					IB_PORT_LINK_WIDTH_ACTIVE_F);
Packit db064d
	uint32_t ispeed = mad_get_field(port->info, 0,
Packit db064d
					IB_PORT_LINK_SPEED_ACTIVE_F);
Packit db064d
	uint32_t vlcap = mad_get_field(port->info, 0,
Packit db064d
				       IB_PORT_VL_CAP_F);
Packit db064d
	uint32_t fdr10 = mad_get_field(port->ext_info, 0,
Packit db064d
				       IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F);
Packit db064d
	uint32_t cap_mask, espeed;
Packit db064d
Packit db064d
	DEBUG("port %p:%d remoteport %p\n", port, port->portnum,
Packit db064d
	      port->remoteport);
Packit db064d
	fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum);
Packit db064d
Packit db064d
	ext_port_str = out_ext_port(port, group);
Packit db064d
	if (ext_port_str)
Packit db064d
		fprintf(f, "%s", ext_port_str);
Packit db064d
Packit db064d
	rem_nodename = remap_node_name(node_name_map,
Packit db064d
				       port->remoteport->node->guid,
Packit db064d
				       port->remoteport->node->nodedesc);
Packit db064d
Packit db064d
	ext_port_str = out_ext_port(port->remoteport, group);
Packit db064d
Packit db064d
	if (!port->node->ports[0]) {
Packit db064d
		cap_mask = 0;
Packit db064d
		ispeed = 0;
Packit db064d
		espeed = 0;
Packit db064d
	} else {
Packit db064d
		cap_mask = mad_get_field(port->node->ports[0]->info, 0,
Packit db064d
					 IB_PORT_CAPMASK_F);
Packit db064d
		if (cap_mask & be32toh(IB_PORT_CAP_HAS_EXT_SPEEDS))
Packit db064d
			espeed = mad_get_field(port->info, 0,
Packit db064d
					       IB_PORT_LINK_SPEED_EXT_ACTIVE_F);
Packit db064d
		else
Packit db064d
			espeed = 0;
Packit db064d
	}
Packit db064d
	fprintf(f, "\t%s[%d]%s",
Packit db064d
		node_name(port->remoteport->node), port->remoteport->portnum,
Packit db064d
		ext_port_str ? ext_port_str : "");
Packit db064d
	if (port->remoteport->node->type != IB_NODE_SWITCH)
Packit db064d
		fprintf(f, "(%" PRIx64 ") ", port->remoteport->guid);
Packit db064d
	fprintf(f, "\t\t# \"%s\" lid %d %s%s",
Packit db064d
		rem_nodename,
Packit db064d
		port->remoteport->node->type == IB_NODE_SWITCH ?
Packit db064d
		port->remoteport->node->smalid :
Packit db064d
		port->remoteport->base_lid,
Packit db064d
		dump_linkwidth_compat(iwidth),
Packit db064d
		(ispeed != 4 && !espeed) ?
Packit db064d
			dump_linkspeed_compat(ispeed) :
Packit db064d
			dump_linkspeedext_compat(espeed, ispeed, fdr10));
Packit db064d
Packit db064d
	if (full_info)
Packit db064d
		fprintf(f, " s=%d w=%d v=%d", ispeed, iwidth, vlcap);
Packit db064d
Packit db064d
	if (ibnd_is_xsigo_tca(port->remoteport->guid))
Packit db064d
		fprintf(f, " slot %d", port->portnum);
Packit db064d
	else if (ibnd_is_xsigo_hca(port->remoteport->guid))
Packit db064d
		fprintf(f, " (scp)");
Packit db064d
	fprintf(f, "\n");
Packit db064d
Packit db064d
	free(rem_nodename);
Packit db064d
}
Packit db064d
Packit db064d
static void out_ca_port(ibnd_port_t *port, int group, const char *out_prefix)
Packit db064d
{
Packit db064d
	char *str = NULL;
Packit db064d
	char *rem_nodename = NULL;
Packit db064d
	uint32_t iwidth = mad_get_field(port->info, 0,
Packit db064d
					IB_PORT_LINK_WIDTH_ACTIVE_F);
Packit db064d
	uint32_t ispeed = mad_get_field(port->info, 0,
Packit db064d
					IB_PORT_LINK_SPEED_ACTIVE_F);
Packit db064d
	uint32_t vlcap = mad_get_field(port->info, 0,
Packit db064d
				       IB_PORT_VL_CAP_F);
Packit db064d
	uint32_t fdr10 = mad_get_field(port->ext_info, 0,
Packit db064d
				       IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F);
Packit db064d
	uint32_t cap_mask, espeed;
Packit db064d
Packit db064d
	fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum);
Packit db064d
	if (port->node->type != IB_NODE_SWITCH)
Packit db064d
		fprintf(f, "(%" PRIx64 ") ", port->guid);
Packit db064d
	fprintf(f, "\t%s[%d]",
Packit db064d
		node_name(port->remoteport->node), port->remoteport->portnum);
Packit db064d
	str = out_ext_port(port->remoteport, group);
Packit db064d
	if (str)
Packit db064d
		fprintf(f, "%s", str);
Packit db064d
	if (port->remoteport->node->type != IB_NODE_SWITCH)
Packit db064d
		fprintf(f, " (%" PRIx64 ") ", port->remoteport->guid);
Packit db064d
Packit db064d
	rem_nodename = remap_node_name(node_name_map,
Packit db064d
				       port->remoteport->node->guid,
Packit db064d
				       port->remoteport->node->nodedesc);
Packit db064d
Packit db064d
	cap_mask = mad_get_field(port->info, 0, IB_PORT_CAPMASK_F);
Packit db064d
	if (cap_mask & be32toh(IB_PORT_CAP_HAS_EXT_SPEEDS))
Packit db064d
		espeed = mad_get_field(port->info, 0,
Packit db064d
				       IB_PORT_LINK_SPEED_EXT_ACTIVE_F);
Packit db064d
	else
Packit db064d
		espeed = 0;
Packit db064d
Packit db064d
	fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s",
Packit db064d
		port->base_lid, port->lmc, rem_nodename,
Packit db064d
		port->remoteport->node->type == IB_NODE_SWITCH ?
Packit db064d
		port->remoteport->node->smalid :
Packit db064d
		port->remoteport->base_lid,
Packit db064d
		dump_linkwidth_compat(iwidth),
Packit db064d
		(ispeed != 4 && !espeed) ?
Packit db064d
			dump_linkspeed_compat(ispeed) :
Packit db064d
			dump_linkspeedext_compat(espeed, ispeed, fdr10));
Packit db064d
Packit db064d
	if (full_info)
Packit db064d
		fprintf(f, " s=%d w=%d v=%d", ispeed, iwidth, vlcap);
Packit db064d
	fprintf(f, "\n");
Packit db064d
Packit db064d
	free(rem_nodename);
Packit db064d
}
Packit db064d
Packit db064d
struct iter_user_data {
Packit db064d
	int group;
Packit db064d
	int skip_chassis_nodes;
Packit db064d
};
Packit db064d
Packit db064d
static void switch_iter_func(ibnd_node_t * node, void *iter_user_data)
Packit db064d
{
Packit db064d
	ibnd_port_t *port;
Packit db064d
	int p = 0;
Packit db064d
	struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
Packit db064d
Packit db064d
	DEBUG("SWITCH: node %p\n", node);
Packit db064d
Packit db064d
	/* skip chassis based switches if flagged */
Packit db064d
	if (data->skip_chassis_nodes && node->chassis
Packit db064d
	    && node->chassis->chassisnum)
Packit db064d
		return;
Packit db064d
Packit db064d
	out_switch(node, data->group, NULL, NULL, NULL);
Packit db064d
	for (p = 1; p <= node->numports; p++) {
Packit db064d
		port = node->ports[p];
Packit db064d
		if (port && port->remoteport)
Packit db064d
			out_switch_port(port, data->group, NULL);
Packit db064d
	}
Packit db064d
}
Packit db064d
Packit db064d
static void ca_iter_func(ibnd_node_t * node, void *iter_user_data)
Packit db064d
{
Packit db064d
	ibnd_port_t *port;
Packit db064d
	int p = 0;
Packit db064d
	struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
Packit db064d
Packit db064d
	DEBUG("CA: node %p\n", node);
Packit db064d
	/* Now, skip chassis based CAs */
Packit db064d
	if (data->group && node->chassis && node->chassis->chassisnum)
Packit db064d
		return;
Packit db064d
	out_ca(node, data->group, NULL, NULL, NULL);
Packit db064d
Packit db064d
	for (p = 1; p <= node->numports; p++) {
Packit db064d
		port = node->ports[p];
Packit db064d
		if (port && port->remoteport)
Packit db064d
			out_ca_port(port, data->group, NULL);
Packit db064d
	}
Packit db064d
}
Packit db064d
Packit db064d
static void router_iter_func(ibnd_node_t * node, void *iter_user_data)
Packit db064d
{
Packit db064d
	ibnd_port_t *port;
Packit db064d
	int p = 0;
Packit db064d
	struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
Packit db064d
Packit db064d
	DEBUG("RT: node %p\n", node);
Packit db064d
	/* Now, skip chassis based RTs */
Packit db064d
	if (data->group && node->chassis && node->chassis->chassisnum)
Packit db064d
		return;
Packit db064d
	out_ca(node, data->group, NULL, NULL, NULL);
Packit db064d
	for (p = 1; p <= node->numports; p++) {
Packit db064d
		port = node->ports[p];
Packit db064d
		if (port && port->remoteport)
Packit db064d
			out_ca_port(port, data->group, NULL);
Packit db064d
	}
Packit db064d
}
Packit db064d
Packit db064d
static int dump_topology(int group, ibnd_fabric_t *fabric)
Packit db064d
{
Packit db064d
	ibnd_node_t *node;
Packit db064d
	ibnd_port_t *port;
Packit db064d
	int i = 0, p = 0;
Packit db064d
	time_t t = time(NULL);
Packit db064d
	uint64_t chguid;
Packit db064d
	char *chname = NULL;
Packit db064d
	struct iter_user_data iter_user_data;
Packit db064d
Packit db064d
	fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t);;
Packit db064d
	if (report_max_hops)
Packit db064d
		fprintf(f, "# Reported max hops discovered: %u\n"
Packit db064d
			"# Total MADs used: %u\n",
Packit db064d
			fabric->maxhops_discovered, fabric->total_mads_used);
Packit db064d
	fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n",
Packit db064d
		fabric->from_node->guid,
Packit db064d
		mad_get_field64(fabric->from_node->info, 0,
Packit db064d
				IB_NODE_PORT_GUID_F));
Packit db064d
Packit db064d
	/* Make pass on switches */
Packit db064d
	if (group) {
Packit db064d
		ibnd_chassis_t *ch = NULL;
Packit db064d
Packit db064d
		/* Chassis based switches first */
Packit db064d
		for (ch = fabric->chassis; ch; ch = ch->next) {
Packit db064d
			int n = 0;
Packit db064d
Packit db064d
			if (!ch->chassisnum)
Packit db064d
				continue;
Packit db064d
			chguid = out_chassis(fabric, ch->chassisnum);
Packit db064d
			chname = NULL;
Packit db064d
			if (ibnd_is_xsigo_guid(chguid)) {
Packit db064d
				for (node = ch->nodes; node;
Packit db064d
				     node = node->next_chassis_node) {
Packit db064d
					if (ibnd_is_xsigo_hca(node->guid)) {
Packit db064d
						chname = node->nodedesc;
Packit db064d
						fprintf(f, "Hostname: %s\n",
Packit db064d
							clean_nodedesc
Packit db064d
							(node->nodedesc));
Packit db064d
					}
Packit db064d
				}
Packit db064d
			}
Packit db064d
Packit db064d
			fprintf(f, "\n# Spine Nodes");
Packit db064d
			for (n = 1; n <= SPINES_MAX_NUM; n++) {
Packit db064d
				if (ch->spinenode[n]) {
Packit db064d
					out_switch(ch->spinenode[n], group,
Packit db064d
						   chname, NULL, NULL);
Packit db064d
					for (p = 1;
Packit db064d
					     p <= ch->spinenode[n]->numports;
Packit db064d
					     p++) {
Packit db064d
						port =
Packit db064d
						    ch->spinenode[n]->ports[p];
Packit db064d
						if (port && port->remoteport)
Packit db064d
							out_switch_port(port,
Packit db064d
									group,
Packit db064d
									NULL);
Packit db064d
					}
Packit db064d
				}
Packit db064d
			}
Packit db064d
			fprintf(f, "\n# Line Nodes");
Packit db064d
			for (n = 1; n <= LINES_MAX_NUM; n++) {
Packit db064d
				if (ch->linenode[n]) {
Packit db064d
					out_switch(ch->linenode[n], group,
Packit db064d
						   chname, NULL, NULL);
Packit db064d
					for (p = 1;
Packit db064d
					     p <= ch->linenode[n]->numports;
Packit db064d
					     p++) {
Packit db064d
						port =
Packit db064d
						    ch->linenode[n]->ports[p];
Packit db064d
						if (port && port->remoteport)
Packit db064d
							out_switch_port(port,
Packit db064d
									group,
Packit db064d
									NULL);
Packit db064d
					}
Packit db064d
				}
Packit db064d
			}
Packit db064d
Packit db064d
			fprintf(f, "\n# Chassis Switches");
Packit db064d
			for (node = ch->nodes; node;
Packit db064d
			     node = node->next_chassis_node) {
Packit db064d
				if (node->type == IB_NODE_SWITCH) {
Packit db064d
					out_switch(node, group, chname, NULL,
Packit db064d
						   NULL);
Packit db064d
					for (p = 1; p <= node->numports; p++) {
Packit db064d
						port = node->ports[p];
Packit db064d
						if (port && port->remoteport)
Packit db064d
							out_switch_port(port,
Packit db064d
									group,
Packit db064d
									NULL);
Packit db064d
					}
Packit db064d
				}
Packit db064d
Packit db064d
			}
Packit db064d
Packit db064d
			fprintf(f, "\n# Chassis CAs");
Packit db064d
			for (node = ch->nodes; node;
Packit db064d
			     node = node->next_chassis_node) {
Packit db064d
				if (node->type == IB_NODE_CA) {
Packit db064d
					out_ca(node, group, chname, NULL, NULL);
Packit db064d
					for (p = 1; p <= node->numports; p++) {
Packit db064d
						port = node->ports[p];
Packit db064d
						if (port && port->remoteport)
Packit db064d
							out_ca_port(port, group,
Packit db064d
								    NULL);
Packit db064d
					}
Packit db064d
				}
Packit db064d
			}
Packit db064d
Packit db064d
		}
Packit db064d
Packit db064d
	} else {		/* !group */
Packit db064d
		iter_user_data.group = group;
Packit db064d
		iter_user_data.skip_chassis_nodes = 0;
Packit db064d
		ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH,
Packit db064d
				     &iter_user_data);
Packit db064d
	}
Packit db064d
Packit db064d
	chname = NULL;
Packit db064d
	if (group) {
Packit db064d
		iter_user_data.group = group;
Packit db064d
		iter_user_data.skip_chassis_nodes = 1;
Packit db064d
Packit db064d
		fprintf(f, "\nNon-Chassis Nodes\n");
Packit db064d
Packit db064d
		ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH,
Packit db064d
				     &iter_user_data);
Packit db064d
	}
Packit db064d
Packit db064d
	iter_user_data.group = group;
Packit db064d
	iter_user_data.skip_chassis_nodes = 0;
Packit db064d
	/* Make pass on CAs */
Packit db064d
	ibnd_iter_nodes_type(fabric, ca_iter_func, IB_NODE_CA, &iter_user_data);
Packit db064d
Packit db064d
	/* Make pass on routers */
Packit db064d
	ibnd_iter_nodes_type(fabric, router_iter_func, IB_NODE_ROUTER,
Packit db064d
			     &iter_user_data);
Packit db064d
Packit db064d
	return i;
Packit db064d
}
Packit db064d
Packit db064d
static void dump_ports_report(ibnd_node_t *node, void *user_data)
Packit db064d
{
Packit db064d
	int p = 0;
Packit db064d
	ibnd_port_t *port = NULL;
Packit db064d
	char *nodename = NULL;
Packit db064d
	char *rem_nodename = NULL;
Packit db064d
Packit db064d
	/* for each port */
Packit db064d
	for (p = node->numports, port = node->ports[p]; p > 0;
Packit db064d
	     port = node->ports[--p]) {
Packit db064d
		uint32_t iwidth, ispeed, fdr10, espeed, cap_mask;
Packit db064d
		uint8_t *info = NULL;
Packit db064d
		if (port == NULL)
Packit db064d
			continue;
Packit db064d
		iwidth =
Packit db064d
		    mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
Packit db064d
		ispeed =
Packit db064d
		    mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
Packit db064d
		if (port->node->type == IB_NODE_SWITCH) {
Packit db064d
			if (port->node->ports[0])
Packit db064d
				info = (uint8_t *)&port->node->ports[0]->info;
Packit db064d
		}
Packit db064d
		else
Packit db064d
			info = (uint8_t *)&port->info;
Packit db064d
		if (info) {
Packit db064d
			cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
Packit db064d
			if (cap_mask & be32toh(IB_PORT_CAP_HAS_EXT_SPEEDS))
Packit db064d
				espeed = mad_get_field(port->info, 0,
Packit db064d
						       IB_PORT_LINK_SPEED_EXT_ACTIVE_F);
Packit db064d
			else
Packit db064d
				espeed = 0;
Packit db064d
		} else {
Packit db064d
			ispeed = 0;
Packit db064d
			iwidth = 0;
Packit db064d
			espeed = 0;
Packit db064d
		}
Packit db064d
		fdr10 = mad_get_field(port->ext_info, 0,
Packit db064d
				      IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F);
Packit db064d
		nodename = remap_node_name(node_name_map,
Packit db064d
					   port->node->guid,
Packit db064d
					   port->node->nodedesc);
Packit db064d
		fprintf(stdout, "%2s %5d %2d 0x%016" PRIx64 " %s %s",
Packit db064d
			ports_nt_str_compat(node),
Packit db064d
			node->type ==
Packit db064d
			IB_NODE_SWITCH ? node->smalid : port->base_lid,
Packit db064d
			port->portnum, port->guid,
Packit db064d
			dump_linkwidth_compat(iwidth),
Packit db064d
			(ispeed != 4 && !espeed) ?
Packit db064d
				dump_linkspeed_compat(ispeed) :
Packit db064d
				dump_linkspeedext_compat(espeed, ispeed, fdr10));
Packit db064d
		if (port->remoteport) {
Packit db064d
			rem_nodename = remap_node_name(node_name_map,
Packit db064d
					      port->remoteport->node->guid,
Packit db064d
					      port->remoteport->node->nodedesc);
Packit db064d
			fprintf(stdout,
Packit db064d
				" - %2s %5d %2d 0x%016" PRIx64
Packit db064d
				" ( '%s' - '%s' )\n",
Packit db064d
				ports_nt_str_compat(port->remoteport->node),
Packit db064d
				port->remoteport->node->type == IB_NODE_SWITCH ?
Packit db064d
				port->remoteport->node->smalid :
Packit db064d
				port->remoteport->base_lid,
Packit db064d
				port->remoteport->portnum,
Packit db064d
				port->remoteport->guid, nodename, rem_nodename);
Packit db064d
			free(rem_nodename);
Packit db064d
		} else
Packit db064d
			fprintf(stdout, "%36s'%s'\n", "", nodename);
Packit db064d
Packit db064d
		free(nodename);
Packit db064d
	}
Packit db064d
}
Packit db064d
Packit db064d
struct iter_diff_data {
Packit db064d
	uint32_t diff_flags;
Packit db064d
	ibnd_fabric_t *fabric1;
Packit db064d
	ibnd_fabric_t *fabric2;
Packit db064d
	const char *fabric1_prefix;
Packit db064d
	const char *fabric2_prefix;
Packit db064d
	void (*out_header)(ibnd_node_t *, int, char *, const char *,
Packit db064d
			   const char *);
Packit db064d
	void (*out_header_detail)(ibnd_node_t *, const char *);
Packit db064d
	void (*out_port)(ibnd_port_t *, int, const char *);
Packit db064d
};
Packit db064d
Packit db064d
static void diff_iter_out_header(ibnd_node_t * node,
Packit db064d
				 struct iter_diff_data *data,
Packit db064d
				 int *out_header_flag)
Packit db064d
{
Packit db064d
	if (!(*out_header_flag)) {
Packit db064d
		(*data->out_header) (node, 0, NULL, NULL, NULL);
Packit db064d
		(*out_header_flag)++;
Packit db064d
	}
Packit db064d
}
Packit db064d
Packit db064d
static void diff_ports(ibnd_node_t * fabric1_node, ibnd_node_t * fabric2_node,
Packit db064d
		       int *out_header_flag, struct iter_diff_data *data)
Packit db064d
{
Packit db064d
	ibnd_port_t *fabric1_port;
Packit db064d
	ibnd_port_t *fabric2_port;
Packit db064d
	int p;
Packit db064d
Packit db064d
	for (p = 1; p <= fabric1_node->numports; p++) {
Packit db064d
		int fabric1_out = 0, fabric2_out = 0;
Packit db064d
Packit db064d
		fabric1_port = fabric1_node->ports[p];
Packit db064d
		fabric2_port = fabric2_node->ports[p];
Packit db064d
Packit db064d
		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION) {
Packit db064d
			if ((fabric1_port && !fabric2_port)
Packit db064d
			    || ((fabric1_port && fabric2_port)
Packit db064d
				&& (fabric1_port->remoteport
Packit db064d
				    && !fabric2_port->remoteport)))
Packit db064d
				fabric1_out++;
Packit db064d
			else if ((!fabric1_port && fabric2_port)
Packit db064d
				 || ((fabric1_port && fabric2_port)
Packit db064d
				     && (!fabric1_port->remoteport
Packit db064d
					 && fabric2_port->remoteport)))
Packit db064d
				fabric2_out++;
Packit db064d
			else if ((fabric1_port && fabric2_port)
Packit db064d
				 && ((fabric1_port->guid != fabric2_port->guid)
Packit db064d
				     ||
Packit db064d
				     ((fabric1_port->remoteport
Packit db064d
				       && fabric2_port->remoteport)
Packit db064d
				      && (fabric1_port->remoteport->guid !=
Packit db064d
					  fabric2_port->remoteport->guid)))) {
Packit db064d
				fabric1_out++;
Packit db064d
				fabric2_out++;
Packit db064d
			}
Packit db064d
		}
Packit db064d
Packit db064d
		if ((data->diff_flags & DIFF_FLAG_LID)
Packit db064d
		    && fabric1_port && fabric2_port
Packit db064d
		    && fabric1_port->base_lid != fabric2_port->base_lid) {
Packit db064d
			fabric1_out++;
Packit db064d
			fabric2_out++;
Packit db064d
		}
Packit db064d
Packit db064d
		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
Packit db064d
		    && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
Packit db064d
		    && fabric1_port && fabric2_port
Packit db064d
		    && fabric1_port->remoteport && fabric2_port->remoteport
Packit db064d
		    && memcmp(fabric1_port->remoteport->node->nodedesc,
Packit db064d
			      fabric2_port->remoteport->node->nodedesc,
Packit db064d
			      IB_SMP_DATA_SIZE)) {
Packit db064d
			fabric1_out++;
Packit db064d
			fabric2_out++;
Packit db064d
		}
Packit db064d
Packit db064d
		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
Packit db064d
		    && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
Packit db064d
		    && fabric1_port && fabric2_port
Packit db064d
		    && fabric1_port->remoteport && fabric2_port->remoteport
Packit db064d
		    && memcmp(fabric1_port->remoteport->node->nodedesc,
Packit db064d
			      fabric2_port->remoteport->node->nodedesc,
Packit db064d
			      IB_SMP_DATA_SIZE)) {
Packit db064d
			fabric1_out++;
Packit db064d
			fabric2_out++;
Packit db064d
		}
Packit db064d
Packit db064d
		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
Packit db064d
		    && data->diff_flags & DIFF_FLAG_LID
Packit db064d
		    && fabric1_port && fabric2_port
Packit db064d
		    && fabric1_port->remoteport && fabric2_port->remoteport
Packit db064d
		    && fabric1_port->remoteport->base_lid != fabric2_port->remoteport->base_lid) {
Packit db064d
			fabric1_out++;
Packit db064d
			fabric2_out++;
Packit db064d
		}
Packit db064d
Packit db064d
		if (fabric1_out) {
Packit db064d
			diff_iter_out_header(fabric1_node, data,
Packit db064d
					     out_header_flag);
Packit db064d
			(*data->out_port) (fabric1_port, 0,
Packit db064d
					   data->fabric1_prefix);
Packit db064d
		}
Packit db064d
		if (fabric2_out) {
Packit db064d
			diff_iter_out_header(fabric1_node, data,
Packit db064d
					     out_header_flag);
Packit db064d
			(*data->out_port) (fabric2_port, 0,
Packit db064d
					   data->fabric2_prefix);
Packit db064d
		}
Packit db064d
	}
Packit db064d
}
Packit db064d
Packit db064d
static void diff_iter_func(ibnd_node_t * fabric1_node, void *iter_user_data)
Packit db064d
{
Packit db064d
	struct iter_diff_data *data = iter_user_data;
Packit db064d
	ibnd_node_t *fabric2_node;
Packit db064d
	ibnd_port_t *fabric1_port;
Packit db064d
	int p;
Packit db064d
Packit db064d
	DEBUG("DEBUG: fabric1_node %p\n", fabric1_node);
Packit db064d
Packit db064d
	fabric2_node = ibnd_find_node_guid(data->fabric2, fabric1_node->guid);
Packit db064d
	if (!fabric2_node) {
Packit db064d
		(*data->out_header) (fabric1_node, 0, NULL,
Packit db064d
				     data->fabric1_prefix,
Packit db064d
				     data->fabric1_prefix);
Packit db064d
		for (p = 1; p <= fabric1_node->numports; p++) {
Packit db064d
			fabric1_port = fabric1_node->ports[p];
Packit db064d
			if (fabric1_port && fabric1_port->remoteport)
Packit db064d
				(*data->out_port) (fabric1_port, 0,
Packit db064d
						   data->fabric1_prefix);
Packit db064d
		}
Packit db064d
	} else if (data->diff_flags &
Packit db064d
		   (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_LID
Packit db064d
		    | DIFF_FLAG_NODE_DESCRIPTION)) {
Packit db064d
		int out_header_flag = 0;
Packit db064d
Packit db064d
		if ((data->diff_flags & DIFF_FLAG_LID
Packit db064d
		     && fabric1_node->smalid != fabric2_node->smalid) ||
Packit db064d
		    (data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
Packit db064d
		     && memcmp(fabric1_node->nodedesc, fabric2_node->nodedesc,
Packit db064d
			       IB_SMP_DATA_SIZE))) {
Packit db064d
			(*data->out_header) (fabric1_node, 0, NULL, NULL,
Packit db064d
					     data->fabric1_prefix);
Packit db064d
			(*data->out_header_detail) (fabric2_node,
Packit db064d
						    data->fabric2_prefix);
Packit db064d
			fprintf(f, "\n");
Packit db064d
			out_header_flag++;
Packit db064d
		}
Packit db064d
Packit db064d
		if (fabric1_node->numports != fabric2_node->numports) {
Packit db064d
			diff_iter_out_header(fabric1_node, data,
Packit db064d
					     &out_header_flag);
Packit db064d
			fprintf(f, "%snumports = %d\n", data->fabric1_prefix,
Packit db064d
				fabric1_node->numports);
Packit db064d
			fprintf(f, "%snumports = %d\n", data->fabric2_prefix,
Packit db064d
				fabric2_node->numports);
Packit db064d
			return;
Packit db064d
		}
Packit db064d
Packit db064d
		if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
Packit db064d
		    || data->diff_flags & DIFF_FLAG_LID)
Packit db064d
			diff_ports(fabric1_node, fabric2_node, &out_header_flag,
Packit db064d
				   data);
Packit db064d
	}
Packit db064d
}
Packit db064d
Packit db064d
static int diff_common(ibnd_fabric_t *orig_fabric, ibnd_fabric_t *new_fabric,
Packit db064d
		       int node_type, uint32_t diff_flags,
Packit db064d
		       void (*out_header)(ibnd_node_t *, int, char *,
Packit db064d
					  const char *, const char *),
Packit db064d
		       void (*out_header_detail)(ibnd_node_t *, const char *),
Packit db064d
		       void (*out_port)(ibnd_port_t *, int, const char *))
Packit db064d
{
Packit db064d
	struct iter_diff_data iter_diff_data;
Packit db064d
Packit db064d
	iter_diff_data.diff_flags = diff_flags;
Packit db064d
	iter_diff_data.fabric1 = orig_fabric;
Packit db064d
	iter_diff_data.fabric2 = new_fabric;
Packit db064d
	iter_diff_data.fabric1_prefix = "< ";
Packit db064d
	iter_diff_data.fabric2_prefix = "> ";
Packit db064d
	iter_diff_data.out_header = out_header;
Packit db064d
	iter_diff_data.out_header_detail = out_header_detail;
Packit db064d
	iter_diff_data.out_port = out_port;
Packit db064d
	ibnd_iter_nodes_type(orig_fabric, diff_iter_func, node_type,
Packit db064d
			     &iter_diff_data);
Packit db064d
Packit db064d
	/* Do opposite diff to find existence of node types
Packit db064d
	 * in new_fabric but not in orig_fabric.
Packit db064d
	 *
Packit db064d
	 * In this diff, we don't need to check port connections,
Packit db064d
	 * lids, or node descriptions since it has already been
Packit db064d
	 * done (i.e. checks are only done when guid exists on both
Packit db064d
	 * orig and new).
Packit db064d
	 */
Packit db064d
	iter_diff_data.diff_flags = diff_flags & ~DIFF_FLAG_PORT_CONNECTION;
Packit db064d
	iter_diff_data.diff_flags &= ~DIFF_FLAG_LID;
Packit db064d
	iter_diff_data.diff_flags &= ~DIFF_FLAG_NODE_DESCRIPTION;
Packit db064d
	iter_diff_data.fabric1 = new_fabric;
Packit db064d
	iter_diff_data.fabric2 = orig_fabric;
Packit db064d
	iter_diff_data.fabric1_prefix = "> ";
Packit db064d
	iter_diff_data.fabric2_prefix = "< ";
Packit db064d
	iter_diff_data.out_header = out_header;
Packit db064d
	iter_diff_data.out_header_detail = out_header_detail;
Packit db064d
	iter_diff_data.out_port = out_port;
Packit db064d
	ibnd_iter_nodes_type(new_fabric, diff_iter_func, node_type,
Packit db064d
			     &iter_diff_data);
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
static int diff(ibnd_fabric_t *orig_fabric, ibnd_fabric_t *new_fabric)
Packit db064d
{
Packit db064d
	if (diffcheck_flags & DIFF_FLAG_SWITCH)
Packit db064d
		diff_common(orig_fabric, new_fabric, IB_NODE_SWITCH,
Packit db064d
			    diffcheck_flags, out_switch, out_switch_detail,
Packit db064d
			    out_switch_port);
Packit db064d
Packit db064d
	if (diffcheck_flags & DIFF_FLAG_CA)
Packit db064d
		diff_common(orig_fabric, new_fabric, IB_NODE_CA,
Packit db064d
			    diffcheck_flags, out_ca, out_ca_detail,
Packit db064d
			    out_ca_port);
Packit db064d
Packit db064d
	if (diffcheck_flags & DIFF_FLAG_ROUTER)
Packit db064d
		diff_common(orig_fabric, new_fabric, IB_NODE_ROUTER,
Packit db064d
			    diffcheck_flags, out_ca, out_ca_detail,
Packit db064d
			    out_ca_port);
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
static int list, group, ports_report;
Packit db064d
Packit db064d
static int process_opt(void *context, int ch)
Packit db064d
{
Packit db064d
	struct ibnd_config *cfg = context;
Packit db064d
	char *p;
Packit db064d
Packit db064d
	switch (ch) {
Packit db064d
	case 1:
Packit db064d
		node_name_map_file = strdup(optarg);
Packit db064d
		if (node_name_map_file == NULL)
Packit db064d
			IBEXIT("out of memory, strdup for node_name_map_file name failed");
Packit db064d
		break;
Packit db064d
	case 2:
Packit db064d
		cache_file = strdup(optarg);
Packit db064d
		break;
Packit db064d
	case 3:
Packit db064d
		load_cache_file = strdup(optarg);
Packit db064d
		break;
Packit db064d
	case 4:
Packit db064d
		diff_cache_file = strdup(optarg);
Packit db064d
		break;
Packit db064d
	case 5:
Packit db064d
		diffcheck_flags = 0;
Packit db064d
		p = strtok(optarg, ",");
Packit db064d
		while (p) {
Packit db064d
			if (!strcasecmp(p, "sw"))
Packit db064d
				diffcheck_flags |= DIFF_FLAG_SWITCH;
Packit db064d
			else if (!strcasecmp(p, "ca"))
Packit db064d
				diffcheck_flags |= DIFF_FLAG_CA;
Packit db064d
			else if (!strcasecmp(p, "router"))
Packit db064d
				diffcheck_flags |= DIFF_FLAG_ROUTER;
Packit db064d
			else if (!strcasecmp(p, "port"))
Packit db064d
				diffcheck_flags |= DIFF_FLAG_PORT_CONNECTION;
Packit db064d
			else if (!strcasecmp(p, "lid"))
Packit db064d
				diffcheck_flags |= DIFF_FLAG_LID;
Packit db064d
			else if (!strcasecmp(p, "nodedesc"))
Packit db064d
				diffcheck_flags |= DIFF_FLAG_NODE_DESCRIPTION;
Packit db064d
			else {
Packit db064d
				fprintf(stderr, "invalid diff check key: %s\n",
Packit db064d
					p);
Packit db064d
				return -1;
Packit db064d
			}
Packit db064d
			p = strtok(NULL, ",");
Packit db064d
		}
Packit db064d
		break;
Packit db064d
	case 's':
Packit db064d
		cfg->show_progress = 1;
Packit db064d
		break;
Packit db064d
	case 'f':
Packit db064d
		full_info = 1;
Packit db064d
		break;
Packit db064d
	case 'l':
Packit db064d
		list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
Packit db064d
		break;
Packit db064d
	case 'g':
Packit db064d
		group = 1;
Packit db064d
		break;
Packit db064d
	case 'S':
Packit db064d
		list = LIST_SWITCH_NODE;
Packit db064d
		break;
Packit db064d
	case 'H':
Packit db064d
		list = LIST_CA_NODE;
Packit db064d
		break;
Packit db064d
	case 'R':
Packit db064d
		list = LIST_ROUTER_NODE;
Packit db064d
		break;
Packit db064d
	case 'p':
Packit db064d
		ports_report = 1;
Packit db064d
		break;
Packit db064d
	case 'm':
Packit db064d
		report_max_hops = 1;
Packit db064d
		break;
Packit db064d
	case 'o':
Packit db064d
		cfg->max_smps = strtoul(optarg, NULL, 0);
Packit db064d
		break;
Packit db064d
	default:
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
int main(int argc, char **argv)
Packit db064d
{
Packit db064d
	struct ibnd_config config = { 0 };
Packit db064d
	ibnd_fabric_t *fabric = NULL;
Packit db064d
	ibnd_fabric_t *diff_fabric = NULL;
Packit db064d
Packit db064d
	const struct ibdiag_opt opts[] = {
Packit db064d
		{"full", 'f', 0, NULL, "show full information (ports' speed and width, vlcap)"},
Packit db064d
		{"show", 's', 0, NULL, "show more information"},
Packit db064d
		{"list", 'l', 0, NULL, "list of connected nodes"},
Packit db064d
		{"grouping", 'g', 0, NULL, "show grouping"},
Packit db064d
		{"Hca_list", 'H', 0, NULL, "list of connected CAs"},
Packit db064d
		{"Switch_list", 'S', 0, NULL, "list of connected switches"},
Packit db064d
		{"Router_list", 'R', 0, NULL, "list of connected routers"},
Packit db064d
		{"node-name-map", 1, 1, "<file>", "node name map file"},
Packit db064d
		{"cache", 2, 1, "<file>",
Packit db064d
		 "filename to cache ibnetdiscover data to"},
Packit db064d
		{"load-cache", 3, 1, "<file>",
Packit db064d
		 "filename of ibnetdiscover cache to load"},
Packit db064d
		{"diff", 4, 1, "<file>",
Packit db064d
		 "filename of ibnetdiscover cache to diff"},
Packit db064d
		{"diffcheck", 5, 1, "<key(s)>",
Packit db064d
		 "specify checks to execute for --diff"},
Packit db064d
		{"ports", 'p', 0, NULL, "obtain a ports report"},
Packit db064d
		{"max_hops", 'm', 0, NULL,
Packit db064d
		 "report max hops discovered by the library"},
Packit db064d
		{"outstanding_smps", 'o', 1, NULL,
Packit db064d
		 "specify the number of outstanding SMP's which should be "
Packit db064d
		 "issued during the scan"},
Packit db064d
		{}
Packit db064d
	};
Packit db064d
	char usage_args[] = "[topology-file]";
Packit db064d
Packit db064d
	ibdiag_process_opts(argc, argv, &config, "DGKLs", opts, process_opt,
Packit db064d
			    usage_args, NULL);
Packit db064d
Packit db064d
	f = stdout;
Packit db064d
Packit db064d
	argc -= optind;
Packit db064d
	argv += optind;
Packit db064d
Packit db064d
	if (ibd_timeout)
Packit db064d
		config.timeout_ms = ibd_timeout;
Packit db064d
Packit db064d
	config.flags = ibd_ibnetdisc_flags;
Packit db064d
Packit db064d
	if (argc && !(f = fopen(argv[0], "w")))
Packit db064d
		IBEXIT("can't open file %s for writing", argv[0]);
Packit db064d
Packit db064d
	config.mkey = ibd_mkey;
Packit db064d
Packit db064d
	node_name_map = open_node_name_map(node_name_map_file);
Packit db064d
Packit db064d
	if (diff_cache_file &&
Packit db064d
	    !(diff_fabric = ibnd_load_fabric(diff_cache_file, 0)))
Packit db064d
		IBEXIT("loading cached fabric for diff failed\n");
Packit db064d
Packit db064d
	if (load_cache_file) {
Packit db064d
		if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL)
Packit db064d
			IBEXIT("loading cached fabric failed\n");
Packit db064d
	} else {
Packit db064d
		if ((fabric =
Packit db064d
		     ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config)) == NULL)
Packit db064d
			IBEXIT("discover failed\n");
Packit db064d
	}
Packit db064d
Packit db064d
	if (ports_report)
Packit db064d
		ibnd_iter_nodes(fabric, dump_ports_report, NULL);
Packit db064d
	else if (list)
Packit db064d
		list_nodes(fabric, list);
Packit db064d
	else if (diff_fabric)
Packit db064d
		diff(diff_fabric, fabric);
Packit db064d
	else
Packit db064d
		dump_topology(group, fabric);
Packit db064d
Packit db064d
	if (cache_file)
Packit db064d
		if (ibnd_cache_fabric(fabric, cache_file, 0) < 0)
Packit db064d
			IBEXIT("caching ibnetdiscover data failed\n");
Packit db064d
Packit db064d
	ibnd_destroy_fabric(fabric);
Packit db064d
	if (diff_fabric)
Packit db064d
		ibnd_destroy_fabric(diff_fabric);
Packit db064d
	close_node_name_map(node_name_map);
Packit db064d
	exit(0);
Packit db064d
}