***SPAM*** Re: [ofa-general] [PATCH V2 1/3] Create a new library libibnetdisc
Al Chu
chu11 at llnl.gov
Tue Dec 23 10:29:02 PST 2008
Hey Ira,
Tiny comment below:
On Thu, 2008-12-11 at 16:20 -0800, Ira Weiny wrote:
> >From d615162e547f3a2b2d1acd8c79c24ee691c96c95 Mon Sep 17 00:00:00 2001
> From: Ira Weiny <weiny2 at llnl.gov>
> Date: Wed, 26 Nov 2008 12:54:47 -0800
> 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 | 31 +-
> infiniband-diags/libibnetdisc/Makefile.am | 66 ++
> .../libibnetdisc/include/infiniband/ibnetdisc.h | 276 ++++++
> 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_linkspeed_str.3 | 2 +
> .../libibnetdisc/man/ibnd_linkstate_str.3 | 2 +
> .../libibnetdisc/man/ibnd_linkwidth_str.3 | 26 +
> .../libibnetdisc/man/ibnd_node_type_str.3 | 2 +
> .../libibnetdisc/man/ibnd_node_type_str_short.3 | 2 +
> .../libibnetdisc/man/ibnd_physstate_str.3 | 2 +
> .../libibnetdisc/man/ibnd_show_progress.3 | 2 +
> .../libibnetdisc/man/ibnd_update_node.3 | 21 +
> infiniband-diags/libibnetdisc/src/chassis.c | 818 ++++++++++++++++++
> infiniband-diags/libibnetdisc/src/chassis.h | 85 ++
> infiniband-diags/libibnetdisc/src/ibnetdisc.c | 872 ++++++++++++++++++++
> infiniband-diags/libibnetdisc/src/internal.h | 82 ++
> infiniband-diags/libibnetdisc/src/libibnetdisc.map | 27 +
> .../libibnetdisc/test/iblinkinfotest.c | 395 +++++++++
> infiniband-diags/libibnetdisc/test/ibnetdisctest.c | 675 +++++++++++++++
> infiniband-diags/libibnetdisc/test/testleaks.c | 268 ++++++
> 28 files changed, 3769 insertions(+), 1 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_linkspeed_str.3
> create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_linkstate_str.3
> create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_linkwidth_str.3
> create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_node_type_str.3
> create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_node_type_str_short.3
> create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_physstate_str.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/iblinkinfotest.c
> create mode 100644 infiniband-diags/libibnetdisc/test/ibnetdisctest.c
> create mode 100644 infiniband-diags/libibnetdisc/test/testleaks.c
>
> diff --git a/infiniband-diags/Makefile.am b/infiniband-diags/Makefile.am
> index c22ba5e..8e8c3c1 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 5509fec..7c346e2 100644
> --- a/infiniband-diags/configure.in
> +++ b/infiniband-diags/configure.in
> @@ -145,6 +145,34 @@ IBSCRIPTPATH_TMP2="`echo $IBSCRIPTPATH_TMP1 | sed 's/^NONE/$ac_default_prefix/'`
> IBSCRIPTPATH="`eval echo $IBSCRIPTPATH_TMP2`"
> AC_SUBST(IBSCRIPTPATH)
>
> +dnl Begin libibnetdisc stuff
> +AC_CHECK_HEADERS([stdint.h stdlib.h string.h syslog.h unistd.h])
> +AC_CHECK_FUNCS([strrchr strtoul strtoull])
> +
> +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)
> +AC_DEFINE_UNQUOTED(API_VERSION,
> + ["$ibnetdisc_api_version"],
> + [The API version of this library])
> +
> +AC_MSG_CHECKING(for --enable-test-utils)
> +AC_ARG_ENABLE(test-utils,
> +[ --enable-test-utils build additional test utilities (default=no)],
> +[case "${enableval}" in
> + yes) tutils=yes ;;
> + no) tutils=no ;;
> + *) AC_MSG_ERROR(bad value ${enableval} for --enable-test-utils) ;;
> +esac],[tutils=no])
> +AM_CONDITIONAL(ENABLE_TEST_UTILS, test x$tutils = xyes)
> +AC_MSG_RESULT(${tutils=no})
> +
> +dnl End libibnetdisc stuff
> +
> +
> AC_CONFIG_FILES([\
> Makefile \
> infiniband-diags.spec \
> @@ -165,6 +193,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..7b478b1
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/Makefile.am
> @@ -0,0 +1,66 @@
> +
> +#SUBDIRS = .
> +
> +INCLUDES = -I$(srcdir)/include -I$(includedir) -I$(includedir)/infiniband
> +
> +lib_LTLIBRARIES = libibnetdisc.la
> +sbin_PROGRAMS =
> +
> +if ENABLE_TEST_UTILS
> +sbin_PROGRAMS += test/ibnetdisctest \
> + test/iblinkinfotest \
> + 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) \
> + -losmcomp -libmad
> +libibnetdisc_la_DEPENDENCIES = $(srcdir)/src/libibnetdisc.map
> +
> +libibnetdiscincludedir = $(includedir)/infiniband
> +
> +test_ibnetdisctest_SOURCES = test/ibnetdisctest.c
> +test_ibnetdisctest_CFLAGS = -Wall $(DBGFLAGS)
> +test_ibnetdisctest_LDFLAGS = -Wl,--rpath -Wl,$(libdir) \
> + -libcommon -libnetdisc
> +
> +test_iblinkinfotest_SOURCES = test/iblinkinfotest.c
> +test_iblinkinfotest_CFLAGS = -Wall $(DBGFLAGS)
> +test_iblinkinfotest_LDFLAGS = -Wl,--rpath -Wl,$(libdir) \
> + -libcommon -libnetdisc
> +
> +test_testleaks_SOURCES = test/testleaks.c
> +test_testleaks_CFLAGS = -Wall $(DBGFLAGS)
> +test_testleaks_LDFLAGS = -Wl,--rpath -Wl,$(libdir) \
> + -libcommon -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_linkspeed_str.3 \
> + man/ibnd_linkstate_str.3 \
> + man/ibnd_linkwidth_str.3 \
> + man/ibnd_node_type_str.3 \
> + man/ibnd_physstate_str.3 \
> + man/ibnd_update_node.3 \
> + man/ibnd_show_progress.3
> +
> +EXTRA_DIST = libibnetdisc.spec.in libibnetdisc.spec \
> + $(srcdir)/src/libibnetdisc.map libibnetdisc.ver autogen.sh
> +
> diff --git a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
> new file mode 100644
> index 0000000..cdee2bd
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
> @@ -0,0 +1,276 @@
> +/*
> + * 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>
> +
> +#define MAXHOPS 63
> +
> +/* HASH table defines */
> +#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))
> +#define HTSZ 137
> +
> +#define IBND_DEBUG(str, args...) \
> + if (ibdebug) printf("%s:%d; "str, __FILE__, __LINE__, ##args)
> +#define IBND_ERROR(str, args...) \
> + fprintf(stderr, "%s:%d; "str, __FILE__, __LINE__, ##args)
I believe the "args ..." and "##args" are only for gcc. Not sure how
much this portability issue matters for OFED. Personally, I always do
the:
#define MYDEBUG(x) printf x
MYDEBUG(("lala: %s", somestrvar));
trick.
Al
> +/** =========================================================================
> + * ENUM definitions
> + */
> +typedef enum {
> + IBND_CA_NODE = 1,
> + IBND_SWITCH_NODE = 2,
> + IBND_ROUTER_NODE = 3
> +} ibnd_node_type_t;
> +
> +typedef enum {
> + IBND_LINK_DOWN = 1,
> + IBND_LINK_INIT = 2,
> + IBND_LINK_ARMED = 3,
> + IBND_LINK_ACTIVE = 4
> +} ibnd_link_state_t;
> +
> +/** =========================================================================
> + * Node
> + */
> +typedef struct switch_info {
> + int smaenhsp0;
> +} ibnd_switch_info_t;
> +
> +typedef struct node_info {
> + int base_ver;
> + int class_ver;
> + int type;
> + int numports;
> + uint64_t sysimgguid;
> + uint64_t nodeguid;
> + uint64_t nodeportguid;
> + uint16_t partition_cap;
> + uint32_t devid;
> + uint32_t revision;
> + int localport;
> + uint32_t vendid;
> +} ibnd_node_info_t;
> +
> +struct ib_fabric; /* forward declare */
> +struct chassis; /* forward declare */
> +struct port; /* forward declare */
> +
> +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;
> + ibnd_switch_info_t sw_info;
> + ibnd_node_info_t info;
> + char nodedesc[64];
> + 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_info {
> + int lid;
> + int smlid;
> + int link_speed_supported;
> + int link_speed_enabled;
> + int link_speed_active;
> + int link_state;
> + int phys_state;
> + int link_down_def_state;
> + int mkey_prot_bits;
> + int lmc;
> + int neighbor_mtu;
> + int smsl;
> + int init_type;
> + int vl_capability;
> + int vl_high_limit;
> + int vl_arb_high_cap;
> + int vl_arb_low_cap;
> + int init_reply;
> + int mtu_cap;
> + int vl_stall_count;
> + int hoq_lifetime;
> + int oper_vls;
> + int partition_enforce_in;
> + int partition_enforce_out;
> + int filter_raw_in;
> + int filter_raw_out;
> + int mkey_violations;
> + int pkey_violations;
> + int qkey_violations;
> + int guid_capabilities;
> + int client_rereg;
> + int subnet_timeout;
> + int response_time_val;
> + int local_phys_error;
> + int overrun_error;
> + int max_credit_hint;
> + uint32_t link_round_trip;
> + int local_port;
> + int link_width_supported;
> + int link_width_enabled;
> + int link_width_active;
> + int diag_code;
> + int mkey_lease;
> + uint32_t capability_mask;
> + uint64_t mkey;
> + uint64_t gid_prefix;
> +} ibnd_port_info_t;
> +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 */
> + ibnd_port_info_t info;
> + struct port *remoteport; /* null if SMA, or does not exist */
> +} ibnd_port_t;
> +
> +
> +/** =========================================================================
> + * Chassis data
> + */
> +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 mutiple 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,
> + ibnd_node_type_t node_type,
> + void *user_data);
> +
> +/** =========================================================================
> + * Str convert functions
> + */
> +char *ibnd_linkwidth_str(int link_width);
> +char *ibnd_linkstate_str(int link_state);
> +char *ibnd_physstate_str(int phys_state);
> +const char *ibnd_node_type_str(ibnd_node_t *node);
> +const char *ibnd_node_type_str_short(ibnd_node_t *node);
> +char *ibnd_linkspeed_str(int link_speed, int data_rate);
> + /* if data_rate == 0 use "SDR", "DDR", etc. */
> + /* if data_rate == 1 use "2.5 Gbps", "5.0 Gbps", etc. */
> +
> +/** =========================================================================
> + * 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..878547c
> --- /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_find_nodes.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_linkspeed_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_linkspeed_str.3
> new file mode 100644
> index 0000000..128cd3e
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_linkspeed_str.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_LINKSPEED_STR 3 "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_linkwidth_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_linkstate_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_linkstate_str.3
> new file mode 100644
> index 0000000..2fa9189
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_linkstate_str.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_LINKSTATE_STR 3 "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_linkwidth_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_linkwidth_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_linkwidth_str.3
> new file mode 100644
> index 0000000..2cd4f0a
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_linkwidth_str.3
> @@ -0,0 +1,26 @@
> +.TH IBND_LINKWIDTH_STR 3 "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.SH "NAME"
> +ibnd_linkwidth_str, ibnd_linkspeed_str, ibnd_linkstate_str, ibnd_physstate_str, ibnd_node_type_str \- prety string functions.
> +
> +.SH "SYNOPSIS"
> +.nf
> +.B #include <infiniband/ibnetdisc.h>
> +.sp
> +.BI
> +.BI "char *ibnd_linkwidth_str(int link_width)"
> +.BI "char *ibnd_linkspeed_str(int link_speed)"
> +.BI "char *ibnd_linkstate_str(int link_state)"
> +.BI "char *ibnd_physstate_str(int phys_state)"
> +.BI "const char *ibnd_node_type_str(ibnd_node_t *node)"
> +.BI "const char *ibnd_node_type_str_short(ibnd_node_t *node)"
> +
> +.SH "DESCRIPTION"
> +Return user readable strings for the values given.
> +
> +.BI "const char *ibnd_node_type_str_short(ibnd_node_t *node)"
> +Returns a shorter abbreviated version of the string.
> +
> +
> +.SH "AUTHORS"
> +.TP
> +Ira Weiny <weiny2 at llnl.gov>
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_node_type_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_node_type_str.3
> new file mode 100644
> index 0000000..77dbf07
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_node_type_str.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_NODE_TYPE_STR 3 "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_linkwidth_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_node_type_str_short.3 b/infiniband-diags/libibnetdisc/man/ibnd_node_type_str_short.3
> new file mode 100644
> index 0000000..62feb6e
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_node_type_str_short.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_NODE_TYPE_STR_SHORT 3 "Aug 05, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_linkwidth_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_physstate_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_physstate_str.3
> new file mode 100644
> index 0000000..aeeaeb7
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_physstate_str.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_PHYSSTATE_STR 3 "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_physstate_str.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..41f325e
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/chassis.c
> @@ -0,0 +1,818 @@
> +/*
> + * 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 <stdint.h>
> +#include <stdlib.h>
> +#include <inttypes.h>
> +
> +#include <infiniband/common.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 (node->info.vendid != 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 (node->info.vendid != 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)
> +{
> + if (!is_xsigo_ca(node->info.sysimgguid)) {
> + /* Byte 3 is NodeType and byte 4 is PortType */
> + /* If NodeType is 1 (switch), PortType is masked */
> + if (is_xsigo_switch(node->info.sysimgguid))
> + return node->info.sysimgguid & 0xffffffff00ffffffULL;
> + else
> + return node->info.sysimgguid;
> + } else {
> + if (!node->ports || !node->ports[1])
> + return (0);
> +
> + /* Is there a peer port ? */
> + if (!node->ports[1]->remoteport)
> + return node->info.sysimgguid;
> +
> + /* If peer port is Leaf 1, use its chassis GUID */
> + if (is_xsigo_leafone(node->ports[1]->remoteport->node->info.sysimgguid))
> + return node->ports[1]->remoteport->node->info.sysimgguid &
> + 0xffffffff00ffffffULL;
> + else
> + return node->info.sysimgguid;
> + }
> +}
> +
> +static uint64_t get_chassisguid(ibnd_node_t *node)
> +{
> + if (node->info.vendid == TS_VENDOR_ID || node->info.vendid == SS_VENDOR_ID)
> + return topspin_chassisguid(node->info.sysimgguid);
> + else if (node->info.vendid == XS_VENDOR_ID || ibnd_is_xsigo_guid(node->info.sysimgguid))
> + return xsigo_chassisguid(node);
> + else
> + return node->info.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)
> +{
> + return (n->node.info.devid == VTR_DEVID_IB_FC_ROUTER ||
> + n->node.info.devid == VTR_DEVID_IB_IP_ROUTER);
> +}
> +
> +static int is_spine_9096(struct ibnd_node *n)
> +{
> + return (n->node.info.devid == VTR_DEVID_SFB4 ||
> + n->node.info.devid == VTR_DEVID_SFB4_DDR);
> +}
> +
> +static int is_spine_9288(struct ibnd_node *n)
> +{
> + return (n->node.info.devid == VTR_DEVID_SFB12 ||
> + n->node.info.devid == VTR_DEVID_SFB12_DDR);
> +}
> +
> +static int is_spine_2004(struct ibnd_node *n)
> +{
> + return (n->node.info.devid == VTR_DEVID_SFB2004);
> +}
> +
> +static int is_spine_2012(struct ibnd_node *n)
> +{
> + return (n->node.info.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)
> +{
> + return (n->node.info.devid == VTR_DEVID_SLB24 ||
> + n->node.info.devid == VTR_DEVID_SLB24_DDR ||
> + n->node.info.devid == VTR_DEVID_SRB2004);
> +}
> +
> +static int is_line_8(struct ibnd_node *n)
> +{
> + return (n->node.info.devid == VTR_DEVID_SLB8);
> +}
> +
> +static int is_line_2024(struct ibnd_node *n)
> +{
> + return (n->node.info.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.info.nodeguid);
> + }
> +}
> +
> +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->info.nodeguid % 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->info.nodeguid % 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->info.nodeguid);
> + }
> +}
> +
> +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->info.nodeguid);
> + }
> +}
> +
> +/* 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.info.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.info.numports; p++) {
> + port = node->node.ports[p];
> + if (!port || !port->remoteport)
> + continue;
> + remnode = CONV_NODE_INTERNAL(port->remoteport->node);
> + if (remnode->node.info.type != IBND_SWITCH_NODE) {
> + 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.info.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.info.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->info.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->info.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->info.nodeguid - 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.info.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 (node->node.info.vendid == 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 (node->node.info.vendid != 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 (node->node.info.vendid == VTR_VENDOR_ID)
> + continue;
> + if (node->node.info.sysimgguid) {
> + 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 (node->node.info.vendid == VTR_VENDOR_ID)
> + continue;
> + if (node->node.info.sysimgguid) {
> + 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..64e4ece
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
> @@ -0,0 +1,872 @@
> +/*
> + * 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/common.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;
> +
> +static char *linkwidth_str[] = {
> + "??",
> + "1x",
> + "4x",
> + "??",
> + "8x",
> + "??",
> + "??",
> + "??",
> + "12x"
> +};
> +
> +static char *linkspeed_str[] = {
> + "???",
> + "SDR",
> + "DDR",
> + "???",
> + "QDR"
> +};
> +
> +static char *linkspeed_datarate_str[] = {
> + "???",
> + "2.5 Gbps",
> + "5.0 Gbps",
> + "???",
> + "10.0 Gbps"
> +};
> +
> +static char *linkstate_str[] = {
> + "No State",
> + "Down",
> + "Init",
> + "Armed",
> + "Active"
> +};
> +
> +static char *physstate_str[] = {
> + "No State",
> + "Sleep",
> + "Polling",
> + "Disabled",
> + "PortConfigTraining",
> + "LinkUp",
> + "LinkErrorRecovery",
> + "Phy Test"
> +};
> +
> +char *
> +ibnd_linkwidth_str(int link_width)
> +{
> + if (link_width > 8)
> + return linkwidth_str[0];
> + else
> + return linkwidth_str[link_width];
> +}
> +
> +char *
> +ibnd_linkspeed_str(int link_speed, int data_rate)
> +{
> + if (link_speed > 4)
> + return linkspeed_str[0];
> + else if (data_rate)
> + return linkspeed_datarate_str[link_speed];
> + else
> + return linkspeed_str[link_speed];
> +}
> +char *
> +ibnd_linkstate_str(int link_state)
> +{
> + if (link_state > 4)
> + return linkstate_str[0];
> + else
> + return linkstate_str[link_state];
> +}
> +
> +char *
> +ibnd_physstate_str(int phys_state)
> +{
> + if (phys_state > 7)
> + return physstate_str[0];
> + else
> + return physstate_str[phys_state];
> +}
> +
> +void
> +decode_port_info(void * rcv_buf, ibnd_port_info_t *pi)
> +{
> + mad_decode_field(rcv_buf, IB_PORT_LID_F, &pi->lid);
> + mad_decode_field(rcv_buf, IB_PORT_SMLID_F, &pi->smlid);
> +
> + mad_decode_field(rcv_buf, IB_PORT_LINK_SPEED_SUPPORTED_F, &pi->link_speed_supported);
> + mad_decode_field(rcv_buf, IB_PORT_LINK_SPEED_ENABLED_F, &pi->link_speed_enabled);
> + mad_decode_field(rcv_buf, IB_PORT_LINK_SPEED_ACTIVE_F, &pi->link_speed_active);
> +
> + mad_decode_field(rcv_buf, IB_PORT_LOCAL_PORT_F, &pi->local_port);
> + mad_decode_field(rcv_buf, IB_PORT_LINK_WIDTH_SUPPORTED_F, &pi->link_width_supported);
> + mad_decode_field(rcv_buf, IB_PORT_LINK_WIDTH_ENABLED_F, &pi->link_width_enabled);
> +
> + mad_decode_field(rcv_buf, IB_PORT_LINK_WIDTH_ACTIVE_F, &pi->link_width_active);
> +
> + mad_decode_field(rcv_buf, IB_PORT_DIAG_F, &pi->diag_code);
> + mad_decode_field(rcv_buf, IB_PORT_MKEY_LEASE_F, &pi->mkey_lease);
> + mad_decode_field(rcv_buf, IB_PORT_CAPMASK_F, &pi->capability_mask);
> + mad_decode_field(rcv_buf, IB_PORT_MKEY_F, &pi->mkey);
> + mad_decode_field(rcv_buf, IB_PORT_GID_PREFIX_F, &pi->gid_prefix);
> +
> + mad_decode_field(rcv_buf, IB_PORT_STATE_F, &pi->link_state);
> + mad_decode_field(rcv_buf, IB_PORT_PHYS_STATE_F, &pi->phys_state);
> +
> + mad_decode_field(rcv_buf, IB_PORT_LINK_DOWN_DEF_F, &pi->link_down_def_state);
> + mad_decode_field(rcv_buf, IB_PORT_MKEY_PROT_BITS_F, &pi->mkey_prot_bits);
> +
> + mad_decode_field(rcv_buf, IB_PORT_LMC_F, &pi->lmc);
> + mad_decode_field(rcv_buf, IB_PORT_NEIGHBOR_MTU_F, &pi->neighbor_mtu);
> + mad_decode_field(rcv_buf, IB_PORT_SMSL_F, &pi->smsl);
> + mad_decode_field(rcv_buf, IB_PORT_INIT_TYPE_F, &pi->init_type);
> +
> + mad_decode_field(rcv_buf, IB_PORT_VL_CAP_F, &pi->vl_capability);
> + mad_decode_field(rcv_buf, IB_PORT_VL_HIGH_LIMIT_F, &pi->vl_high_limit);
> + mad_decode_field(rcv_buf, IB_PORT_VL_ARBITRATION_HIGH_CAP_F, &pi->vl_arb_high_cap);
> + mad_decode_field(rcv_buf, IB_PORT_VL_ARBITRATION_LOW_CAP_F, &pi->vl_arb_low_cap);
> +
> + mad_decode_field(rcv_buf, IB_PORT_INIT_TYPE_REPLY_F, &pi->init_reply);
> + mad_decode_field(rcv_buf, IB_PORT_MTU_CAP_F, &pi->mtu_cap);
> + mad_decode_field(rcv_buf, IB_PORT_VL_STALL_COUNT_F, &pi->vl_stall_count);
> + mad_decode_field(rcv_buf, IB_PORT_HOQ_LIFE_F, &pi->hoq_lifetime);
> + mad_decode_field(rcv_buf, IB_PORT_OPER_VLS_F, &pi->oper_vls);
> + mad_decode_field(rcv_buf, IB_PORT_PART_EN_INB_F, &pi->partition_enforce_in);
> + mad_decode_field(rcv_buf, IB_PORT_PART_EN_OUTB_F, &pi->partition_enforce_out);
> + mad_decode_field(rcv_buf, IB_PORT_FILTER_RAW_INB_F, &pi->filter_raw_in);
> + mad_decode_field(rcv_buf, IB_PORT_FILTER_RAW_OUTB_F, &pi->filter_raw_out);
> + mad_decode_field(rcv_buf, IB_PORT_MKEY_VIOL_F, &pi->mkey_violations);
> + mad_decode_field(rcv_buf, IB_PORT_PKEY_VIOL_F, &pi->pkey_violations);
> + mad_decode_field(rcv_buf, IB_PORT_QKEY_VIOL_F, &pi->qkey_violations);
> +
> + mad_decode_field(rcv_buf, IB_PORT_GUID_CAP_F, &pi->guid_capabilities);
> +
> + mad_decode_field(rcv_buf, IB_PORT_CLIENT_REREG_F, &pi->client_rereg);
> + mad_decode_field(rcv_buf, IB_PORT_SUBN_TIMEOUT_F, &pi->subnet_timeout);
> + mad_decode_field(rcv_buf, IB_PORT_RESP_TIME_VAL_F, &pi->response_time_val);
> + mad_decode_field(rcv_buf, IB_PORT_LOCAL_PHYS_ERR_F, &pi->local_phys_error);
> + mad_decode_field(rcv_buf, IB_PORT_OVERRUN_ERR_F, &pi->overrun_error);
> + mad_decode_field(rcv_buf, IB_PORT_MAX_CREDIT_HINT_F, &pi->max_credit_hint);
> + mad_decode_field(rcv_buf, IB_PORT_LINK_ROUND_TRIP_F, &pi->link_round_trip);
> +}
> +
> +static int
> +get_port_info(struct ibnd_fabric *fabric, struct ibnd_port *port,
> + int portnum, ib_portid_t *portid)
> +{
> + char portinfo[64];
> + void *pi = portinfo;
> +
> + port->port.portnum = portnum;
> +
> + if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout_ms,
> + fabric->ibmad_port))
> + return -1;
> +
> + decode_port_info(pi, &port->port.info);
> +
> + IBND_DEBUG("portid %s portnum %d: lid %d state %d physstate %d %s %s\n",
> + portid2str(portid), portnum, port->port.info.lid, port->port.info.link_state,
> + port->port.info.phys_state, ibnd_linkwidth_str(port->port.info.link_width_active),
> + ibnd_linkspeed_str(port->port.info.link_speed_active, 0));
> + return 1;
> +}
> +
> +static void
> +decode_node_info(void * rcv_buf, ibnd_node_info_t *ni)
> +{
> + mad_decode_field(rcv_buf, IB_NODE_BASE_VERS_F, &ni->base_ver);
> + mad_decode_field(rcv_buf, IB_NODE_CLASS_VERS_F, &ni->class_ver);
> + mad_decode_field(rcv_buf, IB_NODE_TYPE_F, &ni->type);
> + mad_decode_field(rcv_buf, IB_NODE_NPORTS_F, &ni->numports);
> + mad_decode_field(rcv_buf, IB_NODE_SYSTEM_GUID_F, &ni->sysimgguid);
> + mad_decode_field(rcv_buf, IB_NODE_GUID_F, &ni->nodeguid);
> + mad_decode_field(rcv_buf, IB_NODE_PORT_GUID_F, &ni->nodeportguid);
> + mad_decode_field(rcv_buf, IB_NODE_PARTITION_CAP_F, &ni->partition_cap);
> + mad_decode_field(rcv_buf, IB_NODE_DEVID_F, &ni->devid);
> + mad_decode_field(rcv_buf, IB_NODE_REVISION_F, &ni->revision);
> + mad_decode_field(rcv_buf, IB_NODE_LOCAL_PORT_F, &ni->localport);
> + mad_decode_field(rcv_buf, IB_NODE_VENDORID_F, &ni->vendid);
> +}
> +
> +/*
> + * Returns -1 if error.
> + */
> +static int
> +query_node_info(struct ibnd_fabric *fabric, struct ibnd_node *node, ib_portid_t *portid)
> +{
> + char nodeinfo[64];
> + void *ni = nodeinfo;
> + if (!smp_query_via(ni, portid, IB_ATTR_NODE_INFO, 0, timeout_ms,
> + fabric->ibmad_port))
> + return -1;
> + decode_node_info(ni, &(node->node.info));
> + 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)
> +{
> + char portinfo[64];
> + void *pi = portinfo;
> + char switchinfo[64];
> + void *si = switchinfo;
> + 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 = node->info.localport;
> + port->guid = node->info.nodeportguid;
> +
> + if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, timeout_ms,
> + fabric->ibmad_port))
> + return -1;
> +
> + if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, 0, timeout_ms,
> + fabric->ibmad_port))
> + return -1;
> + decode_port_info(pi, &port->info);
> +
> + if (node->info.type != IBND_SWITCH_NODE)
> + return 0;
> +
> + node->smalid = port->info.lid;
> + node->smalmc = port->info.lmc;
> +
> + /* after we have the sma information find out the real PortInfo for this port */
> + if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, node->info.localport, timeout_ms,
> + fabric->ibmad_port))
> + return -1;
> + decode_port_info(pi, &port->info);
> +
> + if (!smp_query_via(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout_ms,
> + fabric->ibmad_port))
> + node->sw_info.smaenhsp0 = 0; /* assume base SP0 */
> + else
> + mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &node->sw_info.smaenhsp0);
> +
> + IBND_DEBUG("portid %s: got switch node %" PRIx64 " '%s'\n",
> + portid2str(portid), node->info.nodeguid, node->nodedesc);
> + return 1;
> +}
> +
> +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)
> +{
> + if (!show_progress)
> + return;
> +
> + printf("%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d\"%s\"\n",
> + portid2str(path), prompt,
> + ibnd_node_type_str((ibnd_node_t *)node),
> + node->node.info.nodeguid,
> + node->node.info.type == IBND_SWITCH_NODE ? 0 : port->port.portnum,
> + port->port.info.lid, port->port.info.lid + (1 << port->port.info.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.info.nodeguid) % HTSZ;
> + struct ibnd_node *node;
> +
> + for (node = fabric->nodestbl[hash]; node; node = node->htnext)
> + if (node->node.info.nodeguid == new->node.info.nodeguid)
> + 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.info.nodeguid == guid)
> + return (ibnd_node_t *)node;
> +
> + return NULL;
> +}
> +
> +ibnd_node_t *
> +ibnd_update_node(ibnd_node_t *node)
> +{
> + char portinfo[64];
> + void *pi = portinfo;
> + ibnd_port_info_t port0_info;
> + char switchinfo[64];
> + void *si = switchinfo;
> + 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.info.numports; p++) {
> + get_port_info(f, CONV_PORT_INTERNAL(n->node.ports[p]), p, &(n->node.path_portid));
> + }
> +
> + if (n->node.info.type != IBND_SWITCH_NODE)
> + goto done;
> +
> + if (!smp_query_via(pi, &(n->node.path_portid), IB_ATTR_PORT_INFO, 0, timeout_ms,
> + f->ibmad_port))
> + return (NULL);
> + decode_port_info(pi, &port0_info);
> +
> + n->node.smalid = port0_info.lid;
> + n->node.smalmc = port0_info.lmc;
> +
> + if (!smp_query_via(si, &(n->node.path_portid), IB_ATTR_SWITCH_INFO, 0, timeout_ms,
> + f->ibmad_port))
> + node->sw_info.smaenhsp0 = 0; /* assume base SP0 */
> + else
> + mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &n->node.sw_info.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.info.nodeguid) % 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.info.type) {
> + case IBND_CA_NODE:
> + node->type_next = fabric->ch_adapters;
> + fabric->ch_adapters = node;
> + break;
> + case IBND_SWITCH_NODE:
> + node->type_next = fabric->switches;
> + fabric->switches = node;
> + break;
> + case IBND_ROUTER_NODE:
> + 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.info.type != IBND_SWITCH_NODE)
> + 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.info.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.info.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.info.nodeguid, node, port, port->port.portnum,
> + remotenode->node.info.nodeguid, 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 (port->port.info.phys_state != 5) /* LinkUp */
> + return -1;
> +
> + if (extend_dpath(fabric, &path->drpath, portnum) < 0)
> + return -1;
> +
> + if (query_node(fabric, &node_buf, &port_buf, path) < 0) {
> + 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) < 0) {
> + 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.info.type != IBND_SWITCH_NODE &&
> + get_remote_node(fabric, node, port, from, node->node.info.localport, 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.info.numports; i++) {
> + if (i == node->node.info.localport)
> + continue;
> +
> + if (get_port_info(fabric, &port_buf, i, path) < 0) {
> + 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.info.type == IBND_SWITCH_NODE)
> + port->port.guid = node->node.info.nodeportguid;
> +
> + 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.info.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;
> +}
> +
> +const char*
> +ibnd_node_type_str(ibnd_node_t *node)
> +{
> + switch(node->info.type) {
> + case IBND_CA_NODE: return "Ca";
> + case IBND_SWITCH_NODE: return "Switch";
> + case IBND_ROUTER_NODE: return "Router";
> + }
> + return "??";
> +}
> +
> +const char*
> +ibnd_node_type_str_short(ibnd_node_t *node)
> +{
> + switch(node->info.type) {
> + case IBND_SWITCH_NODE: return "SW";
> + case IBND_CA_NODE: return "CA";
> + case IBND_ROUTER_NODE: return "RT";
> + }
> + return "??";
> +}
> +
> +
> +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,
> + ibnd_node_type_t 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 IBND_SWITCH_NODE:
> + list = f->switches;
> + break;
> + case IBND_CA_NODE:
> + list = f->ch_adapters;
> + break;
> + case IBND_ROUTER_NODE:
> + 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..89f238f
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/internal.h
> @@ -0,0 +1,82 @@
> +/*
> + * 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>
> +
> +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)
> +
> +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/iblinkinfotest.c b/infiniband-diags/libibnetdisc/test/iblinkinfotest.c
> new file mode 100644
> index 0000000..6e63f4a
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/test/iblinkinfotest.c
> @@ -0,0 +1,395 @@
> +/*
> + * 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 char *node_name_map_file = NULL;
> +static nn_map_t *node_name_map = NULL;
> +
> +static int timeout_ms = 500;
> +
> +static int debug = 0;
> +#define DEBUG(str, args...) \
> + if (debug) fprintf(stderr, str, ##args)
> +
> +static int down_links_only = 0;
> +static int line_mode = 0;
> +static int add_sw_settings = 0;
> +static int print_port_guids = 0;
> +
> +static unsigned int
> +get_max(unsigned int num)
> +{
> + unsigned int v = num; // 32-bit word to find the log base 2 of
> + unsigned r = 0; // r will be lg(v)
> +
> + while (v >>= 1) // unroll for more speed...
> + {
> + r++;
> + }
> +
> + return (1 << r);
> +}
> +
> +void
> +get_msg(char *width_msg, char *speed_msg, int msg_size, ibnd_port_t *port)
> +{
> + int max_speed = 0;
> +
> + int max_width = get_max(port->info.link_width_supported
> + & port->remoteport->info.link_width_supported);
> + if ((max_width & port->info.link_width_active) == 0) {
> + // we are not at the max supported width
> + // print what we could be at.
> + snprintf(width_msg, msg_size, "Could be %s",
> + ibnd_linkwidth_str(max_width));
> + }
> +
> + max_speed = get_max(port->info.link_speed_supported
> + & port->remoteport->info.link_speed_supported);
> + if ((max_speed & port->info.link_speed_active) == 0) {
> + // we are not at the max supported speed
> + // print what we could be at.
> + snprintf(speed_msg, msg_size, "Could be %s",
> + ibnd_linkspeed_str(max_speed, 1));
> + }
> +}
> +
> +void
> +print_port(ibnd_node_t *node, ibnd_port_t *port)
> +{
> + char remote_guid_str[256];
> + char remote_str[256];
> + char link_str[256];
> + char width_msg[256];
> + char speed_msg[256];
> + char ext_port_str[256];
> +
> + if (!port)
> + return;
> +
> + remote_guid_str[0] = '\0';
> + remote_str[0] = '\0';
> + link_str[0] = '\0';
> + width_msg[0] = '\0';
> + speed_msg[0] = '\0';
> +
> + if (port->remoteport) {
> + char remote_name_buf[256];
> + strncpy(remote_name_buf, port->remoteport->node->nodedesc, 256);
> +
> + if (port->remoteport->ext_portnum)
> + snprintf(ext_port_str, 256, "%d", port->remoteport->ext_portnum);
> + else
> + ext_port_str[0] = '\0';
> +
> + get_msg(width_msg, speed_msg, 256, port);
> + if (line_mode) {
> + if (print_port_guids) {
> + snprintf(remote_guid_str, 256,
> + "0x%016lx ",
> + port->remoteport->guid);
> + } else {
> + snprintf(remote_guid_str, 256,
> + "0x%016lx ",
> + port->remoteport->node->info.nodeguid);
> + }
> + }
> +
> + snprintf(remote_str, 256,
> + "%s%6d %4d[%2s] \"%s\" (%s %s)\n",
> + remote_guid_str,
> + port->remoteport->info.lid ?
> + port->remoteport->info.lid :
> + port->remoteport->node->smalid,
> + port->remoteport->portnum,
> + ext_port_str,
> + remap_node_name(node_name_map,
> + port->remoteport->node->info.nodeguid,
> + remote_name_buf),
> + width_msg,
> + speed_msg
> + );
> + } else {
> + snprintf(remote_str, 256,
> + "%6s %4s[%2s] \"\" ( )\n", "", "", "");
> + }
> +
> + if (add_sw_settings) {
> + snprintf(link_str, 256,
> + "(%3s %s %6s/%8s) (HOQ:%d VL_Stall:%d)",
> + ibnd_linkwidth_str(port->info.link_width_active),
> + ibnd_linkspeed_str(port->info.link_speed_active, 1),
> + ibnd_linkstate_str(port->info.link_state),
> + ibnd_physstate_str(port->info.phys_state),
> + port->info.hoq_lifetime,
> + port->info.vl_stall_count
> + );
> + } else {
> + snprintf(link_str, 256,
> + "(%3s %s %6s/%8s)",
> + ibnd_linkwidth_str(port->info.link_width_active),
> + ibnd_linkspeed_str(port->info.link_speed_active, 1),
> + ibnd_linkstate_str(port->info.link_state),
> + ibnd_physstate_str(port->info.phys_state)
> + );
> + }
> +
> + if (port->ext_portnum)
> + snprintf(ext_port_str, 256, "%d", port->ext_portnum);
> + else
> + ext_port_str[0] = '\0';
> +
> + if (line_mode) {
> + char name_buf[256];
> + strncpy(name_buf, node->nodedesc, 256);
> + printf("0x%016lx \"%30s\" %6d %4d[%2s] ==%s==> %s",
> + node->info.nodeguid,
> + remap_node_name(node_name_map,
> + node->info.nodeguid,
> + name_buf),
> + node->smalid, port->portnum,
> + ext_port_str,
> + link_str,
> + remote_str
> + );
> + } else {
> + printf(" %6d %4d[%2s] ==%s==> %s",
> + node->smalid, port->portnum,
> + ext_port_str,
> + link_str,
> + remote_str
> + );
> + }
> +}
> +
> +void
> +print_switch(ibnd_node_t *node, void *user_data)
> +{
> + int i = 0;
> +
> + if (!line_mode) {
> + char name_buf[256];
> + strncpy(name_buf, node->nodedesc, 256);
> + printf("Switch 0x%016lx %s:\n",
> + node->info.nodeguid,
> + remap_node_name(node_name_map,
> + node->info.nodeguid,
> + name_buf));
> + }
> +
> + for (i = 1; i <= node->info.numports; i++) {
> + ibnd_port_t *port = node->ports[i];
> + if (!port)
> + continue;
> + if (!down_links_only || port->info.link_state == IBND_LINK_DOWN) {
> + print_port(node, port);
> + }
> + }
> +}
> +
> +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"
> + " -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"
> + " -d print only down links\n"
> + " -l (line mode) print all information for each link on each line\n"
> + " -p print additional switch settings (PktLifeTime,HoqLife,VLStallCount)\n"
> +
> +
> + " -t <timeout_ms> timeout for any single fabric query\n"
> + " -s show errors\n"
> + " --node-name-map <map_file> use specified node name map\n"
> +
> + " -C <ca_name> use selected Channel Adaptor name for queries\n"
> + " -P <ca_port> use selected channel adaptor port for queries\n"
> + " -g print port guids instead of node guids\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;
> +
> + static char const str_opts[] = "S:D:n:C:P:t:sldgphuf:";
> + static const struct option long_opts[] = {
> + { "S", 1, 0, 'S'},
> + { "D", 1, 0, 'D'},
> + { "num-hops", 1, 0, 'n'},
> + { "down-links-only", 0, 0, 'd'},
> + { "line-mode", 0, 0, 'l'},
> + { "ca-name", 1, 0, 'C'},
> + { "ca-port", 1, 0, 'P'},
> + { "timeout", 1, 0, 't'},
> + { "show", 0, 0, 's'},
> + { "print-port-guids", 0, 0, 'g'},
> + { "print-additional", 0, 0, 'p'},
> + { "help", 0, 0, 'h'},
> + { "usage", 0, 0, 'u'},
> + { "node-name-map", 1, 0, 1},
> + { "debug", 0, 0, 2},
> + { "from", 1, 0, 'f'},
> + { }
> + };
> +
> + 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 1:
> + node_name_map_file = strdup(optarg);
> + break;
> + case 2:
> + debug = 1;
> + 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 'd':
> + down_links_only = 1;
> + break;
> + case 'l':
> + line_mode = 1;
> + break;
> + case 't':
> + timeout_ms = strtoul(optarg, 0, 0);
> + break;
> + case 'g':
> + print_port_guids = 1;
> + break;
> + case 'S':
> + guid = (uint64_t)strtoull(optarg, 0, 0);
> + break;
> + case 'p':
> + add_sw_settings = 1;
> + break;
> + default:
> + usage();
> + break;
> + }
> + }
> + argc -= optind;
> + argv += optind;
> +
> + if (argc && !(f = fopen(argv[0], "w")))
> + fprintf(stderr, "can't open file %s for writing", argv[0]);
> +
> + node_name_map = open_node_name_map(node_name_map_file);
> +
> + 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);
> + }
> + }
> +
> + if (guid) {
> + ibnd_node_t *sw = ibnd_find_node_guid(fabric, guid);
> + print_switch(sw, NULL);
> + } else if (dr_path) {
> + ibnd_node_t *sw = ibnd_find_node_dr(fabric, dr_path);
> + print_switch(sw, NULL);
> + } else {
> + ibnd_iter_nodes_type(fabric, print_switch, IBND_SWITCH_NODE, NULL);
> + }
> +
> + ibnd_destroy_fabric(fabric);
> +
> + close_node_name_map(node_name_map);
> + exit(0);
> +}
> diff --git a/infiniband-diags/libibnetdisc/test/ibnetdisctest.c b/infiniband-diags/libibnetdisc/test/ibnetdisctest.c
> new file mode 100644
> index 0000000..fc6e234
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/test/ibnetdisctest.c
> @@ -0,0 +1,675 @@
> +/*
> + * Copyright (c) 2004-2008 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>
> +#include <infiniband/common.h>
> +
> +static int verbose;
> +#define LIST_CA_NODE (1 << IBND_CA_NODE)
> +#define LIST_SWITCH_NODE (1 << IBND_SWITCH_NODE)
> +#define LIST_ROUTER_NODE (1 << IBND_ROUTER_NODE)
> +
> +char *argv0 = "ibnetdiscover";
> +static FILE *f;
> +
> +static char *node_name_map_file = NULL;
> +static nn_map_t *node_name_map = NULL;
> +
> +static int timeout_ms = 2000;
> +
> +static int debug = 0;
> +#define DEBUG(str, args...) \
> + if (debug) fprintf(stderr, str, ##args)
> +
> +
> +char *
> +node_name(ibnd_node_t *node)
> +{
> + static char buf[256];
> +
> + switch(node->info.type) {
> + case IBND_CA_NODE:
> + sprintf(buf, "\"%s", "H");
> + break;
> + case IBND_SWITCH_NODE:
> + sprintf(buf, "\"%s", "S");
> + break;
> + case IBND_ROUTER_NODE:
> + sprintf(buf, "\"%s", "R");
> + break;
> + default:
> + sprintf(buf, "\"%s", "?");
> + break;
> + }
> + sprintf(buf+2, "-%016" PRIx64 "\"", node->info.nodeguid);
> +
> + return buf;
> +}
> +
> +void
> +list_node(ibnd_node_t *node, void *user_data)
> +{
> + char *nodename = remap_node_name(node_name_map, node->info.nodeguid,
> + node->nodedesc);
> +
> + fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n",
> + ibnd_node_type_str(node),
> + node->info.nodeguid, node->info.numports, node->info.devid,
> + node->info.vendid,
> + nodename);
> +
> + free(nodename);
> +}
> +
> +void
> +list_nodes(ibnd_fabric_t *fabric, int list)
> +{
> + if (list & LIST_CA_NODE) {
> + ibnd_iter_nodes_type(fabric, list_node, IBND_CA_NODE, NULL);
> + }
> + if (list & LIST_SWITCH_NODE) {
> + ibnd_iter_nodes_type(fabric, list_node, IBND_SWITCH_NODE, NULL);
> + }
> + if (list & LIST_ROUTER_NODE) {
> + ibnd_iter_nodes_type(fabric, list_node, IBND_ROUTER_NODE, NULL);
> + }
> +}
> +
> +void
> +out_ids(ibnd_node_t *node, int group, char *chname)
> +{
> + fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", node->info.vendid, node->info.devid);
> + if (node->info.sysimgguid)
> + fprintf(f, "sysimgguid=0x%" PRIx64, node->info.sysimgguid);
> + if (group
> + && node->chassis && node->chassis->chassisnum) {
> + fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum);
> + if (chname)
> + fprintf(f, " (%s)", clean_nodedesc(chname));
> + if (ibnd_is_xsigo_tca(node->info.nodeguid)
> + && node->ports[1]
> + && node->ports[1]->remoteport)
> + fprintf(f, " slot %d", node->ports[1]->remoteport->portnum);
> + }
> + fprintf(f, "\n");
> +}
> +
> +
> +uint64_t
> +out_chassis(ibnd_fabric_t *fabric, int chassisnum)
> +{
> + uint64_t guid;
> +
> + fprintf(f, "\nChassis %d", chassisnum);
> + guid = ibnd_get_chassis_guid(fabric, chassisnum);
> + if (guid)
> + fprintf(f, " (guid 0x%" PRIx64 ")", guid);
> + fprintf(f, "\n");
> + return guid;
> +}
> +
> +void
> +out_switch(ibnd_node_t *node, int group, char *chname)
> +{
> + char *str;
> + char str2[256];
> + char *nodename = NULL;
> +
> + out_ids(node, group, chname);
> + fprintf(f, "switchguid=0x%" PRIx64, node->info.nodeguid);
> + fprintf(f, "(%" PRIx64 ")", node->info.nodeportguid);
> + if (group) {
> + str = ibnd_get_chassis_type(node);
> + if (str)
> + fprintf(f, "%s ", str);
> + str = ibnd_get_chassis_slot_str(node, str2, 256);
> + if (str)
> + fprintf(f, "%s", str);
> + }
> +
> + nodename = remap_node_name(node_name_map, node->info.nodeguid,
> + node->nodedesc);
> +
> + fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n",
> + node->info.numports, node_name(node),
> + nodename,
> + node->sw_info.smaenhsp0 ? "enhanced" : "base",
> + node->smalid, node->smalmc);
> +
> + free(nodename);
> +}
> +
> +void
> +out_ca(ibnd_node_t *node, int group, char *chname)
> +{
> + char *node_type;
> + char *node_type2;
> +
> + out_ids(node, group, chname);
> + switch(node->info.type) {
> + case IBND_CA_NODE:
> + node_type = "ca";
> + node_type2 = "Ca";
> + break;
> + case IBND_ROUTER_NODE:
> + node_type = "rt";
> + node_type2 = "Rt";
> + break;
> + default:
> + node_type = "???";
> + node_type2 = "???";
> + break;
> + }
> +
> + fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->info.nodeguid);
> + fprintf(f, "%s\t%d %s\t\t# \"%s\"",
> + node_type2, node->info.numports, node_name(node),
> + clean_nodedesc(node->nodedesc));
> + if (group && ibnd_is_xsigo_hca(node->info.nodeguid))
> + fprintf(f, " (scp)");
> + fprintf(f, "\n");
> +}
> +
> +#define OUT_BUFFER_SIZE 16
> +static char *
> +out_ext_port(ibnd_port_t *port, int group)
> +{
> + static char mapping[OUT_BUFFER_SIZE];
> +
> + if (group && port->ext_portnum != 0) {
> + snprintf(mapping, OUT_BUFFER_SIZE,
> + "[ext %d]", port->ext_portnum);
> + return (mapping);
> + }
> +
> + return (NULL);
> +}
> +
> +void
> +out_switch_port(ibnd_port_t *port, int group)
> +{
> + char *ext_port_str = NULL;
> + char *rem_nodename = NULL;
> +
> + DEBUG("port %p:%d remoteport %p\n", port, port->portnum, port->remoteport);
> + fprintf(f, "[%d]", port->portnum);
> +
> + ext_port_str = out_ext_port(port, group);
> + if (ext_port_str)
> + fprintf(f, "%s", ext_port_str);
> +
> + rem_nodename = remap_node_name(node_name_map,
> + port->remoteport->node->info.nodeguid,
> + port->remoteport->node->nodedesc);
> +
> + ext_port_str = out_ext_port(port->remoteport, group);
> + fprintf(f, "\t%s[%d]%s",
> + node_name(port->remoteport->node),
> + port->remoteport->portnum,
> + ext_port_str ? ext_port_str : "");
> + if (port->remoteport->node->info.type != IBND_SWITCH_NODE)
> + fprintf(f, "(%" PRIx64 ") ", port->remoteport->guid);
> + fprintf(f, "\t\t# \"%s\" lid %d %s%s",
> + rem_nodename,
> + port->remoteport->node->info.type == IBND_SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->info.lid,
> + ibnd_linkwidth_str(port->info.link_width_active),
> + ibnd_linkspeed_str(port->info.link_speed_active, 0));
> +
> + if (ibnd_is_xsigo_tca(port->remoteport->guid))
> + fprintf(f, " slot %d", port->portnum);
> + else if (ibnd_is_xsigo_hca(port->remoteport->guid))
> + fprintf(f, " (scp)");
> + fprintf(f, "\n");
> +
> + free(rem_nodename);
> +}
> +
> +void
> +out_ca_port(ibnd_port_t *port, int group)
> +{
> + char *str = NULL;
> + char *rem_nodename = NULL;
> +
> + fprintf(f, "[%d]", port->portnum);
> + if (port->node->info.type != IBND_SWITCH_NODE)
> + fprintf(f, "(%" PRIx64 ") ", port->guid);
> + fprintf(f, "\t%s[%d]",
> + node_name(port->remoteport->node),
> + port->remoteport->portnum);
> + str = out_ext_port(port->remoteport, group);
> + if (str)
> + fprintf(f, "%s", str);
> + if (port->remoteport->node->info.type != IBND_SWITCH_NODE)
> + fprintf(f, " (%" PRIx64 ") ", port->remoteport->guid);
> +
> + rem_nodename = remap_node_name(node_name_map,
> + port->remoteport->node->info.nodeguid,
> + port->remoteport->node->nodedesc);
> +
> + fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n",
> + port->info.lid, port->info.lmc, rem_nodename,
> + port->remoteport->node->info.type == IBND_SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->info.lid,
> + ibnd_linkwidth_str(port->info.link_width_active),
> + ibnd_linkspeed_str(port->info.link_speed_active, 0));
> +
> + free(rem_nodename);
> +}
> +
> +struct iter_user_data {
> + int group;
> + int skip_chassis_nodes;
> +};
> +
> +static void
> +switch_iter_func(ibnd_node_t *node, void *iter_user_data)
> +{
> + ibnd_port_t *port;
> + int p = 0;
> + struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
> +
> + DEBUG("SWITCH: node %p\n", node);
> +
> + /* skip chassis based switches if flagged */
> + if (data->skip_chassis_nodes && node->chassis && node->chassis->chassisnum)
> + return;
> +
> + out_switch(node, data->group, NULL);
> + for (p = 1; p <= node->info.numports; p++) {
> + port = node->ports[p];
> + if (port && port->remoteport)
> + out_switch_port(port, data->group);
> + }
> +}
> +
> +static void
> +ca_iter_func(ibnd_node_t *node, void *iter_user_data)
> +{
> + ibnd_port_t *port;
> + int p = 0;
> + struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
> +
> + DEBUG("CA: node %p\n", node);
> + /* Now, skip chassis based CAs */
> + if (data->group && node->chassis && node->chassis->chassisnum)
> + return;
> + out_ca(node, data->group, NULL);
> +
> + for (p = 1; p <= node->info.numports; p++) {
> + port = node->ports[p];
> + if (port && port->remoteport)
> + out_ca_port(port, data->group);
> + }
> +}
> +
> +static void
> +router_iter_func(ibnd_node_t *node, void *iter_user_data)
> +{
> + ibnd_port_t *port;
> + int p = 0;
> + struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
> +
> + DEBUG("RT: node %p\n", node);
> + /* Now, skip chassis based RTs */
> + if (data->group && node->chassis && node->chassis->chassisnum)
> + return;
> + out_ca(node, data->group, NULL);
> + for (p = 1; p <= node->info.numports; p++) {
> + port = node->ports[p];
> + if (port && port->remoteport)
> + out_ca_port(port, data->group);
> + }
> +}
> +
> +int
> +dump_topology(int group, ibnd_fabric_t *fabric)
> +{
> + ibnd_node_t *node;
> + ibnd_port_t *port;
> + int i = 0, p = 0;
> + time_t t = time(0);
> + uint64_t chguid;
> + char *chname = NULL;
> + struct iter_user_data iter_user_data;
> +
> + fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));
> + fprintf(f, "# Max of %d hops discovered\n", fabric->maxhops_discovered);
> + fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n",
> + fabric->from_node->info.nodeguid, fabric->from_node->info.nodeportguid);
> +
> + /* Make pass on switches */
> + if (group) {
> + ibnd_chassis_t *ch = NULL;
> +
> + /* Chassis based switches first */
> + for (ch = fabric->chassis; ch; ch = ch->next) {
> + int n = 0;
> +
> + if (!ch->chassisnum)
> + continue;
> + chguid = out_chassis(fabric, ch->chassisnum);
> +
> + chname = NULL;
> +/**
> + * Will this work for Xsigo?
> + */
> + if (ibnd_is_xsigo_guid(chguid)) {
> + for (node = ch->nodes; node;
> + node = node->next_chassis_node) {
> + if (ibnd_is_xsigo_hca(node->info.nodeguid)) {
> + chname = node->nodedesc;
> + fprintf(f, "Hostname: %s\n", clean_nodedesc(node->nodedesc));
> + }
> + }
> +
> +#if 0
> +/**
> + * vs. this?
> + * I don't want to expose the nodesdist array to the end user.
> + */
> + for (node = fabric->nodesdist[MAXHOPS]; node; node = node->dnext) {
> + if (!node->chrecord ||
> + !node->chrecord->chassisnum)
> + continue;
> +
> + if (node->chrecord->chassisnum != ch->chassisnum)
> + continue;
> +
> + if (ibnd_is_xsigo_hca(node->nodeguid)) {
> + chname = node->nodedesc;
> + fprintf(f, "Hostname: %s\n", clean_nodedesc(node->nodedesc));
> + }
> + }
> +#endif
> + }
> +
> + fprintf(f, "\n# Spine Nodes");
> + for (n = 1; n <= SPINES_MAX_NUM; n++) {
> + if (ch->spinenode[n]) {
> + out_switch(ch->spinenode[n], group, chname);
> + for (p = 1; p <= ch->spinenode[n]->info.numports; p++) {
> + port = ch->spinenode[n]->ports[p];
> + if (port && port->remoteport)
> + out_switch_port(port, group);
> + }
> + }
> + }
> + fprintf(f, "\n# Line Nodes");
> + for (n = 1; n <= LINES_MAX_NUM; n++) {
> + if (ch->linenode[n]) {
> + out_switch(ch->linenode[n], group, chname);
> + for (p = 1; p <= ch->linenode[n]->info.numports; p++) {
> + port = ch->linenode[n]->ports[p];
> + if (port && port->remoteport)
> + out_switch_port(port, group);
> + }
> + }
> + }
> +
> + fprintf(f, "\n# Chassis Switches");
> + for (node = ch->nodes; node;
> + node = node->next_chassis_node) {
> + if (node->info.type == IBND_SWITCH_NODE) {
> + out_switch(node, group, chname);
> + for (p = 1; p <= node->info.numports; p++) {
> + port = node->ports[p];
> + if (port && port->remoteport)
> + out_switch_port(port, group);
> + }
> + }
> + }
> +
> + fprintf(f, "\n# Chassis CAs");
> + for (node = ch->nodes; node;
> + node = node->next_chassis_node) {
> + if (node->info.type == IBND_CA_NODE) {
> + out_ca(node, group, chname);
> + for (p = 1; p <= node->info.numports; p++) {
> + port = node->ports[p];
> + if (port && port->remoteport)
> + out_ca_port(port, group);
> + }
> + }
> + }
> +
> + }
> +
> + } else { /* !group */
> + iter_user_data.group = group;
> + iter_user_data.skip_chassis_nodes = 0;
> +
> + ibnd_iter_nodes_type(fabric, switch_iter_func,
> + IBND_SWITCH_NODE, &iter_user_data);
> + }
> +
> + chname = NULL;
> + if (group) {
> + iter_user_data.group = group;
> + iter_user_data.skip_chassis_nodes = 1;
> +
> + fprintf(f, "\nNon-Chassis Nodes\n");
> + ibnd_iter_nodes_type(fabric, switch_iter_func,
> + IBND_SWITCH_NODE, &iter_user_data);
> +
> + }
> +
> + iter_user_data.group = group;
> + iter_user_data.skip_chassis_nodes = 0;
> +
> + /* Make pass on CAs */
> + ibnd_iter_nodes_type(fabric, ca_iter_func, IBND_CA_NODE,
> + &iter_user_data);
> +
> + /* make pass on routers */
> + ibnd_iter_nodes_type(fabric, router_iter_func, IBND_ROUTER_NODE,
> + &iter_user_data);
> +
> + return i;
> +}
> +
> +
> +void dump_ports_report (ibnd_node_t *node, void *user_data)
> +{
> + int p = 0;
> + ibnd_port_t *port = NULL;
> +
> + /* for each port */
> + for (p = node->info.numports, port = node->ports[p];
> + p > 0;
> + port = node->ports[--p]) {
> + if (port == NULL)
> + continue;
> +
> + fprintf(stdout,
> + "%2s %5d %2d 0x%016" PRIx64 " %s %s",
> + ibnd_node_type_str_short(node),
> + node->info.type == IBND_SWITCH_NODE ? node->smalid : port->info.lid,
> + port->portnum,
> + port->guid,
> + ibnd_linkwidth_str(port->info.link_width_active),
> + ibnd_linkspeed_str(port->info.link_speed_active, 0));
> + if (port->remoteport)
> + fprintf(stdout,
> + " - %2s %5d %2d 0x%016" PRIx64
> + " ( '%s' - '%s' )\n",
> + ibnd_node_type_str_short(port->remoteport->node),
> + port->remoteport->node->info.type == IBND_SWITCH_NODE ?
> + port->remoteport->node->smalid : port->remoteport->info.lid,
> + port->remoteport->portnum,
> + port->remoteport->guid,
> + port->node->nodedesc,
> + port->remoteport->node->nodedesc);
> + else
> + fprintf(stdout, "%36s'%s'\n", "",
> + port->node->nodedesc);
> + }
> +}
> +
> +void
> +usage(void)
> +{
> + fprintf(stderr, "Usage: %s [-d(ebug)] -s(how) -l(ist) -g(rouping) -H(ca_list) -S(witch_list) -R(outer_list) -V(ersion) -C ca_name -P ca_port "
> + "-t(imeout) timeout_ms --node-name-map node-name-map] -p(orts) [<topology-file>]\n",
> + argv0);
> + fprintf(stderr, " --node-name-map <node-name-map> specify a node name map file\n");
> + exit(-1);
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> + int list = 0;
> + char *ca = 0;
> + int ca_port = 0;
> + int group = 0;
> + int ports_report = 0;
> + ibnd_fabric_t *fabric = NULL;
> +
> + static char const str_opts[] = "C:P:t:devslgHSRpVhu";
> + static const struct option long_opts[] = {
> + { "C", 1, 0, 'C'},
> + { "P", 1, 0, 'P'},
> + { "debug", 0, 0, 'd'},
> + { "verbose", 0, 0, 'v'},
> + { "show", 0, 0, 's'},
> + { "list", 0, 0, 'l'},
> + { "grouping", 0, 0, 'g'},
> + { "Hca_list", 0, 0, 'H'},
> + { "Switch_list", 0, 0, 'S'},
> + { "Router_list", 0, 0, 'R'},
> + { "timeout", 1, 0, 't'},
> + { "node-name-map", 1, 0, 1},
> + { "ports", 0, 0, 'p'},
> + { "Version", 0, 0, 'V'},
> + { "help", 0, 0, 'h'},
> + { "usage", 0, 0, 'u'},
> + { }
> + };
> +
> + 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 1:
> + node_name_map_file = strdup(optarg);
> + break;
> + case 'C':
> + ca = optarg;
> + break;
> + case 'P':
> + ca_port = strtoul(optarg, 0, 0);
> + break;
> + case 'd':
> + debug = 1;
> + ibnd_debug(1);
> + break;
> + case 't':
> + timeout_ms = strtoul(optarg, 0, 0);
> + break;
> + case 'v':
> + verbose++;
> + break;
> + case 's':
> + ibnd_show_progress(1);
> + break;
> + case 'l':
> + list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
> + break;
> + case 'g':
> + group = 1;
> + break;
> + case 'S':
> + list |= LIST_SWITCH_NODE;
> + break;
> + case 'H':
> + list |= LIST_CA_NODE;
> + break;
> + case 'R':
> + list |= LIST_ROUTER_NODE;
> + break;
> + case 'p':
> + ports_report = 1;
> + break;
> + default:
> + usage();
> + break;
> + }
> + }
> + argc -= optind;
> + argv += optind;
> +
> + if (argc && !(f = fopen(argv[0], "w")))
> + fprintf(stderr, "can't open file %s for writing", argv[0]);
> +
> + node_name_map = open_node_name_map(node_name_map_file);
> +
> + if ((fabric = ibnd_discover_fabric(ca, ca_port, timeout_ms, NULL, -1)) == NULL) {
> + fprintf(stderr, "discover failed\n");
> + exit(1);
> + }
> +
> + if (ports_report)
> + ibnd_iter_nodes(fabric,
> + dump_ports_report,
> + NULL);
> + else if (list)
> + list_nodes(fabric, list);
> + else
> + dump_topology(group, fabric);
> +
> + ibnd_destroy_fabric(fabric);
> + close_node_name_map(node_name_map);
> + exit(0);
> +}
> diff --git a/infiniband-diags/libibnetdisc/test/testleaks.c b/infiniband-diags/libibnetdisc/test/testleaks.c
> new file mode 100644
> index 0000000..3fbf7af
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/test/testleaks.c
> @@ -0,0 +1,268 @@
> +/*
> + * 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
> +print_port(ibnd_node_t *node, ibnd_port_t *port)
> +{
> + char remote_guid_str[256];
> + char remote_str[256];
> + char link_str[256];
> + char speed_msg[256];
> + char ext_port_str[256];
> +
> + if (!port)
> + return;
> +
> + remote_guid_str[0] = '\0';
> + remote_str[0] = '\0';
> + link_str[0] = '\0';
> + speed_msg[0] = '\0';
> +
> + if (port->remoteport) {
> + char remote_name_buf[256];
> + strncpy(remote_name_buf, port->remoteport->node->nodedesc, 256);
> +
> + if (port->remoteport->ext_portnum)
> + snprintf(ext_port_str, 256, "%d", port->remoteport->ext_portnum);
> + else
> + ext_port_str[0] = '\0';
> +
> + snprintf(remote_str, 256,
> + "%s%6d %4d[%2s] \"%s\" (%s)\n",
> + remote_guid_str,
> + port->remoteport->info.lid ?
> + port->remoteport->info.lid :
> + port->remoteport->node->smalid,
> + port->remoteport->portnum,
> + ext_port_str,
> + port->remoteport->node->nodedesc,
> + speed_msg
> + );
> + } else {
> + snprintf(remote_str, 256,
> + "%6s %4s[%2s] \"\" ( )\n", "", "", "");
> + }
> +
> + snprintf(link_str, 256,
> + "(%3s %s %6s/%8s)",
> + ibnd_linkwidth_str(port->info.link_width_active),
> + ibnd_linkspeed_str(port->info.link_speed_active, 0),
> + ibnd_linkstate_str(port->info.link_state),
> + ibnd_physstate_str(port->info.phys_state)
> + );
> +
> + if (port->ext_portnum)
> + snprintf(ext_port_str, 256, "%d", port->ext_portnum);
> + else
> + ext_port_str[0] = '\0';
> +
> + printf(" %6d %4d[%2s] ==%s==> %s",
> + node->smalid, port->portnum,
> + ext_port_str,
> + link_str,
> + remote_str
> + );
> +}
> +
> +void
> +print_switch(ibnd_node_t *node, void *user_data)
> +{
> + int i = 0;
> +
> + for (i = 1; i <= node->info.numports; i++) {
> + ibnd_port_t *port = node->ports[i];
> + if (!port)
> + continue;
> + if (port->info.link_state == IBND_LINK_DOWN) {
> + print_port(node, port);
> + }
> + }
> +}
> +
> +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);
> + }
> + }
> +
> +#if 0
> + if (guid) {
> + ibnd_node_t *sw = ibnd_find_node_guid(fabric, guid);
> + print_switch(sw, NULL);
> + } else if (dr_path) {
> + ibnd_node_t *sw = ibnd_find_node_dr(fabric, dr_path);
> + print_switch(sw, NULL);
> + } else {
> + ibnd_iter_nodes_type(fabric, print_switch, IBND_SWITCH_NODE, NULL);
> + }
> +#endif
> +
> + ibnd_destroy_fabric(fabric);
> + }
> +
> + exit(0);
> +}
--
Albert Chu
chu11 at llnl.gov
Computer Scientist
High Performance Systems Division
Lawrence Livermore National Laboratory
More information about the general
mailing list