[ofa-general] ***SPAM*** Re: [PATCH 1/3 - no ibcommon] Create a new library libibnetdisc

Sasha Khapyorsky sashak at voltaire.com
Wed Jan 21 06:49:23 PST 2009


On 15:47 Fri 09 Jan     , Ira Weiny wrote:
> 
> Signed-off-by: weiny2 at llnl.gov <weiny2 at llnl.gov>

Some comments...

> 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 58eea0a..c5b437d 100644
> --- a/infiniband-diags/configure.in
> +++ b/infiniband-diags/configure.in
> @@ -48,7 +48,7 @@ fi
>  
>  dnl Checks for header files.
>  AC_HEADER_STDC
> -AC_CHECK_HEADERS([stdlib.h string.h unistd.h fcntl.h inttypes.h netinet/in.h sys/ioctl.h syslog.h])
> +AC_CHECK_HEADERS([stdlib.h string.h unistd.h fcntl.h inttypes.h netinet/in.h sys/ioctl.h])
>  if test "$disable_libcheck" != "yes"
>  then
>  AC_CHECK_HEADER(infiniband/umad.h, [],
> @@ -70,7 +70,7 @@ AC_C_CONST
>  dnl Check if we should include test utilities
>  AC_MSG_CHECKING(for --enable-test-utils)
>  AC_ARG_ENABLE(test-utils,
> -[  --enable-test-utils build additional test utilities],
> +[  --enable-test-utils build additional test utilities (default=no)],
>  [case "${enableval}" in
>    yes) tutils=yes ;;
>    no)  tutils=no ;;
> @@ -140,6 +140,23 @@ 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])

BTW (not related to the patch), in current grouping.c code I see

#include <stdint.h>
#include <inttypes.h>

inttypes.h by itself includes stdint.h and as addition declares related
printf formats such as PRIx64, etc.. So it is not really necessary to
include both.

> +AC_CHECK_FUNCS([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])

Where do you plan to use it (API_VERSION)?

> +
> +dnl End libibnetdisc stuff
> +
> +
>  AC_CONFIG_FILES([\
>          Makefile \
>          infiniband-diags.spec \
> @@ -160,6 +177,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..8e0e16b
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/Makefile.am
> @@ -0,0 +1,62 @@
> +
> +#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 = -libnetdisc
> +
> +test_iblinkinfotest_SOURCES = test/iblinkinfotest.c
> +test_iblinkinfotest_CFLAGS = -Wall $(DBGFLAGS)
> +test_iblinkinfotest_LDFLAGS = -libnetdisc
> +
> +test_testleaks_SOURCES = test/testleaks.c
> +test_testleaks_CFLAGS = -Wall $(DBGFLAGS)
> +test_testleaks_LDFLAGS = -libnetdisc
> +
> +libibnetdiscinclude_HEADERS = $(srcdir)/include/infiniband/ibnetdisc.h
> +
> +man_MANS = man/ibnd_debug.3 \
> +	man/ibnd_destroy_fabric.3 \
> +	man/ibnd_discover_fabric.3 \
> +	man/ibnd_find_node_dr.3 \
> +	man/ibnd_find_node_guid.3 \
> +	man/ibnd_iter_nodes.3 \
> +	man/ibnd_iter_nodes_type.3 \
> +	man/ibnd_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 = $(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..773c64b
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
> @@ -0,0 +1,282 @@
> +/*
> + * 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

This is used only in ./libibnetdisc/src/ibnetdisc.c, if so should it be
in public header file?

> +
> +#define	IBND_DEBUG(...) \
> +	if (ibdebug) { \
> +		printf("%s:%d; ", __FILE__, __LINE__); \
> +		printf(__VA_ARGS__); \
> +	}
> +#define	IBND_ERROR(...) \
> +	{ \
> +		fprintf(stderr, "%s:%d; ", __FILE__, __LINE__); \
> +		fprintf(stderr, __VA_ARGS__); \
> +	}

This can be done as

#define IBND_ERROR(fmt, ...) \
	fprintf(stderr, "%s:%u: " fmt, __FILE__, __LINE__, ## __VA_ARGS__)

> +
> +/** =========================================================================
> + * ENUM definitions
> + */
> +typedef enum {
> +	IBND_CA_NODE	= 1,
> +	IBND_SWITCH_NODE = 2,
> +	IBND_ROUTER_NODE = 3
> +} ibnd_node_type_t;

infiniband/mad.h has IB_NODE_CA, IB_NODE_SWITCH, IB_NODE_ROUTER
definitions already.

> +
> +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;

Discussed in another thread about those definitions...

> +
> +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 base_lid;
> +	int smlid;
> +	int link_speed_supported;
> +	int link_speed_enabled;
> +	int link_speed_active;
> +	int port_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_ */

[snip...]

> diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
> new file mode 100644
> index 0000000..29f691c
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
> @@ -0,0 +1,871 @@
> +/*
> + * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
> + * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
> + * Copyright (c) 2008 Lawrence Livermore National Laboratory
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +#if HAVE_CONFIG_H
> +#  include <config.h>
> +#endif /* HAVE_CONFIG_H */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <stdarg.h>
> +#include <time.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +
> +#include <infiniband/umad.h>
> +#include <infiniband/mad.h>
> +
> +#include <infiniband/ibnetdisc.h>
> +#include <complib/cl_nodenamemap.h>
> +
> +#include "internal.h"
> +#include "chassis.h"
> +
> +static int timeout_ms = 2000;
> +static int show_progress = 0;
> +
> +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->base_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->port_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: base lid %d state %d physstate %d %s %s\n",
> +		portid2str(portid), portnum, port->port.info.base_lid, port->port.info.port_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;

Maybe better to use '0' as successful status (similar to another
functions like query_node_info())?

> +}
> +
> +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.base_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);

Somehow indentation is broken here.

> +
> +	IBND_DEBUG("portid %s: got switch node %" PRIx64 " '%s'\n",
> +	      portid2str(portid), node->info.nodeguid, node->nodedesc);
> +	return 1;

Same about return status.

> +}
> +
> +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 base 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.base_lid, port->port.info.base_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.base_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)

Why should we hide this internal data so hard?

Maybe we can use a single structures, to mark those fields (in comment)
as "for internal use" - somebody may want to use it.

> +
> +#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;

Where is ibnd_update_node() useful (in public API)?

> +		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: *;
> +};

Sasha



More information about the general mailing list