[ofa-general] [PATCH v3 1/3] Create a new library libibnetdisc

Ira Weiny weiny2 at llnl.gov
Fri Apr 3 15:42:51 PDT 2009


>From e1c2c10678b0d1d90f7eb31eb1c1441b5ee43311 Mon Sep 17 00:00:00 2001
From: Ira Weiny <weiny2 at llnl.gov>
Date: Fri, 3 Apr 2009 15:28:08 -0700
Subject: [PATCH] Create a new library libibnetdisc

This encompasses the functionality of ibnetdiscover in a C library.  It returns
a single "ibnd_fabric_t" object which represents the data found during the
scan.  The NodeInfo, PortInfo, and SwitchInfo are preserved from the queries
made on the fabric to be used by the calling function as they see fit.

This greatly benefits some diags like iblinkinfo.pl.  This diag in particular
was re-written using this library in C and has shown an 85% speed up on a ~1000
node cluster.

Previous iblinkinfo.pl
   real    3m35.876s
   user    0m13.210s
   sys     1m1.046s

New iblinkinfotest
   real    0m32.869s
   user    0m0.067s
   sys     0m0.140s

Signed-off-by: Ira Weiny <weiny2 at llnl.gov>
---
 infiniband-diags/Makefile.am                       |    1 +
 infiniband-diags/configure.in                      |   18 +-
 infiniband-diags/libibnetdisc/Makefile.am          |   47 ++
 .../libibnetdisc/include/infiniband/ibnetdisc.h    |  188 +++++
 infiniband-diags/libibnetdisc/libibnetdisc.ver     |    9 +
 infiniband-diags/libibnetdisc/man/ibnd_debug.3     |    2 +
 .../libibnetdisc/man/ibnd_destroy_fabric.3         |    2 +
 .../libibnetdisc/man/ibnd_discover_fabric.3        |   49 ++
 .../libibnetdisc/man/ibnd_find_node_dr.3           |    2 +
 .../libibnetdisc/man/ibnd_find_node_guid.3         |   25 +
 .../libibnetdisc/man/ibnd_iter_nodes.3             |   24 +
 .../libibnetdisc/man/ibnd_iter_nodes_type.3        |    2 +
 .../libibnetdisc/man/ibnd_show_progress.3          |    2 +
 .../libibnetdisc/man/ibnd_update_node.3            |   21 +
 infiniband-diags/libibnetdisc/src/chassis.c        |  830 ++++++++++++++++++++
 infiniband-diags/libibnetdisc/src/chassis.h        |   85 ++
 infiniband-diags/libibnetdisc/src/ibnetdisc.c      |  700 +++++++++++++++++
 infiniband-diags/libibnetdisc/src/internal.h       |   95 +++
 infiniband-diags/libibnetdisc/src/libibnetdisc.map |   27 +
 infiniband-diags/libibnetdisc/test/testleaks.c     |  179 +++++
 20 files changed, 2304 insertions(+), 4 deletions(-)
 create mode 100644 infiniband-diags/libibnetdisc/Makefile.am
 create mode 100644 infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
 create mode 100644 infiniband-diags/libibnetdisc/libibnetdisc.ver
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_debug.3
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_destroy_fabric.3
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_discover_fabric.3
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_find_node_dr.3
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_find_node_guid.3
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_iter_nodes.3
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_iter_nodes_type.3
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_show_progress.3
 create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_update_node.3
 create mode 100644 infiniband-diags/libibnetdisc/src/chassis.c
 create mode 100644 infiniband-diags/libibnetdisc/src/chassis.h
 create mode 100644 infiniband-diags/libibnetdisc/src/ibnetdisc.c
 create mode 100644 infiniband-diags/libibnetdisc/src/internal.h
 create mode 100644 infiniband-diags/libibnetdisc/src/libibnetdisc.map
 create mode 100644 infiniband-diags/libibnetdisc/test/testleaks.c

diff --git a/infiniband-diags/Makefile.am b/infiniband-diags/Makefile.am
index f9cc5bd..7b8523a 100644
--- a/infiniband-diags/Makefile.am
+++ b/infiniband-diags/Makefile.am
@@ -1,3 +1,4 @@
+SUBDIRS = libibnetdisc
 
 INCLUDES = -I$(top_builddir)/include/ -I$(srcdir)/include -I$(includedir) -I$(includedir)/infiniband
 
diff --git a/infiniband-diags/configure.in b/infiniband-diags/configure.in
index 4495a53..2b73167 100644
--- a/infiniband-diags/configure.in
+++ b/infiniband-diags/configure.in
@@ -44,7 +44,7 @@ fi
 
 dnl Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS([stdlib.h string.h unistd.h fcntl.h inttypes.h netinet/in.h sys/ioctl.h syslog.h])
+AC_CHECK_HEADERS([stdlib.h string.h unistd.h fcntl.h inttypes.h netinet/in.h sys/ioctl.h])
 if test "$disable_libcheck" != "yes"
 then
 AC_CHECK_HEADER(infiniband/umad.h, [],
@@ -58,7 +58,7 @@ fi
 dnl Checks for library functions
 AC_FUNC_ERROR_AT_LINE
 AC_FUNC_VPRINTF
-AC_CHECK_FUNCS([strchr strrchr strtol strtoul memset])
+AC_CHECK_FUNCS([strchr strrchr strtol strtoul memset strtoull])
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -66,7 +66,7 @@ AC_C_CONST
 dnl Check if we should include test utilities
 AC_MSG_CHECKING(for --enable-test-utils)
 AC_ARG_ENABLE(test-utils,
-[  --enable-test-utils build additional test utilities],
+[  --enable-test-utils build additional test utilities (default=no)],
 [case "${enableval}" in
   yes) tutils=yes ;;
   no)  tutils=no ;;
@@ -136,6 +136,15 @@ IBSCRIPTPATH_TMP2="`echo $IBSCRIPTPATH_TMP1 | sed 's/^NONE/$ac_default_prefix/'`
 IBSCRIPTPATH="`eval echo $IBSCRIPTPATH_TMP2`"
 AC_SUBST(IBSCRIPTPATH)
 
+dnl Begin libibnetdisc stuff
+ibnetdisc_api_version=`grep LIBVERSION $srcdir/libibnetdisc/libibnetdisc.ver | sed 's/LIBVERSION=//'`
+if test -z $ibnetdisc_api_version; then
+   echo "FAILED to find $srcdir/libibnetdisc/libibnetdisc.ver"
+   exit 1
+fi
+AC_SUBST(ibnetdisc_api_version)
+dnl End libibnetdisc stuff
+
 AC_CONFIG_FILES([\
         Makefile \
         infiniband-diags.spec \
@@ -156,6 +165,7 @@ AC_CONFIG_FILES([\
         scripts/ibhosts \
         scripts/ibnodes \
         scripts/ibswitches \
-	scripts/ibrouters
+	scripts/ibrouters \
+   libibnetdisc/Makefile
 ])
 AC_OUTPUT
diff --git a/infiniband-diags/libibnetdisc/Makefile.am b/infiniband-diags/libibnetdisc/Makefile.am
new file mode 100644
index 0000000..e6e3620
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/Makefile.am
@@ -0,0 +1,47 @@
+
+#SUBDIRS = .
+
+INCLUDES = -I$(srcdir)/include -I$(includedir) -I$(includedir)/infiniband
+
+lib_LTLIBRARIES = libibnetdisc.la
+sbin_PROGRAMS =
+
+if ENABLE_TEST_UTILS
+sbin_PROGRAMS += test/testleaks
+endif
+
+DBGFLAGS = -g
+
+if HAVE_LD_VERSION_SCRIPT
+libibnetdisc_version_script = -Wl,--version-script=$(srcdir)/src/libibnetdisc.map
+else
+libibnetdisc_version_script =
+endif
+
+libibnetdisc_la_SOURCES = src/ibnetdisc.c src/chassis.c src/chassis.h
+libibnetdisc_la_CFLAGS = -Wall $(DBGFLAGS)
+libibnetdisc_la_LDFLAGS = -version-info $(ibnetdisc_api_version) \
+	-export-dynamic $(libibnetdisc_version_script) \
+	-libmad
+libibnetdisc_la_DEPENDENCIES = $(srcdir)/src/libibnetdisc.map
+
+libibnetdiscincludedir = $(includedir)/infiniband
+
+test_testleaks_SOURCES = test/testleaks.c
+test_testleaks_CFLAGS = -Wall $(DBGFLAGS)
+test_testleaks_LDFLAGS = -libnetdisc
+
+libibnetdiscinclude_HEADERS = $(srcdir)/include/infiniband/ibnetdisc.h
+
+man_MANS = man/ibnd_debug.3 \
+	man/ibnd_destroy_fabric.3 \
+	man/ibnd_discover_fabric.3 \
+	man/ibnd_find_node_dr.3 \
+	man/ibnd_find_node_guid.3 \
+	man/ibnd_iter_nodes.3 \
+	man/ibnd_iter_nodes_type.3 \
+	man/ibnd_show_progress.3 \
+	man/ibnd_update_node.3
+
+EXTRA_DIST = $(srcdir)/src/libibnetdisc.map libibnetdisc.ver
+
diff --git a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
new file mode 100644
index 0000000..a882994
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _IBNETDISC_H_
+#define _IBNETDISC_H_
+
+#include <stdio.h>
+#include <infiniband/mad.h>
+#include <iba/ib_types.h>
+
+struct ib_fabric; /* forward declare */
+struct chassis; /* forward declare */
+struct port; /* forward declare */
+
+/** =========================================================================
+ * Node
+ */
+typedef struct node {
+	struct node *next; /* all node list in fabric */
+	struct ib_fabric *fabric; /* the fabric node belongs to */
+
+	ib_portid_t path_portid; /* path from "from_node" */
+	int dist; /* num of hops from "from_node" */
+	int smalid;
+	int smalmc;
+
+	/* quick cache of switchinfo below */
+	int smaenhsp0;
+	/* use libibmad decoder functions for switchinfo */
+	//WHY does this not work???
+	//uint8_t switchinfo[sizeof (ib_switch_info_t)];
+	uint8_t switchinfo[64];
+
+	/* quick cache of info below */
+	uint64_t guid;
+	int type;
+	int numports;
+	/* use libibmad decoder functions for info */
+	uint8_t info[sizeof(ib_node_info_t)];
+
+	char nodedesc[IB_NODE_DESCRIPTION_SIZE];
+
+	struct port **ports; /* in order array of port pointers */
+				/* the size of this array is info.numports + 1 */
+				/* items MAY BE NULL!  (ie 0 == switches only) */
+
+	/* chassis info */
+	struct node *next_chassis_node; /* next node in ibnd_chassis_t->nodes */
+	struct chassis *chassis; /* if != NULL the chassis this node belongs to */
+	unsigned char ch_type;
+	unsigned char ch_anafanum;
+	unsigned char ch_slotnum;
+	unsigned char ch_slot;
+} ibnd_node_t;
+
+/** =========================================================================
+ * Port
+ */
+typedef struct port {
+	uint64_t guid;
+	int portnum;
+	int ext_portnum; /* optional if != 0 external port num */
+	ibnd_node_t *node; /* node this port belongs to */
+	struct port *remoteport; /* null if SMA, or does not exist */
+	/* quick cache of info below */
+	uint16_t base_lid;
+	uint8_t lmc;
+	/* use libibmad decoder functions for info */
+	uint8_t info[sizeof(ib_port_info_t)];
+} ibnd_port_t;
+
+
+/** =========================================================================
+ * Chassis
+ */
+typedef struct chassis {
+	struct chassis *next;
+	uint64_t chassisguid;
+	int chassisnum;
+
+	/* generic grouping by SystemImageGUID */
+	int nodecount;
+	ibnd_node_t *nodes;
+
+	/* specific to voltaire type nodes */
+#define SPINES_MAX_NUM 12
+#define LINES_MAX_NUM 36
+	ibnd_node_t *spinenode[SPINES_MAX_NUM + 1];
+	ibnd_node_t *linenode[LINES_MAX_NUM + 1];
+} ibnd_chassis_t;
+
+/** =========================================================================
+ * Fabric
+ * Main fabric object which is returned and represents the data discovered
+ */
+typedef struct ib_fabric {
+	/* the node the discover was initiated from
+	 * "from" parameter in ibnd_discover_fabric
+	 * or by default the node you ar running on
+	 */
+	ibnd_node_t *from_node;
+	/* NULL term list of all nodes in the fabric */
+	ibnd_node_t *nodes;
+	/* NULL terminated list of all chassis found in the fabric */
+	ibnd_chassis_t *chassis;
+	int maxhops_discovered;
+} ibnd_fabric_t;
+
+
+/** =========================================================================
+ * Initialization (fabric operations)
+ */
+void           ibnd_debug(int i);
+void           ibnd_show_progress(int i);
+
+ibnd_fabric_t *ibnd_discover_fabric(char *dev_name, int dev_port,
+			int timeout_ms, ib_portid_t *from, int hops);
+	/**
+	 * dev_name: (required) local device name to use to access the fabric
+	 * dev_port: (required) local device port to use to access the fabric
+	 * timeout_ms: (required) gives the timeout for a _SINGLE_ query on
+	 *             the fabric.  So if there are multiple nodes not
+	 *             responding this may result in a lengthy delay.
+	 * from: (optional) specify the node to start scanning from.
+	 *       If NULL start from the node we are running on.
+	 * hops: (optional) Specify how much of the fabric to traverse.
+	 *       negative value == scan entire fabric
+	 */
+void           ibnd_destroy_fabric(ibnd_fabric_t *fabric);
+
+/** =========================================================================
+ * Node operations
+ */
+ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t *fabric, uint64_t guid);
+ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t *fabric, char *dr_str);
+ibnd_node_t *ibnd_update_node(ibnd_node_t *node);
+
+typedef void (*ibnd_iter_node_func_t)(ibnd_node_t *node, void *user_data);
+void         ibnd_iter_nodes(ibnd_fabric_t *fabric,
+				ibnd_iter_node_func_t func,
+				void *user_data);
+void         ibnd_iter_nodes_type(ibnd_fabric_t *fabric,
+				ibnd_iter_node_func_t func,
+				int node_type,
+				void *user_data);
+
+/** =========================================================================
+ * Chassis queries
+ */
+uint64_t  ibnd_get_chassis_guid(ibnd_fabric_t *fabric, unsigned char chassisnum);
+char     *ibnd_get_chassis_type(ibnd_node_t *node);
+char     *ibnd_get_chassis_slot_str(ibnd_node_t *node, char *str, size_t size);
+
+int       ibnd_is_xsigo_guid(uint64_t guid);
+int       ibnd_is_xsigo_tca(uint64_t guid);
+int       ibnd_is_xsigo_hca(uint64_t guid);
+
+#endif	/* _IBNETDISC_H_ */
diff --git a/infiniband-diags/libibnetdisc/libibnetdisc.ver b/infiniband-diags/libibnetdisc/libibnetdisc.ver
new file mode 100644
index 0000000..a0a5f3c
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/libibnetdisc.ver
@@ -0,0 +1,9 @@
+# In this file we track the current API version
+# of the IB net discover interface (and libraries)
+# The version is built of the following
+# tree numbers:
+# API_REV:RUNNING_REV:AGE
+# API_REV - advance on any added API
+# RUNNING_REV - advance any change to the vendor files
+# AGE - number of backward versions the API still supports
+LIBVERSION=1:0:0
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_debug.3 b/infiniband-diags/libibnetdisc/man/ibnd_debug.3
new file mode 100644
index 0000000..a4076fc
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_debug.3
@@ -0,0 +1,2 @@
+.\".TH IBND_DEBUG 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.so man3/ibnd_discover_fabric.3
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_destroy_fabric.3 b/infiniband-diags/libibnetdisc/man/ibnd_destroy_fabric.3
new file mode 100644
index 0000000..8fe20ae
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_destroy_fabric.3
@@ -0,0 +1,2 @@
+.\".TH IBND_DESTROY_FABRIC 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.so man3/ibnd_discover_fabric.3
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_discover_fabric.3 b/infiniband-diags/libibnetdisc/man/ibnd_discover_fabric.3
new file mode 100644
index 0000000..44d8c65
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_discover_fabric.3
@@ -0,0 +1,49 @@
+.TH IBND_DISCOVER_FABRIC 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.SH "NAME"
+ibnd_discover_fabric, ibnd_destroy_fabric, ibnd_debug ibnd_show_progress \- initialize ibnetdiscover library.
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/ibnetdisc.h>
+.sp
+.BI "ibnd_fabric_t *ibnd_discover_fabric(char *dev_name, int dev_port, int timeout_ms, ib_portid_t *from, int hops)"
+.BI "void ibnd_destroy_fabric(ibnd_fabric_t *fabric)"
+.BI "void ibnd_debug(int i)"
+.BI "void ibnd_show_progress(int i)"
+
+
+.SH "DESCRIPTION"
+.B ibnd_discover_fabric()
+Discover the fabric connected to the port specified by dev_name and dev_port, using a timeout specified.  The "from" and "hops" parameters are optional and allow one to scan part of a fabric by specifying a node "from" and a number of hops away from that node to scan, "hops".  This gives the user a "sub-fabric" which is "centered" anywhere they chose.
+
+.B ibnd_destroy_fabric()
+free all memory and resources associated with the fabric.
+
+.B ibnd_debug()
+Set the debug level to be printed as library operations take place.
+
+.B ibnd_debug()
+Indicate that the library should print debug output which shows it's progress
+through the fabric.
+
+.SH "RETURN VALUE"
+.B ibnd_discover_fabric()
+return NULL on failure, otherwise a valid ibnd_fabric_t object.
+
+.B ibnd_destory_fabric(), ibnd_debug()
+NONE
+
+.SH "EXAMPLES"
+
+.B Discover the entire fabric connected to device "mthca0", port 1.
+
+	ibnd_discover_fabric("mthca0", 1, 100, NULL, 0);
+
+.B Discover only a single node and those nodes connected to it.
+
+	str2drpath(&(port_id.drpath), from, 0, 0);
+
+	ibnd_discover_fabric("mthca0", 1, 100, &port_id, 1);
+
+.SH "AUTHORS"
+.TP
+Ira Weiny <weiny2 at llnl.gov>
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_find_node_dr.3 b/infiniband-diags/libibnetdisc/man/ibnd_find_node_dr.3
new file mode 100644
index 0000000..612e501
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_find_node_dr.3
@@ -0,0 +1,2 @@
+.\".TH IBND_FIND_NODE_DR 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.so man3/ibnd_find_node_guid.3
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_find_node_guid.3 b/infiniband-diags/libibnetdisc/man/ibnd_find_node_guid.3
new file mode 100644
index 0000000..676b528
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_find_node_guid.3
@@ -0,0 +1,25 @@
+.TH IBND_FIND_NODE_GUID 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.SH "NAME"
+ibnd_find_node_guid, ibnd_find_node_dr \- given a fabric object find the node object within it which matches the guid or directed route specified.
+
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/ibnetdisc.h>
+.sp
+.BI "ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t *fabric, uint64_t guid)"
+.BI "ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t *fabric, char *dr_str)"
+
+.SH "DESCRIPTION"
+.B ibnd_find_node_guid()
+Given a fabric object and a guid, return the ibnd_node_t object with that node guid.
+.B ibnd_find_node_dr()
+Given a fabric object and a directed route, return the ibnd_node_t object with
+that directed route.
+
+.SH "RETURN VALUE"
+.B ibnd_find_node_guid(), ibnd_find_node_dr()
+return NULL on failure, otherwise a valid ibnd_node_t object.
+
+.SH "AUTHORS"
+.TP
+Ira Weiny <weiny2 at llnl.gov>
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes.3 b/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes.3
new file mode 100644
index 0000000..7199dfb
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes.3
@@ -0,0 +1,24 @@
+.TH IBND_ITER_NODES 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.SH "NAME"
+ibnd_iter_nodes, ibnd_iter_nodes_type \- given a fabric object and a function itterate over the nodes in the fabric.
+
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/ibnetdisc.h>
+.sp
+.BI "void ibnd_iter_nodes(ibnd_fabric_t *fabric, ibnd_iter_func_t func, void *user_data)"
+.BI "void ibnd_iter_nodes_type(ibnd_fabric_t *fabric, ibnd_iter_func_t func, ibnd_node_type_t type, void *user_data)"
+
+.SH "DESCRIPTION"
+.B ibnd_iter_nodes()
+Itterate through all the nodes in the fabric and call "func" on them.
+.B ibnd_iter_nodes_type()
+The same as ibnd_iter_nodes except to limit the iteration to the nodes with the specified type.
+
+.SH "RETURN VALUE"
+.B ibnd_iter_nodes(), ibnd_iter_nodes_type()
+NONE
+
+.SH "AUTHORS"
+.TP
+Ira Weiny <weiny2 at llnl.gov>
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes_type.3 b/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes_type.3
new file mode 100644
index 0000000..dc3ac8f
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes_type.3
@@ -0,0 +1,2 @@
+.\".TH IBND_FIND_NODES_TYPE 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.so man3/ibnd_iter_nodes.3
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_show_progress.3 b/infiniband-diags/libibnetdisc/man/ibnd_show_progress.3
new file mode 100644
index 0000000..280af31
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_show_progress.3
@@ -0,0 +1,2 @@
+.\".TH IBND_SHOW_PROGRESS 3  "Nov 26, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.so man3/ibnd_discover_fabric.3
diff --git a/infiniband-diags/libibnetdisc/man/ibnd_update_node.3 b/infiniband-diags/libibnetdisc/man/ibnd_update_node.3
new file mode 100644
index 0000000..d3aa206
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/man/ibnd_update_node.3
@@ -0,0 +1,21 @@
+.TH IBND_UPDATE_NODE 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
+.SH "NAME"
+ibnd_update_node \- Update the node specified with new data from the fabric.
+
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/ibnetdisc.h>
+.sp
+.BI "ibnd_node_t *ibnd_update_node(ibnd_node_t *node)"
+
+.SH "DESCRIPTION"
+.B ibnd_update_node()
+Update the node info, port info, and node description of the node specified.
+
+.SH "RETURN VALUE"
+.B ibnd_update_node()
+Return NULL on failure, otherwise a valid ibnd_node_t object which is part of the fabric object.
+
+.SH "AUTHORS"
+.TP
+Ira Weiny <weiny2 at llnl.gov>
diff --git a/infiniband-diags/libibnetdisc/src/chassis.c b/infiniband-diags/libibnetdisc/src/chassis.c
new file mode 100644
index 0000000..a25d710
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/src/chassis.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
+ * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/*========================================================*/
+/*               FABRIC SCANNER SPECIFIC DATA             */
+/*========================================================*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <infiniband/mad.h>
+
+#include "internal.h"
+#include "chassis.h"
+
+static char *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" };
+static char *ChassisSlotTypeStr[4] = { "", "Line", "Spine", "SRBD" };
+
+char *ibnd_get_chassis_type(ibnd_node_t *node)
+{
+	/* Currently, only if Voltaire chassis */
+	if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
+		return (NULL);
+	if (!node->chassis)
+		return (NULL);
+	if (node->ch_type == UNRESOLVED_CT
+		|| node->ch_type > ISR2004_CT)
+		return (NULL);
+	return ChassisTypeStr[node->ch_type];
+}
+
+char *ibnd_get_chassis_slot_str(ibnd_node_t *node, char *str, size_t size)
+{
+	/* Currently, only if Voltaire chassis */
+	if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
+		return (NULL);
+	if (!node->chassis)
+		return (NULL);
+	if (node->ch_slot == UNRESOLVED_CS
+		|| node->ch_slot > SRBD_CS)
+		return (NULL);
+	if (!str)
+		return (NULL);
+	snprintf(str, size, "%s %d Chip %d",
+			ChassisSlotTypeStr[node->ch_slot],
+			node->ch_slotnum,
+			node->ch_anafanum);
+	return (str);
+}
+
+static ibnd_chassis_t *find_chassisnum(struct ibnd_fabric *fabric, unsigned char chassisnum)
+{
+	ibnd_chassis_t *current;
+
+	for (current = fabric->first_chassis; current; current = current->next) {
+		if (current->chassisnum == chassisnum)
+			return current;
+	}
+
+	return NULL;
+}
+
+static uint64_t topspin_chassisguid(uint64_t guid)
+{
+	/* Byte 3 in system image GUID is chassis type, and */
+	/* Byte 4 is location ID (slot) so just mask off byte 4 */
+	return guid & 0xffffffff00ffffffULL;
+}
+
+int ibnd_is_xsigo_guid(uint64_t guid)
+{
+	if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_xsigo_leafone(uint64_t guid)
+{
+	if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL)
+		return 1;
+	else
+		return 0;
+}
+
+int ibnd_is_xsigo_hca(uint64_t guid)
+{
+	/* NodeType 2 is HCA */
+	if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL)
+		return 1;
+	else
+		return 0;
+}
+
+int ibnd_is_xsigo_tca(uint64_t guid)
+{
+	/* NodeType 3 is TCA */
+	if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_xsigo_ca(uint64_t guid)
+{
+	if (ibnd_is_xsigo_hca(guid) || ibnd_is_xsigo_tca(guid))
+		return 1;
+	else
+		return 0;
+}
+
+static int is_xsigo_switch(uint64_t guid)
+{
+	if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL)
+		return 1;
+	else
+		return 0;
+}
+
+static uint64_t xsigo_chassisguid(ibnd_node_t *node)
+{
+	uint64_t sysimgguid = mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
+	if (!is_xsigo_ca(sysimgguid)) {
+		/* Byte 3 is NodeType and byte 4 is PortType */
+		/* If NodeType is 1 (switch), PortType is masked */
+		if (is_xsigo_switch(sysimgguid))
+			return sysimgguid & 0xffffffff00ffffffULL;
+		else
+			return sysimgguid;
+	} else {
+		if (!node->ports || !node->ports[1])
+			return (0);
+
+		/* Is there a peer port ? */
+		if (!node->ports[1]->remoteport)
+			return sysimgguid;
+
+		/* If peer port is Leaf 1, use its chassis GUID */
+		uint64_t remote_sysimgguid = mad_get_field64(
+					node->ports[1]->remoteport->node->info,
+					0, IB_NODE_SYSTEM_GUID_F);
+		if (is_xsigo_leafone(remote_sysimgguid))
+			return remote_sysimgguid & 0xffffffff00ffffffULL;
+		else
+			return sysimgguid;
+	}
+}
+
+static uint64_t get_chassisguid(ibnd_node_t *node)
+{
+	uint32_t vendid = mad_get_field(node->info, 0, IB_NODE_VENDORID_F);
+	uint64_t sysimgguid = mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
+
+	if (vendid == TS_VENDOR_ID || vendid == SS_VENDOR_ID)
+		return topspin_chassisguid(sysimgguid);
+	else if (vendid == XS_VENDOR_ID || ibnd_is_xsigo_guid(sysimgguid))
+		return xsigo_chassisguid(node);
+	else
+		return sysimgguid;
+}
+
+static ibnd_chassis_t *find_chassisguid(ibnd_node_t *node)
+{
+	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(node->fabric);
+	ibnd_chassis_t *current;
+	uint64_t chguid;
+
+	chguid = get_chassisguid(node);
+	for (current = f->first_chassis; current; current = current->next) {
+		if (current->chassisguid == chguid)
+			return current;
+	}
+
+	return NULL;
+}
+
+uint64_t ibnd_get_chassis_guid(ibnd_fabric_t *fabric, unsigned char chassisnum)
+{
+	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
+	ibnd_chassis_t *chassis;
+
+	chassis = find_chassisnum(f, chassisnum);
+	if (chassis)
+		return chassis->chassisguid;
+	else
+		return 0;
+}
+
+static int is_router(struct ibnd_node *n)
+{
+	uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F);
+	return (devid == VTR_DEVID_IB_FC_ROUTER ||
+		devid == VTR_DEVID_IB_IP_ROUTER);
+}
+
+static int is_spine_9096(struct ibnd_node *n)
+{
+	uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F);
+	return (devid == VTR_DEVID_SFB4 ||
+		devid == VTR_DEVID_SFB4_DDR);
+}
+
+static int is_spine_9288(struct ibnd_node *n)
+{
+	uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F);
+	return (devid == VTR_DEVID_SFB12 ||
+		devid == VTR_DEVID_SFB12_DDR);
+}
+
+static int is_spine_2004(struct ibnd_node *n)
+{
+	uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F);
+	return (devid == VTR_DEVID_SFB2004);
+}
+
+static int is_spine_2012(struct ibnd_node *n)
+{
+	uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F);
+	return (devid == VTR_DEVID_SFB2012);
+}
+
+static int is_spine(struct ibnd_node *n)
+{
+	return (is_spine_9096(n) || is_spine_9288(n) ||
+		is_spine_2004(n) || is_spine_2012(n));
+}
+
+static int is_line_24(struct ibnd_node *n)
+{
+	uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F);
+	return (devid == VTR_DEVID_SLB24 ||
+		devid == VTR_DEVID_SLB24_DDR ||
+		devid == VTR_DEVID_SRB2004);
+}
+
+static int is_line_8(struct ibnd_node *n)
+{
+	uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F);
+	return (devid == VTR_DEVID_SLB8);
+}
+
+static int is_line_2024(struct ibnd_node *n)
+{
+	uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F);
+	return (devid == VTR_DEVID_SLB2024);
+}
+
+static int is_line(struct ibnd_node *n)
+{
+	return (is_line_24(n) || is_line_8(n) || is_line_2024(n));
+}
+
+int is_chassis_switch(struct ibnd_node *n)
+{
+    return (is_spine(n) || is_line(n));
+}
+
+/* these structs help find Line (Anafa) slot number while using spine portnum */
+int line_slot_2_sfb4[25]        = { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 };
+int anafa_line_slot_2_sfb4[25]  = { 0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2 };
+int line_slot_2_sfb12[25]       = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10, 10, 11, 11, 12, 12 };
+int anafa_line_slot_2_sfb12[25] = { 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 };
+
+/* IPR FCR modules connectivity while using sFB4 port as reference */
+int ipr_slot_2_sfb4_port[25]    = { 0, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1 };
+
+/* these structs help find Spine (Anafa) slot number while using spine portnum */
+int spine12_slot_2_slb[25]      = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+int anafa_spine12_slot_2_slb[25]= { 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+int spine4_slot_2_slb[25]       = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+int anafa_spine4_slot_2_slb[25] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+/*	reference                     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */
+
+static void get_sfb_slot(struct ibnd_node *node, ibnd_port_t *lineport)
+{
+	ibnd_node_t *n = (ibnd_node_t *)node;
+
+	n->ch_slot = SPINE_CS;
+	if (is_spine_9096(node)) {
+		n->ch_type = ISR9096_CT;
+		n->ch_slotnum = spine4_slot_2_slb[lineport->portnum];
+		n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
+	} else if (is_spine_9288(node)) {
+		n->ch_type = ISR9288_CT;
+		n->ch_slotnum = spine12_slot_2_slb[lineport->portnum];
+		n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
+	} else if (is_spine_2012(node)) {
+		n->ch_type = ISR2012_CT;
+		n->ch_slotnum = spine12_slot_2_slb[lineport->portnum];
+		n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
+	} else if (is_spine_2004(node)) {
+		n->ch_type = ISR2004_CT;
+		n->ch_slotnum = spine4_slot_2_slb[lineport->portnum];
+		n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
+	} else {
+		IBPANIC("Unexpected node found: guid 0x%016" PRIx64,
+		node->node.guid);
+	}
+}
+
+static void get_router_slot(struct ibnd_node *node, ibnd_port_t *spineport)
+{
+	ibnd_node_t *n = (ibnd_node_t *)node;
+	int guessnum = 0;
+
+	node->ch_found = 1;
+
+	n->ch_slot = SRBD_CS;
+	if (is_spine_9096(CONV_NODE_INTERNAL(spineport->node))) {
+		n->ch_type = ISR9096_CT;
+		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
+		n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
+	} else if (is_spine_9288(CONV_NODE_INTERNAL(spineport->node))) {
+		n->ch_type = ISR9288_CT;
+		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
+		/* this is a smart guess based on nodeguids order on sFB-12 module */
+		guessnum = spineport->node->guid % 4;
+		/* module 1 <--> remote anafa 3 */
+		/* module 2 <--> remote anafa 2 */
+		/* module 3 <--> remote anafa 1 */
+		n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));
+	} else if (is_spine_2012(CONV_NODE_INTERNAL(spineport->node))) {
+		n->ch_type = ISR2012_CT;
+		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
+		/* this is a smart guess based on nodeguids order on sFB-12 module */
+		guessnum = spineport->node->guid % 4;
+		// module 1 <--> remote anafa 3
+		// module 2 <--> remote anafa 2
+		// module 3 <--> remote anafa 1
+		n->ch_anafanum = (guessnum == 3? 1 : (guessnum == 1 ? 3 : 2));
+	} else if (is_spine_2004(CONV_NODE_INTERNAL(spineport->node))) {
+		n->ch_type = ISR2004_CT;
+		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
+		n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
+	} else {
+		IBPANIC("Unexpected node found: guid 0x%016" PRIx64,
+		spineport->node->guid);
+	}
+}
+
+static void get_slb_slot(ibnd_node_t *n, ibnd_port_t *spineport)
+{
+	n->ch_slot = LINE_CS;
+	if (is_spine_9096(CONV_NODE_INTERNAL(spineport->node))) {
+		n->ch_type = ISR9096_CT;
+		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
+		n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
+	} else if (is_spine_9288(CONV_NODE_INTERNAL(spineport->node))) {
+		n->ch_type = ISR9288_CT;
+		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
+		n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
+	} else if (is_spine_2012(CONV_NODE_INTERNAL(spineport->node))) {
+		n->ch_type = ISR2012_CT;
+		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
+		n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
+	} else if (is_spine_2004(CONV_NODE_INTERNAL(spineport->node))) {
+		n->ch_type = ISR2004_CT;
+		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
+		n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
+	} else {
+		IBPANIC("Unexpected node found: guid 0x%016" PRIx64,
+		spineport->node->guid);
+	}
+}
+
+/* forward declare this */
+static void voltaire_portmap(ibnd_port_t *port);
+/*
+	This function called for every Voltaire node in fabric
+	It could be optimized so, but time overhead is very small
+	and its only diag.util
+*/
+static void fill_voltaire_chassis_record(struct ibnd_node *node)
+{
+	ibnd_node_t *n = (ibnd_node_t *)node;
+	int p = 0;
+	ibnd_port_t *port;
+	struct ibnd_node *remnode = 0;
+
+	if (node->ch_found) /* somehow this node has already been passed */
+		return;
+	node->ch_found = 1;
+
+	/* node is router only in case of using unique lid */
+	/* (which is lid of chassis router port) */
+	/* in such case node->ports is actually a requested port... */
+	if (is_router(node)) {
+		/* find the remote node */
+		for (p = 1; p <= node->node.numports; p++) {
+			port = node->node.ports[p];
+			if (port && is_spine(CONV_NODE_INTERNAL(port->remoteport->node)))
+				get_router_slot(node, port->remoteport);
+		}
+	} else if (is_spine(node)) {
+		for (p = 1; p <= node->node.numports; p++) {
+			port = node->node.ports[p];
+			if (!port || !port->remoteport)
+				continue;
+			remnode = CONV_NODE_INTERNAL(port->remoteport->node);
+			if (remnode->node.type != IB_NODE_SWITCH) {
+				if (!remnode->ch_found)
+					get_router_slot(remnode, port);
+				continue;
+			}
+			if (!n->ch_type)
+				/* we assume here that remoteport belongs to line */
+				get_sfb_slot(node, port->remoteport);
+
+				/* we could break here, but need to find if more routers connected */
+		}
+
+	} else if (is_line(node)) {
+		for (p = 1; p <= node->node.numports; p++) {
+			port = node->node.ports[p];
+			if (!port || port->portnum > 12 || !port->remoteport)
+				continue;
+			/* we assume here that remoteport belongs to spine */
+			get_slb_slot(n, port->remoteport);
+			break;
+		}
+	}
+
+	/* for each port of this node, map external ports */
+	for (p = 1; p <= node->node.numports; p++) {
+		port = node->node.ports[p];
+		if (!port)
+			continue;
+		voltaire_portmap(port);
+	}
+
+	return;
+}
+
+static int get_line_index(ibnd_node_t *node)
+{
+	int retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
+
+	if (retval > LINES_MAX_NUM || retval < 1)
+		IBPANIC("Internal error");
+	return retval;
+}
+
+static int get_spine_index(ibnd_node_t *node)
+{
+	int retval;
+
+	if (is_spine_9288(CONV_NODE_INTERNAL(node)) || is_spine_2012(CONV_NODE_INTERNAL(node)))
+		retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
+	else
+		retval = node->ch_slotnum;
+
+	if (retval > SPINES_MAX_NUM || retval < 1)
+		IBPANIC("Internal error");
+	return retval;
+}
+
+static void insert_line_router(ibnd_node_t *node, ibnd_chassis_t *chassis)
+{
+	int i = get_line_index(node);
+
+	if (chassis->linenode[i])
+		return;		/* already filled slot */
+
+	chassis->linenode[i] = node;
+	node->chassis = chassis;
+}
+
+static void insert_spine(ibnd_node_t *node, ibnd_chassis_t *chassis)
+{
+	int i = get_spine_index(node);
+
+	if (chassis->spinenode[i])
+		return;		/* already filled slot */
+
+	chassis->spinenode[i] = node;
+	node->chassis = chassis;
+}
+
+static void pass_on_lines_catch_spines(ibnd_chassis_t *chassis)
+{
+	ibnd_node_t *node, *remnode;
+	ibnd_port_t *port;
+	int i, p;
+
+	for (i = 1; i <= LINES_MAX_NUM; i++) {
+		node = chassis->linenode[i];
+
+		if (!(node && is_line(CONV_NODE_INTERNAL(node))))
+			continue;	/* empty slot or router */
+
+		for (p = 1; p <= node->numports; p++) {
+			port = node->ports[p];
+			if (!port || port->portnum > 12 || !port->remoteport)
+				continue;
+
+			remnode = port->remoteport->node;
+
+			if (!CONV_NODE_INTERNAL(remnode)->ch_found)
+				continue;	/* some error - spine not initialized ? FIXME */
+			insert_spine(remnode, chassis);
+		}
+	}
+}
+
+static void pass_on_spines_catch_lines(ibnd_chassis_t *chassis)
+{
+	ibnd_node_t *node, *remnode;
+	ibnd_port_t *port;
+	int i, p;
+
+	for (i = 1; i <= SPINES_MAX_NUM; i++) {
+		node = chassis->spinenode[i];
+		if (!node)
+			continue;	/* empty slot */
+		for (p = 1; p <= node->numports; p++) {
+			port = node->ports[p];
+			if (!port || !port->remoteport)
+				continue;
+			remnode = port->remoteport->node;
+
+			if (!CONV_NODE_INTERNAL(remnode)->ch_found)
+				continue;	/* some error - line/router not initialized ? FIXME */
+			insert_line_router(remnode, chassis);
+		}
+	}
+}
+
+/*
+	Stupid interpolation algorithm...
+	But nothing to do - have to be compliant with VoltaireSM/NMS
+*/
+static void pass_on_spines_interpolate_chguid(ibnd_chassis_t *chassis)
+{
+	ibnd_node_t *node;
+	int i;
+
+	for (i = 1; i <= SPINES_MAX_NUM; i++) {
+		node = chassis->spinenode[i];
+		if (!node)
+			continue;	/* skip the empty slots */
+
+		/* take first guid minus one to be consistent with SM */
+		chassis->chassisguid = node->guid - 1;
+		break;
+	}
+}
+
+/*
+	This function fills chassis structure with all nodes
+	in that chassis
+	chassis structure = structure of one standalone chassis
+*/
+static void build_chassis(struct ibnd_node *node, ibnd_chassis_t *chassis)
+{
+	int p = 0;
+	struct ibnd_node *remnode = 0;
+	ibnd_port_t *port = 0;
+
+	/* we get here with node = chassis_spine */
+	insert_spine((ibnd_node_t *)node, chassis);
+
+	/* loop: pass on all ports of node */
+	for (p = 1; p <= node->node.numports; p++ ) {
+		port = node->node.ports[p];
+		if (!port || !port->remoteport)
+			continue;
+		remnode = CONV_NODE_INTERNAL(port->remoteport->node);
+
+		if (!remnode->ch_found)
+			continue; /* some error - line or router not initialized ? FIXME */
+
+		insert_line_router(&(remnode->node), chassis);
+	}
+
+	pass_on_lines_catch_spines(chassis);
+	/* this pass needed for to catch routers, since routers connected only */
+	/* to spines in slot 1 or 4 and we could miss them first time */
+	pass_on_spines_catch_lines(chassis);
+
+	/* additional 2 passes needed for to overcome a problem of pure "in-chassis" */
+	/* connectivity - extra pass to ensure that all related chips/modules */
+	/* inserted into the chassis */
+	pass_on_lines_catch_spines(chassis);
+	pass_on_spines_catch_lines(chassis);
+	pass_on_spines_interpolate_chguid(chassis);
+}
+
+/*========================================================*/
+/*                INTERNAL TO EXTERNAL PORT MAPPING       */
+/*========================================================*/
+
+/*
+Description : On ISR9288/9096 external ports indexing
+              is not matching the internal ( anafa ) port
+              indexes. Use this MAP to translate the data you get from
+              the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.)
+
+
+Module : sLB-24
+                anafa 1             anafa 2
+ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
+int port | 22 23 24 18 17 16 | 22 23 24 18 17 16
+ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
+int port | 19 20 21 15 14 13 | 19 20 21 15 14 13
+------------------------------------------------
+
+Module : sLB-8
+                anafa 1             anafa 2
+ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
+int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
+ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
+int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
+
+----------->
+                anafa 1             anafa 2
+ext port | -  -  5  -  -  6  | -  -  7  -  -  8
+int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
+ext port | -  -  1  -  -  2  | -  -  3  -  -  4
+int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
+------------------------------------------------
+
+Module : sLB-2024
+
+ext port | 13 14 15 16 17 18 19 20 21 22 23 24
+A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24
+ext port | 1 2 3 4 5 6 7 8 9 10 11 12
+A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24
+---------------------------------------------------
+
+*/
+
+int int2ext_map_slb24[2][25] = {
+					{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3, 13, 14, 15 },
+					{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9, 19, 20, 21 }
+				};
+int int2ext_map_slb8[2][25] = {
+					{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5, 5 },
+					{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7, 7 }
+				};
+int int2ext_map_slb2024[2][25] = {
+					{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 },
+					{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
+				};
+/*	reference			{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */
+
+/* map internal ports to external ports if appropriate */
+static void
+voltaire_portmap(ibnd_port_t *port)
+{
+	struct ibnd_node *n = CONV_NODE_INTERNAL(port->node);
+	int portnum = port->portnum;
+	int chipnum = 0;
+	ibnd_node_t *node = port->node;
+
+	if (!n->ch_found || !is_line(CONV_NODE_INTERNAL(node)) || (portnum < 13 || portnum > 24)) {
+		port->ext_portnum = 0;
+		return;
+	}
+
+	if (port->node->ch_anafanum < 1 || port->node->ch_anafanum > 2) {
+		port->ext_portnum = 0;
+		return;
+	}
+
+	chipnum = port->node->ch_anafanum - 1;
+
+	if (is_line_24(CONV_NODE_INTERNAL(node)))
+		port->ext_portnum = int2ext_map_slb24[chipnum][portnum];
+	else if (is_line_2024(CONV_NODE_INTERNAL(node)))
+		port->ext_portnum = int2ext_map_slb2024[chipnum][portnum];
+	else
+		port->ext_portnum = int2ext_map_slb8[chipnum][portnum];
+}
+
+static void add_chassis(struct ibnd_fabric *fabric)
+{
+	if (!(fabric->current_chassis = calloc(1, sizeof(ibnd_chassis_t))))
+		IBPANIC("out of mem");
+
+	if (fabric->first_chassis == NULL) {
+		fabric->first_chassis = fabric->current_chassis;
+		fabric->last_chassis = fabric->current_chassis;
+	} else {
+		fabric->last_chassis->next = fabric->current_chassis;
+		fabric->last_chassis = fabric->current_chassis;
+	}
+}
+
+static void
+add_node_to_chassis(ibnd_chassis_t *chassis, ibnd_node_t *node)
+{
+	node->chassis = chassis;
+	node->next_chassis_node = chassis->nodes;
+	chassis->nodes = node;
+}
+
+/*
+	Main grouping function
+	Algorithm:
+	1. pass on every Voltaire node
+	2. catch spine chip for every Voltaire node
+		2.1 build/interpolate chassis around this chip
+		2.2 go to 1.
+	3. pass on non Voltaire nodes (SystemImageGUID based grouping)
+	4. now group non Voltaire nodes by SystemImageGUID
+	Returns:
+	Pointer to the first chassis in a NULL terminated list of chassis in
+	the fabric specified.
+*/
+ibnd_chassis_t *group_nodes(struct ibnd_fabric *fabric)
+{
+	struct ibnd_node *node;
+	int dist;
+	int chassisnum = 0;
+	ibnd_chassis_t *chassis;
+
+	fabric->first_chassis = NULL;
+	fabric->current_chassis = NULL;
+
+	/* first pass on switches and build for every Voltaire node */
+	/* an appropriate chassis record (slotnum and position) */
+	/* according to internal connectivity */
+	/* not very efficient but clear code so... */
+	for (dist = 0; dist <= fabric->fabric.maxhops_discovered; dist++) {
+		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
+			if (mad_get_field(node->node.info, 0, IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
+				fill_voltaire_chassis_record(node);
+		}
+	}
+
+	/* separate every Voltaire chassis from each other and build linked list of them */
+	/* algorithm: catch spine and find all surrounding nodes */
+	for (dist = 0; dist <= fabric->fabric.maxhops_discovered; dist++) {
+		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
+			if (mad_get_field(node->node.info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
+				continue;
+			//if (!node->node.chrecord || node->node.chrecord->chassisnum || !is_spine(node))
+			if (!node->ch_found
+					|| (node->node.chassis && node->node.chassis->chassisnum)
+					|| !is_spine(node))
+				continue;
+			add_chassis(fabric);
+			fabric->current_chassis->chassisnum = ++chassisnum;
+			build_chassis(node, fabric->current_chassis);
+		}
+	}
+
+	/* now make pass on nodes for chassis which are not Voltaire */
+	/* grouped by common SystemImageGUID */
+	for (dist = 0; dist <= fabric->fabric.maxhops_discovered; dist++) {
+		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
+			if (mad_get_field(node->node.info, 0, IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
+				continue;
+			if (mad_get_field64(node->node.info, 0, IB_NODE_SYSTEM_GUID_F)) {
+				chassis = find_chassisguid((ibnd_node_t *)node);
+				if (chassis)
+					chassis->nodecount++;
+				else {
+					/* Possible new chassis */
+					add_chassis(fabric);
+					fabric->current_chassis->chassisguid =
+							get_chassisguid((ibnd_node_t *)node);
+					fabric->current_chassis->nodecount = 1;
+				}
+			}
+		}
+	}
+
+	/* now, make another pass to see which nodes are part of chassis */
+	/* (defined as chassis->nodecount > 1) */
+	for (dist = 0; dist <= MAXHOPS; ) {
+		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
+			if (mad_get_field(node->node.info, 0, IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
+				continue;
+			if (mad_get_field64(node->node.info, 0, IB_NODE_SYSTEM_GUID_F)) {
+				chassis = find_chassisguid((ibnd_node_t *)node);
+				if (chassis && chassis->nodecount > 1) {
+					if (!chassis->chassisnum)
+						chassis->chassisnum = ++chassisnum;
+					if (!node->ch_found) {
+						node->ch_found = 1;
+						add_node_to_chassis(chassis, (ibnd_node_t *)node);
+					}
+				}
+			}
+		}
+		if (dist == fabric->fabric.maxhops_discovered)
+			dist = MAXHOPS;	/* skip to CAs */
+		else
+			dist++;
+	}
+
+	return (fabric->first_chassis);
+}
diff --git a/infiniband-diags/libibnetdisc/src/chassis.h b/infiniband-diags/libibnetdisc/src/chassis.h
new file mode 100644
index 0000000..16dad49
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/src/chassis.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _CHASSIS_H_
+#define _CHASSIS_H_
+
+#include <infiniband/ibnetdisc.h>
+
+#include "internal.h"
+
+/*========================================================*/
+/*                CHASSIS RECOGNITION SPECIFIC DATA       */
+/*========================================================*/
+
+/* Device IDs */
+#define VTR_DEVID_IB_FC_ROUTER		0x5a00
+#define VTR_DEVID_IB_IP_ROUTER		0x5a01
+#define VTR_DEVID_ISR9600_SPINE		0x5a02
+#define VTR_DEVID_ISR9600_LEAF		0x5a03
+#define VTR_DEVID_HCA1			0x5a04
+#define VTR_DEVID_HCA2			0x5a44
+#define VTR_DEVID_HCA3			0x6278
+#define VTR_DEVID_SW_6IB4		0x5a05
+#define VTR_DEVID_ISR9024		0x5a06
+#define VTR_DEVID_ISR9288		0x5a07
+#define VTR_DEVID_SLB24			0x5a09
+#define VTR_DEVID_SFB12			0x5a08
+#define VTR_DEVID_SFB4			0x5a0b
+#define VTR_DEVID_ISR9024_12		0x5a0c
+#define VTR_DEVID_SLB8			0x5a0d
+#define VTR_DEVID_RLX_SWITCH_BLADE	0x5a20
+#define VTR_DEVID_ISR9024_DDR		0x5a31
+#define VTR_DEVID_SFB12_DDR		0x5a32
+#define VTR_DEVID_SFB4_DDR		0x5a33
+#define VTR_DEVID_SLB24_DDR		0x5a34
+#define VTR_DEVID_SFB2012		0x5a37
+#define VTR_DEVID_SLB2024		0x5a38
+#define VTR_DEVID_ISR2012		0x5a39
+#define VTR_DEVID_SFB2004		0x5a40
+#define VTR_DEVID_ISR2004		0x5a41
+#define VTR_DEVID_SRB2004		0x5a42
+
+/* Vendor IDs (for chassis based systems) */
+#define VTR_VENDOR_ID			0x8f1	/* Voltaire */
+#define TS_VENDOR_ID			0x5ad	/* Cisco */
+#define SS_VENDOR_ID			0x66a	/* InfiniCon */
+#define XS_VENDOR_ID			0x1397	/* Xsigo */
+
+enum ibnd_chassis_type { UNRESOLVED_CT, ISR9288_CT, ISR9096_CT, ISR2012_CT, ISR2004_CT };
+enum ibnd_chassis_slot_type { UNRESOLVED_CS, LINE_CS, SPINE_CS, SRBD_CS };
+
+ibnd_chassis_t *group_nodes(struct ibnd_fabric *fabric);
+
+#endif	/* _CHASSIS_H_ */
diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
new file mode 100644
index 0000000..bf7c2a7
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
+ * Copyright (c) 2008 Lawrence Livermore National Laboratory
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#include <infiniband/ibnetdisc.h>
+#include <complib/cl_nodenamemap.h>
+
+#include "internal.h"
+#include "chassis.h"
+
+static int timeout_ms = 2000;
+static int show_progress = 0;
+
+void
+decode_port_info(ibnd_port_t *port)
+{
+	port->base_lid = mad_get_field(port->info, 0, IB_PORT_LID_F);
+	port->lmc = mad_get_field(port->info, 0, IB_PORT_LMC_F);
+}
+
+static int
+get_port_info(struct ibnd_fabric *fabric, struct ibnd_port *port,
+		int portnum, ib_portid_t *portid)
+{
+	char width[64], speed[64];
+	port->port.portnum = portnum;
+	int iwidth = mad_get_field(port->port.info, 0,
+				IB_PORT_LINK_WIDTH_ACTIVE_F);
+	int ispeed = mad_get_field(port->port.info, 0,
+				IB_PORT_LINK_SPEED_ACTIVE_F);
+
+	if (!smp_query_via(port->port.info, portid, IB_ATTR_PORT_INFO, portnum, timeout_ms,
+			fabric->ibmad_port))
+		return -1;
+
+	decode_port_info(&(port->port));
+
+	IBND_DEBUG("portid %s portnum %d: base lid %d state %d physstate %d %s %s\n",
+		portid2str(portid), portnum, port->port.base_lid,
+		mad_get_field(port->port.info, 0, IB_PORT_STATE_F),
+		mad_get_field(port->port.info, 0, IB_PORT_PHYS_STATE_F),
+		mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth),
+		mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed));
+	return 0;
+}
+
+/*
+ * Returns -1 if error.
+ */
+static int
+query_node_info(struct ibnd_fabric *fabric, struct ibnd_node *node, ib_portid_t *portid)
+{
+	if (!smp_query_via(&(node->node.info), portid, IB_ATTR_NODE_INFO, 0, timeout_ms,
+			fabric->ibmad_port))
+		return -1;
+
+	/* decode just a couple of fields for quicker reference. */
+	mad_decode_field(node->node.info, IB_NODE_GUID_F, &(node->node.guid));
+	mad_decode_field(node->node.info, IB_NODE_TYPE_F, &(node->node.type));
+	mad_decode_field(node->node.info, IB_NODE_NPORTS_F,
+			&(node->node.numports));
+
+	return (0);
+}
+
+/*
+ * Returns 0 if non switch node is found, 1 if switch is found, -1 if error.
+ */
+static int
+query_node(struct ibnd_fabric *fabric, struct ibnd_node *inode,
+		struct ibnd_port *iport, ib_portid_t *portid)
+{
+	ibnd_node_t *node = &(inode->node);
+	ibnd_port_t *port = &(iport->port);
+	void *nd = inode->node.nodedesc;
+
+	if (query_node_info(fabric, inode, portid))
+		return -1;
+
+	port->portnum = mad_get_field(node->info, 0, IB_NODE_LOCAL_PORT_F);
+	port->guid = mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F);
+
+	if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, timeout_ms,
+			fabric->ibmad_port))
+		return -1;
+
+	if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO, 0, timeout_ms,
+			fabric->ibmad_port))
+		return -1;
+	decode_port_info(port);
+
+	if (node->type != IB_NODE_SWITCH)
+		return 0;
+
+	node->smalid = port->base_lid;
+	node->smalmc = port->lmc;
+
+	/* after we have the sma information find out the real PortInfo for this port */
+	if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO, port->portnum, timeout_ms,
+			fabric->ibmad_port))
+		return -1;
+	decode_port_info(port);
+
+        if (!smp_query_via(node->switchinfo, portid, IB_ATTR_SWITCH_INFO, 0, timeout_ms,
+			fabric->ibmad_port))
+		node->smaenhsp0 = 0;	/* assume base SP0 */
+	else
+		mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F, &node->smaenhsp0);
+
+	IBND_DEBUG("portid %s: got switch node %" PRIx64 " '%s'\n",
+	      portid2str(portid), node->guid, node->nodedesc);
+	return 0;
+}
+
+static int
+add_port_to_dpath(ib_dr_path_t *path, int nextport)
+{
+	if (path->cnt+2 >= sizeof(path->p))
+		return -1;
+	++path->cnt;
+	path->p[path->cnt] = nextport;
+	return path->cnt;
+}
+
+static int
+extend_dpath(struct ibnd_fabric *f, ib_dr_path_t *path, int nextport)
+{
+	int rc = add_port_to_dpath(path, nextport);
+	if ((rc != -1) && (path->cnt > f->fabric.maxhops_discovered))
+		f->fabric.maxhops_discovered = path->cnt;
+	return (rc);
+}
+
+static void
+dump_endnode(ib_portid_t *path, char *prompt,
+		struct ibnd_node *node, struct ibnd_port *port)
+{
+	char type[64];
+	if (!show_progress)
+		return;
+
+	mad_dump_node_type(type, 64, &(node->node.type), sizeof(int)),
+
+	printf("%s -> %s %s {%016" PRIx64 "} portnum %d base lid %d-%d\"%s\"\n",
+		portid2str(path), prompt, type,
+		node->node.guid,
+		node->node.type == IB_NODE_SWITCH ? 0 : port->port.portnum,
+		port->port.base_lid, port->port.base_lid + (1 << port->port.lmc) - 1,
+		node->node.nodedesc);
+}
+
+static struct ibnd_node *
+find_existing_node(struct ibnd_fabric *fabric, struct ibnd_node *new)
+{
+	int hash = HASHGUID(new->node.guid) % HTSZ;
+	struct ibnd_node *node;
+
+	for (node = fabric->nodestbl[hash]; node; node = node->htnext)
+		if (node->node.guid == new->node.guid)
+			return node;
+
+	return NULL;
+}
+
+ibnd_node_t *
+ibnd_find_node_guid(ibnd_fabric_t *fabric, uint64_t guid)
+{
+	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
+	int hash = HASHGUID(guid) % HTSZ;
+	struct ibnd_node *node;
+
+	for (node = f->nodestbl[hash]; node; node = node->htnext)
+		if (node->node.guid == guid)
+			return (ibnd_node_t *)node;
+
+	return NULL;
+}
+
+ibnd_node_t *
+ibnd_update_node(ibnd_node_t *node)
+{
+	char portinfo_port0[sizeof (ib_port_info_t)];
+	void *nd = node->nodedesc;
+	int p = 0;
+	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(node->fabric);
+	struct ibnd_node *n = CONV_NODE_INTERNAL(node);
+
+	if (query_node_info(f, n, &(n->node.path_portid)))
+		return (NULL);
+
+	if (!smp_query_via(nd, &(n->node.path_portid), IB_ATTR_NODE_DESC, 0, timeout_ms,
+			f->ibmad_port))
+		return (NULL);
+
+	/* update all the port info's */
+	for (p = 1; p >= n->node.numports; p++) {
+		get_port_info(f, CONV_PORT_INTERNAL(n->node.ports[p]), p, &(n->node.path_portid));
+	}
+
+	if (n->node.type != IB_NODE_SWITCH)
+		goto done;
+
+	if (!smp_query_via(portinfo_port0, &(n->node.path_portid), IB_ATTR_PORT_INFO, 0, timeout_ms,
+			f->ibmad_port))
+		return (NULL);
+
+	n->node.smalid = mad_get_field(portinfo_port0, 0, IB_PORT_LID_F);
+	n->node.smalmc = mad_get_field(portinfo_port0, 0, IB_PORT_LMC_F);
+
+        if (!smp_query_via(node->switchinfo, &(n->node.path_portid), IB_ATTR_SWITCH_INFO, 0, timeout_ms,
+			f->ibmad_port))
+                node->smaenhsp0 = 0;	/* assume base SP0 */
+	else
+		mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F, &n->node.smaenhsp0);
+
+done:
+	return (node);
+}
+
+ibnd_node_t *
+ibnd_find_node_dr(ibnd_fabric_t *fabric, char *dr_str)
+{
+	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
+	int i = 0;
+	ibnd_node_t *rc = f->fabric.from_node;
+	ib_dr_path_t path;
+
+	if (str2drpath(&path, dr_str, 0, 0) == -1) {
+		return (NULL);
+	}
+
+	for (i = 0; i <= path.cnt; i++) {
+		ibnd_port_t *remote_port = NULL;
+		if (path.p[i] == 0)
+			continue;
+		if (!rc->ports)
+			return (NULL);
+
+		remote_port = rc->ports[path.p[i]]->remoteport;
+		if (!remote_port)
+			return (NULL);
+
+		rc = remote_port->node;
+	}
+
+	return (rc);
+}
+
+static void
+add_to_nodeguid_hash(struct ibnd_node *node, struct ibnd_node *hash[])
+{
+	int hash_idx = HASHGUID(node->node.guid) % HTSZ;
+
+	node->htnext = hash[hash_idx];
+	hash[hash_idx] = node;
+}
+
+static void
+add_to_portguid_hash(struct ibnd_port *port, struct ibnd_port *hash[])
+{
+	int hash_idx = HASHGUID(port->port.guid) % HTSZ;
+
+	port->htnext = hash[hash_idx];
+	hash[hash_idx] = port;
+}
+
+static void
+add_to_type_list(struct ibnd_node*node, struct ibnd_fabric *fabric)
+{
+	switch (node->node.type) {
+		case IB_NODE_CA:
+			node->type_next = fabric->ch_adapters;
+			fabric->ch_adapters = node;
+			break;
+		case IB_NODE_SWITCH:
+			node->type_next = fabric->switches;
+			fabric->switches = node;
+			break;
+		case IB_NODE_ROUTER:
+			node->type_next = fabric->routers;
+			fabric->routers = node;
+			break;
+	}
+}
+
+static void
+add_to_nodedist(struct ibnd_node *node, struct ibnd_fabric *fabric)
+{
+	int dist = node->node.dist;
+	if (node->node.type != IB_NODE_SWITCH)
+			dist = MAXHOPS; 	/* special Ca list */
+
+	node->dnext = fabric->nodesdist[dist];
+	fabric->nodesdist[dist] = node;
+}
+
+
+static struct ibnd_node *
+create_node(struct ibnd_fabric *fabric, struct ibnd_node *temp, ib_portid_t *path, int dist)
+{
+	struct ibnd_node *node;
+
+	node = malloc(sizeof(*node));
+	if (!node) {
+		IBPANIC("OOM: node creation failed\n");
+		return NULL;
+	}
+
+	memcpy(node, temp, sizeof(*node));
+	node->node.dist = dist;
+	node->node.path_portid = *path;
+	node->node.fabric = (ibnd_fabric_t *)fabric;
+
+	add_to_nodeguid_hash(node, fabric->nodestbl);
+
+	/* add this to the all nodes list */
+	node->node.next = fabric->fabric.nodes;
+	fabric->fabric.nodes = (ibnd_node_t *)node;
+
+	add_to_type_list(node, fabric);
+	add_to_nodedist(node, fabric);
+
+	return node;
+}
+
+static struct ibnd_port *
+find_existing_port_node(struct ibnd_node *node, struct ibnd_port *port)
+{
+	if (port->port.portnum > node->node.numports || node->node.ports == NULL )
+		return (NULL);
+
+	return (CONV_PORT_INTERNAL(node->node.ports[port->port.portnum]));
+}
+
+static struct ibnd_port *
+add_port_to_node(struct ibnd_fabric *fabric, struct ibnd_node *node, struct ibnd_port *temp)
+{
+	struct ibnd_port *port;
+
+	port = malloc(sizeof(*port));
+	if (!port)
+		return NULL;
+
+	memcpy(port, temp, sizeof(*port));
+	port->port.node = (ibnd_node_t *)node;
+	port->port.ext_portnum = 0;
+
+	if (node->node.ports == NULL) {
+		node->node.ports = calloc(sizeof(*node->node.ports), node->node.numports + 1);
+		if (!node->node.ports) {
+			IBND_ERROR("Failed to allocate the ports array\n");
+			return (NULL);
+		}
+	}
+
+	node->node.ports[temp->port.portnum] = (ibnd_port_t *)port;
+
+	add_to_portguid_hash(port, fabric->portstbl);
+	return port;
+}
+
+static void
+link_ports(struct ibnd_node *node, struct ibnd_port *port,
+		struct ibnd_node *remotenode, struct ibnd_port *remoteport)
+{
+	IBND_DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u\n",
+		node->node.guid, node, port, port->port.portnum,
+		remotenode->node.guid, remotenode,
+		remoteport, remoteport->port.portnum);
+	if (port->port.remoteport)
+		port->port.remoteport->remoteport = NULL;
+	if (remoteport->port.remoteport)
+		remoteport->port.remoteport->remoteport = NULL;
+	port->port.remoteport = (ibnd_port_t *)remoteport;
+	remoteport->port.remoteport = (ibnd_port_t *)port;
+}
+
+static int
+get_remote_node(struct ibnd_fabric *fabric, struct ibnd_node *node, struct ibnd_port *port, ib_portid_t *path,
+		int portnum, int dist)
+{
+	struct ibnd_node node_buf;
+	struct ibnd_port port_buf;
+	struct ibnd_node *remotenode, *oldnode;
+	struct ibnd_port *remoteport, *oldport;
+
+	memset(&node_buf, 0, sizeof(node_buf));
+	memset(&port_buf, 0, sizeof(port_buf));
+
+	IBND_DEBUG("handle node %p port %p:%d dist %d\n", node, port, portnum, dist);
+
+	if (mad_get_field(port->port.info, 0, IB_PORT_PHYS_STATE_F)
+			!= IB_PORT_PHYS_STATE_LINKUP)
+		return -1;
+
+	if (extend_dpath(fabric, &path->drpath, portnum) < 0)
+		return -1;
+
+	if (query_node(fabric, &node_buf, &port_buf, path)) {
+		IBWARN("NodeInfo on %s failed, skipping port",
+			portid2str(path));
+		path->drpath.cnt--;	/* restore path */
+		return -1;
+	}
+
+	oldnode = find_existing_node(fabric, &node_buf);
+	if (oldnode)
+		remotenode = oldnode;
+	else if (!(remotenode = create_node(fabric, &node_buf, path, dist + 1)))
+		IBPANIC("no memory");
+
+	oldport = find_existing_port_node(remotenode, &port_buf);
+	if (oldport) {
+		remoteport = oldport;
+	} else if (!(remoteport = add_port_to_node(fabric, remotenode, &port_buf)))
+		IBPANIC("no memory");
+
+	dump_endnode(path, oldnode ? "known remote" : "new remote",
+			remotenode, remoteport);
+
+	link_ports(node, port, remotenode, remoteport);
+
+	path->drpath.cnt--;	/* restore path */
+	return 0;
+}
+
+static void *
+ibnd_init_port(char *dev_name, int dev_port)
+{
+	int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS};
+
+	/* Crank up the mad lib */
+	return (mad_rpc_open_port(dev_name, dev_port, mgmt_classes, 2));
+}
+
+ibnd_fabric_t *
+ibnd_discover_fabric(char *dev_name, int dev_port, int timeout_ms,
+			ib_portid_t *from, int hops)
+{
+	struct ibnd_fabric *fabric = NULL;
+	ib_portid_t my_portid = {0};
+	struct ibnd_node node_buf;
+	struct ibnd_port port_buf;
+	struct ibnd_node *node;
+	struct ibnd_port *port;
+	int i;
+	int dist = 0;
+	ib_portid_t *path;
+	int max_hops = MAXHOPS-1; /* default find everything */
+
+	/* if not everything how much? */
+	if (hops >= 0) {
+		max_hops = hops;
+	}
+
+	/* If not specified start from "my" port */
+	if (!from) {
+		from = &my_portid;
+	}
+
+	fabric = malloc(sizeof(*fabric));
+
+	if (!fabric) {
+		IBPANIC("OOM: failed to malloc ibnd_fabric_t\n");
+		return (NULL);
+	}
+
+	memset(fabric, 0, sizeof(*fabric));
+
+	fabric->ibmad_port = ibnd_init_port(dev_name, dev_port);
+	if (!fabric->ibmad_port) {
+		IBPANIC("OOM: failed to open \"%s\" port %d\n",
+			dev_name, dev_port);
+		goto error;
+	}
+
+	IBND_DEBUG("from %s\n", portid2str(from));
+
+	memset(&node_buf, 0, sizeof(node_buf));
+	memset(&port_buf, 0, sizeof(port_buf));
+
+	if (query_node(fabric, &node_buf, &port_buf, from)) {
+		IBWARN("can't reach node %s\n", portid2str(from));
+		goto error;
+	}
+
+	node = create_node(fabric, &node_buf, from, 0);
+	if (!node)
+		goto error;
+
+	fabric->fabric.from_node = (ibnd_node_t *)node;
+
+	port = add_port_to_node(fabric, node, &port_buf);
+	if (!port)
+		IBPANIC("out of memory");
+
+	if (node->node.type != IB_NODE_SWITCH &&
+	    get_remote_node(fabric, node, port, from,
+				mad_get_field(node->node.info, 0, IB_NODE_LOCAL_PORT_F),
+				0) < 0)
+		return ((ibnd_fabric_t *)fabric);
+
+	for (dist = 0; dist <= max_hops; dist++) {
+
+		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
+
+			path = &node->node.path_portid;
+
+			IBND_DEBUG("dist %d node %p\n", dist, node);
+			dump_endnode(path, "processing", node, port);
+
+			for (i = 1; i <= node->node.numports; i++) {
+				if (i == mad_get_field(node->node.info, 0,
+							IB_NODE_LOCAL_PORT_F))
+					continue;
+
+				if (get_port_info(fabric, &port_buf, i, path)) {
+					IBWARN("can't reach node %s port %d", portid2str(path), i);
+					continue;
+				}
+
+				port = find_existing_port_node(node, &port_buf);
+				if (port)
+					continue;
+
+				port = add_port_to_node(fabric, node, &port_buf);
+				if (!port)
+					IBPANIC("out of memory");
+
+				/* If switch, set port GUID to node port GUID */
+				if (node->node.type == IB_NODE_SWITCH) {
+					port->port.guid = mad_get_field64(node->node.info,
+								0, IB_NODE_PORT_GUID_F);
+				}
+
+				get_remote_node(fabric, node, port, path, i, dist);
+			}
+		}
+	}
+
+	fabric->fabric.chassis = group_nodes(fabric);
+
+	return ((ibnd_fabric_t *)fabric);
+error:
+	free(fabric);
+	return (NULL);
+}
+
+static void
+destroy_node(struct ibnd_node *node)
+{
+	int p = 0;
+
+	for (p = 0; p <= node->node.numports; p++) {
+		free(node->node.ports[p]);
+	}
+	free(node->node.ports);
+	free(node);
+}
+
+void
+ibnd_destroy_fabric(ibnd_fabric_t *fabric)
+{
+	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
+	int dist = 0;
+	struct ibnd_node *node = NULL;
+	struct ibnd_node *next = NULL;
+	ibnd_chassis_t *ch, *ch_next;
+
+	ch = f->first_chassis;
+	while (ch) {
+		ch_next = ch->next;
+		free(ch);
+		ch = ch_next;
+	}
+	for (dist = 0; dist <= MAXHOPS; dist++) {
+		node = f->nodesdist[dist];
+		while (node) {
+			next = node->dnext;
+			destroy_node(node);
+			node = next;
+		}
+	}
+	if (f->ibmad_port)
+		mad_rpc_close_port(f->ibmad_port);
+	free(f);
+}
+
+void
+ibnd_debug(int i)
+{
+	if (i) {
+		ibdebug++;
+		madrpc_show_errors(1);
+		umad_debug(i);
+	} else {
+		ibdebug = 0;
+		madrpc_show_errors(0);
+		umad_debug(0);
+	}
+}
+
+void
+ibnd_show_progress(int i)
+{
+	show_progress = i;
+}
+
+void
+ibnd_iter_nodes(ibnd_fabric_t *fabric,
+		ibnd_iter_node_func_t func,
+		void *user_data)
+{
+	ibnd_node_t *cur = NULL;
+
+	for (cur = fabric->nodes; cur; cur = cur->next) {
+		func(cur, user_data);
+	}
+}
+
+
+void
+ibnd_iter_nodes_type(ibnd_fabric_t *fabric,
+		ibnd_iter_node_func_t func,
+		int node_type,
+		void *user_data)
+{
+	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
+	struct ibnd_node *list = NULL;
+	struct ibnd_node *cur = NULL;
+
+	switch (node_type) {
+		case IB_NODE_SWITCH:
+			list = f->switches;
+			break;
+		case IB_NODE_CA:
+			list = f->ch_adapters;
+			break;
+		case IB_NODE_ROUTER:
+			list = f->routers;
+			break;
+		default:
+			IBND_DEBUG("Invalid node_type specified %d\n", node_type);
+			break;
+	}
+
+	for (cur = list; cur; cur = cur->type_next) {
+		func((ibnd_node_t *)cur, user_data);
+	}
+}
+
diff --git a/infiniband-diags/libibnetdisc/src/internal.h b/infiniband-diags/libibnetdisc/src/internal.h
new file mode 100644
index 0000000..afed25e
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/src/internal.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2008 Lawrence Livermore National Laboratory
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/** =========================================================================
+ * Define the internal data structures.
+ */
+
+#ifndef _INTERNAL_H_
+#define _INTERNAL_H_
+
+#include <infiniband/ibnetdisc.h>
+
+#define MAXHOPS		63
+
+#define	IBND_DEBUG(fmt, ...) \
+	if (ibdebug) { \
+		printf("%s:%u; " fmt, __FILE__, __LINE__, ## __VA_ARGS__); \
+	}
+#define	IBND_ERROR(fmt, ...) \
+		fprintf(stderr, "%s:%u; " fmt, __FILE__, __LINE__, ## __VA_ARGS__)
+
+struct ibnd_node {
+	/* This member MUST BE FIRST */
+	ibnd_node_t node;
+
+	/* internal use only */
+	unsigned char ch_found;
+	struct ibnd_node *htnext; /* hash table list */
+	struct ibnd_node *dnext; /* nodesdist next */
+	struct ibnd_node *type_next; /* next based on type */
+};
+#define CONV_NODE_INTERNAL(node) ((struct ibnd_node *)node)
+
+struct ibnd_port {
+	/* This member MUST BE FIRST */
+	ibnd_port_t port;
+
+	/* internal use only */
+	struct ibnd_port *htnext;
+};
+#define CONV_PORT_INTERNAL(port) ((struct ibnd_port *)port)
+
+/* HASH table defines */
+#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))
+#define HTSZ 137
+
+struct ibnd_fabric {
+	/* This member MUST BE FIRST */
+	ibnd_fabric_t fabric;
+
+	/* internal use only */
+	void *ibmad_port;
+	struct ibnd_node *nodestbl[HTSZ];
+	struct ibnd_port *portstbl[HTSZ];
+	struct ibnd_node *nodesdist[MAXHOPS+1];
+	ibnd_chassis_t *first_chassis;
+	ibnd_chassis_t *current_chassis;
+	ibnd_chassis_t *last_chassis;
+	struct ibnd_node *switches;
+	struct ibnd_node *ch_adapters;
+	struct ibnd_node *routers;
+};
+#define CONV_FABRIC_INTERNAL(fabric) ((struct ibnd_fabric *)fabric)
+
+#endif /* _INTERNAL_H_ */
diff --git a/infiniband-diags/libibnetdisc/src/libibnetdisc.map b/infiniband-diags/libibnetdisc/src/libibnetdisc.map
new file mode 100644
index 0000000..5e8c315
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/src/libibnetdisc.map
@@ -0,0 +1,27 @@
+IBNETDISC_1.0 {
+	global:
+		ibnd_debug;
+		ibnd_show_progress;
+		ibnd_discover_fabric;
+		ibnd_cache_fabric;
+		ibnd_read_fabric;
+		ibnd_destroy_fabric;
+		ibnd_find_node_guid;
+		ibnd_update_node;
+		ibnd_find_node_dr;
+		ibnd_linkwidth_str;
+		ibnd_linkspeed_str;
+		ibnd_node_type_str;
+		ibnd_node_type_str_short;
+		ibnd_is_xsigo_guid;
+		ibnd_is_xsigo_tca;
+		ibnd_is_xsigo_hca;
+		ibnd_get_chassis_guid;
+		ibnd_get_chassis_type;
+		ibnd_get_chassis_slot_str;
+		ibnd_linkstate_str;
+		ibnd_physstate_str;
+		ibnd_iter_nodes;
+		ibnd_iter_nodes_type;
+	local: *;
+};
diff --git a/infiniband-diags/libibnetdisc/test/testleaks.c b/infiniband-diags/libibnetdisc/test/testleaks.c
new file mode 100644
index 0000000..1fabaac
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/test/testleaks.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
+ * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <infiniband/complib/cl_nodenamemap.h>
+#include <infiniband/ibnetdisc.h>
+
+char *argv0 = "iblinkinfotest";
+static FILE *f;
+
+static int timeout_ms = 500;
+
+void
+usage(void)
+{
+	fprintf(stderr,
+		"Usage: %s [-hclp -S <guid> -D <direct route> -C <ca_name> -P <ca_port>]\n"
+		"   Report link speed and connection for each port of each switch which is active\n"
+		"   -h This help message\n"
+		"   -i <iters> Number of iterations to run (default -1 == infinate)\n"
+
+		"   -S <guid> output only the node specified by guid\n"
+		"   -D <direct route> print only node specified by <direct route>\n"
+		"   -f <dr_path> specify node to start \"from\"\n"
+		"   -n <hops> Number of hops to include away from specified node\n"
+
+		"   -t <timeout_ms> timeout for any single fabric query\n"
+		"   -s show errors\n"
+
+		"   -C <ca_name> use selected Channel Adaptor name for queries\n"
+		"   -P <ca_port> use selected channel adaptor port for queries\n"
+		"   --debug print debug messages\n"
+		,
+			argv0);
+	exit(-1);
+}
+
+int
+main(int argc, char **argv)
+{
+	char *ca = 0;
+	int ca_port = 0;
+	ibnd_fabric_t *fabric = NULL;
+	uint64_t guid = 0;
+	char *dr_path = NULL;
+	char *from = NULL;
+	int hops = 0;
+	ib_portid_t port_id;
+	int iters = -1;
+
+	static char const str_opts[] = "S:D:n:C:P:t:shuf:i:";
+	static const struct option long_opts[] = {
+		{ "S", 1, 0, 'S'},
+		{ "D", 1, 0, 'D'},
+		{ "num-hops", 1, 0, 'n'},
+		{ "ca-name", 1, 0, 'C'},
+		{ "ca-port", 1, 0, 'P'},
+		{ "timeout", 1, 0, 't'},
+		{ "show", 0, 0, 's'},
+		{ "help", 0, 0, 'h'},
+		{ "usage", 0, 0, 'u'},
+		{ "debug", 0, 0, 2},
+		{ "from", 1, 0, 'f'},
+		{ "iters", 1, 0, 'i'},
+		{ }
+	};
+
+	f = stdout;
+
+	argv0 = argv[0];
+
+	while (1) {
+		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
+		if ( ch == -1 )
+			break;
+		switch(ch) {
+		case 2:
+			ibnd_debug(1);
+			break;
+		case 'f':
+			from = strdup(optarg);
+			break;
+		case 'C':
+			ca = strdup(optarg);
+			break;
+		case 'P':
+			ca_port = strtoul(optarg, 0, 0);
+			break;
+		case 'D':
+			dr_path = strdup(optarg);
+			break;
+		case 'n':
+			hops = (int)strtol(optarg, NULL, 0);
+			break;
+		case 'i':
+			iters = (int)strtol(optarg, NULL, 0);
+			break;
+		case 't':
+			timeout_ms = strtoul(optarg, 0, 0);
+			break;
+		case 'S':
+			guid = (uint64_t)strtoull(optarg, 0, 0);
+			break;
+		default:
+			usage();
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	while (iters == -1 || iters-- > 0) {
+		if (from) {
+			/* only scan part of the fabric */
+			str2drpath(&(port_id.drpath), from, 0, 0);
+			if ((fabric = ibnd_discover_fabric(ca, ca_port, timeout_ms,
+					&port_id, hops)) == NULL) {
+				fprintf(stderr, "discover failed\n");
+				exit(1);
+			}
+			guid = 0;
+		} else {
+			if ((fabric = ibnd_discover_fabric(ca, ca_port, timeout_ms, NULL, -1)) == NULL) {
+				fprintf(stderr, "discover failed\n");
+				exit(1);
+			}
+		}
+
+		ibnd_destroy_fabric(fabric);
+	}
+
+	exit(0);
+}
-- 
1.5.4.5




More information about the general mailing list