This change introduces a glib dependancy to support list features

Signed-off-by: Ira Weiny <wei...@llnl.gov>
---
 Makefile.am         |   17 +-
 configure.in        |    8 +
 man/iblinkinfo.8    |   85 ------
 man/iblinkinfo.8.in |  213 +++++++++++++
 src/checkfabric.c   |  822 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/checkfabric.h   |   60 ++++
 src/iblinkinfo.c    |  180 +++++++++---
 7 files changed, 1251 insertions(+), 134 deletions(-)
 delete mode 100644 man/iblinkinfo.8
 create mode 100644 man/iblinkinfo.8.in
 create mode 100644 src/checkfabric.c
 create mode 100644 src/checkfabric.h

diff --git a/Makefile.am b/Makefile.am
index d64bb2c..4aaa41a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,8 @@ endif
 SUBDIRS = libibnetdisc $(IBFABRICCONF)
 
 INCLUDES = -I$(top_builddir)/include/ -I$(srcdir)/include -I$(includedir) \
-       -I$(includedir)/infiniband -I$(top_srcdir)/libibnetdisc/include
+       -I$(includedir)/infiniband -I$(top_srcdir)/libibnetdisc/include \
+       -I$(top_srcdir)/libibfabricconf/include
 
 if DEBUG
 DBGFLAGS = -ggdb -D_DEBUG_
@@ -64,13 +65,24 @@ src_ibsendtrap_SOURCES = src/ibsendtrap.c
 src_vendstat_SOURCES = src/vendstat.c
 src_mcm_rereg_test_SOURCES = src/mcm_rereg_test.c
 src_iblinkinfo_SOURCES = src/iblinkinfo.c
-src_ibccquery_SOURCES = src/ibccquery.c
 src_iblinkinfo_LDFLAGS = -L$(top_builddir)/libibnetdisc -libnetdisc
+src_ibccquery_SOURCES = src/ibccquery.c
 src_ibqueryerrors_SOURCES = src/ibqueryerrors.c
 src_ibqueryerrors_LDFLAGS = -L$(top_builddir)/libibnetdisc -libnetdisc
 src_ibcacheedit_SOURCES = src/ibcacheedit.c
 src_ibcacheedit_LDFLAGS = -L$(top_builddir)/libibnetdisc -libnetdisc
 
+if HAVE_XML
+src_iblinkinfo_SOURCES = src/iblinkinfo.c src/checkfabric.c src/checkfabric.h
+src_iblinkinfo_CFLAGS = $(GLIB_CFLAGS)
+src_iblinkinfo_LDFLAGS = -losmcomp -libmad \
+       -L$(top_builddir)/libibnetdisc -libnetdisc \
+       -L$(top_builddir)/libibfabricconf -libfabricconf $(GLIB_LIBS)
+else
+src_iblinkinfo_SOURCES = src/iblinkinfo.c
+src_iblinkinfo_LDFLAGS = -L$(top_builddir)/libibnetdisc -libnetdisc
+endif
+
 man_MANS = man/ibaddr.8 man/ibcheckerrors.8 man/ibcheckerrs.8 \
        man/ibchecknet.8 man/ibchecknode.8 man/ibcheckport.8 \
        man/ibcheckportstate.8 man/ibcheckportwidth.8 man/ibcheckstate.8 \
@@ -87,6 +99,7 @@ man_MANS = man/ibaddr.8 man/ibcheckerrors.8 man/ibcheckerrs.8 
\
        man/check_lft_balance.8 man/ibcacheedit.8 \
        man/infiniband-diags.8 man/ibccquery.8
 
+
 BUILT_SOURCES = ibdiag_version
 ibdiag_version:
        if [ -x $(top_srcdir)/gen_ver.sh ] ; then \
diff --git a/configure.in b/configure.in
index 175a358..0652948 100644
--- a/configure.in
+++ b/configure.in
@@ -146,6 +146,13 @@ IBSCRIPTPATH_TMP2="`echo $IBSCRIPTPATH_TMP1 | sed 
's/^NONE/$ac_default_prefix/'`
 IBSCRIPTPATH="${with_ibpath_override:-`eval echo $IBSCRIPTPATH_TMP2`}"
 AC_SUBST(IBSCRIPTPATH)
 
+dnl check for glib
+PKG_CHECK_MODULES([GLIB], [glib-2.0], ac_glib=yes, ac_glib=no)
+AM_CONDITIONAL([HAVE_GLIB], test "$ac_glib" = "yes")
+if test "$ac_glib" = "yes"; then
+   AC_DEFINE([HAVE_GLIB], 1, [Define to 1 to indicate GLIB support])
+fi
+
 dnl Begin libibfabricconf stuff
 dnl find the XML support for ibfabricconf
 PKG_CHECK_MODULES([XML], [libxml-2.0], ac_xml=yes, ac_xml=no)
@@ -199,5 +206,6 @@ AC_CONFIG_FILES([\
        libibnetdisc/Makefile \
        libibfabricconf/Makefile \
        libibfabricconf/include/infiniband/ibfabricconf.h \
+       man/iblinkinfo.8 \
 ])
 AC_OUTPUT
diff --git a/man/iblinkinfo.8 b/man/iblinkinfo.8
deleted file mode 100644
index 5fa2678..0000000
--- a/man/iblinkinfo.8
+++ /dev/null
@@ -1,85 +0,0 @@
-.TH IBLINKINFO 8 "Jan 24, 2008" "OpenIB" "OpenIB Diagnostics"
-
-.SH NAME
-iblinkinfo \- report link info for all links in the fabric
-
-.SH SYNOPSIS
-.B iblinkinfo
-   [-hcdl -C <ca_name> -P <ca_port> -p -S <port_guid> -G <port_guid> -D 
<direct_route> \-\-load\-cache <filename>]
-
-.SH DESCRIPTION
-.PP
-iblinkinfo reports link info for each port in an IB fabric, node by node.
-Optionally, iblinkinfo can do partial scans and limit its output to parts of a
-fabric.
-
-.SH OPTIONS
-
-.PP
-.TP
-\fB\-S <port_guid>\fR \fB\-G <port_guid>\fR \fB\-\-port\-guid\fR
-start partial scan at the port specified by <port_guid> (hex format)
-.TP
-\fB\-D <direct_route>\fR
-start partial scan at the port specified by the direct route path.
-.TP
-\fB\-l\fR
-Print all information for each link on one line. Default is to print a header
-with the node information and then a list for each port (useful for
-grep\'ing output).
-.TP
-\fB\-d\fR
-Print only nodes which have a port in the "Down" state.
-.TP
-\fB\-p\fR
-Print additional port settings (<LifeTime>,<HoqLife>,<VLStallCount>)
-.TP
-\fB\-C <ca_name>\fR    use the specified ca_name for the search.
-.TP
-\fB\-P <ca_port>\fR    use the specified ca_port for the search.
-.TP
-\fB\-R\fR (This option is obsolete and does nothing)
-.TP
-\fB\-\-load\-cache\fR <filename>
-Load and use the cached ibnetdiscover data stored in the specified
-filename.  May be useful for outputting and learning about other
-fabrics or a previous state of a fabric.  Cannot be used if user
-specifies a direct route path.  See
-.B ibnetdiscover
-for information on caching ibnetdiscover output.
-.TP
-\fB\-\-diff\fR <filename>
-Load cached ibnetdiscover data and do a diff comparison to the current
-network or another cache.  A special diff output for iblinkinfo
-output will be displayed showing differences between the old and current
-fabric links.  Be default, the following are compared for differences:
-port connections and port state.  See
-.B ibnetdiscover
-for information on caching ibnetdiscover output.
-.TP
-\fB\-\-diffcheck\fR <key(s)>
-Specify what diff checks should be done in the \fB\-\-diff\fR option above.
-Comma separate multiple diff check key(s).  The available diff checks
-are:\fIport\fR = port connections, \fIstate\fR = port state, \fIlid\fR = lids,
-\fInodedesc\fR = node descriptions.  If \fIport\fR is specified alongside 
\fIlid\fR
-or \fInodedesc\fR, remote port lids and node descriptions will also be 
compared.
-.TP
-\fB\-\-filterdownports\fR <filename>
-Filter downports indicated in a ibnetdiscover cache.  If a port was previously
-indicated as down in the specified cache, and is still down, do not output it 
in the
-resulting output.  This option may be particularly useful for environments
-where switches are not fully populated, thus much of the default iblinkinfo
-info is considered unuseful.  See
-.B ibnetdiscover
-for information on caching ibnetdiscover output.
-.TP
-\fB\-\-switches\-only\fR
-Show only switches in output.
-.TP
-\fB\-\-cas\-only\fR
-Show only CAs in output.
-
-.SH AUTHOR
-.TP
-Ira Weiny
-.RI < wei...@llnl.gov >
diff --git a/man/iblinkinfo.8.in b/man/iblinkinfo.8.in
new file mode 100644
index 0000000..6e7241b
--- /dev/null
+++ b/man/iblinkinfo.8.in
@@ -0,0 +1,213 @@
+.TH IBLINKINFO 8 "Jan 24, 2008" "OpenIB" "OpenIB Diagnostics"
+
+.SH NAME
+iblinkinfo \- report link info for all links in the fabric
+
+.SH SYNOPSIS
+.B iblinkinfo
+   [-hcdl -C <ca_name> -P <ca_port> -p -S <port_guid> -G <port_guid> -D 
<direct_route> \-\-load\-cache <filename>]
+
+.SH DESCRIPTION
+.PP
+iblinkinfo reports link information for each port in an IB fabric, node by 
node.
+Optionally, iblinkinfo can do partial scans and limit its output to parts of a
+fabric.
+
+Alternately, in "check mode" iblinkinfo scans an attached IB fabric, reads the
+ib fabric config file, and checks the two.  Checks performed include invalid
+cabling, downed/disabled ports, invalid speed, and invalid width's.
+
+While iblinkinfo can create it's config file from a scan of an IB fabric this
+is not the intended use case.  The fabric config is intended to document the
+desired cabling and properties of an IB fabric, generated from vendor cabling
+documentation.  This document can then be verified against reality by
+iblinkinfo -c.  For simply diffing the fabric from one run to the next both
+ibnetdiscover and iblinkinfo have cache capabilities.
+
+See \fBFILES\fR for more information on the configuration file format.
+
+.SH OPTIONS
+
+.PP
+.TP
+\fB\-S <port_guid>\fR \fB\-G <port_guid>\fR \fB\-\-port\-guid\fR
+start partial scan at the port specified by <port_guid> (hex format)
+.TP
+\fB\-D <direct_route>\fR
+start partial scan at the port specified by the direct route path.
+.TP
+\fB\-l\fR
+Print all information for each link on one line. Default is to print a header
+with the node information and then a list for each port (useful for
+grep\'ing output).
+.TP
+\fB\-d\fR
+Print only nodes which have a port in the "Down" state.
+.TP
+\fB\-p\fR
+Print additional port settings (<LifeTime>,<HoqLife>,<VLStallCount>)
+.TP
+\fB\-C <ca_name>\fR    use the specified ca_name for the search.
+.TP
+\fB\-P <ca_port>\fR    use the specified ca_port for the search.
+.TP
+\fB\-R\fR (This option is obsolete and does nothing)
+.TP
+\fB\-\-load\-cache\fR <filename>
+Load and use the cached ibnetdiscover data stored in the specified
+filename.  May be useful for outputting and learning about other
+fabrics or a previous state of a fabric.  Cannot be used if user
+specifies a direct route path.  See
+.B ibnetdiscover
+for information on caching ibnetdiscover output.
+.TP
+\fB\-\-diff\fR <filename>
+Load cached ibnetdiscover data and do a diff comparison to the current
+network or another cache.  A special diff output for iblinkinfo
+output will be displayed showing differences between the old and current
+fabric links.  Be default, the following are compared for differences:
+port connections and port state.  See
+.B ibnetdiscover
+for information on caching ibnetdiscover output.
+.TP
+\fB\-\-diffcheck\fR <key(s)>
+Specify what diff checks should be done in the \fB\-\-diff\fR option above.
+Comma separate multiple diff check key(s).  The available diff checks
+are:\fIport\fR = port connections, \fIstate\fR = port state, \fIlid\fR = lids,
+\fInodedesc\fR = node descriptions.  If \fIport\fR is specified alongside 
\fIlid\fR
+or \fInodedesc\fR, remote port lids and node descriptions will also be 
compared.
+.TP
+\fB\-\-filterdownports\fR <filename>
+Filter downports indicated in a ibnetdiscover cache.  If a port was previously
+indicated as down in the specified cache, and is still down, do not output it 
in the
+resulting output.  This option may be particularly useful for environments
+where switches are not fully populated, thus much of the default iblinkinfo
+info is considered unuseful.  See
+.B ibnetdiscover
+for information on caching ibnetdiscover output.
+
+.TP
+\fB\-\-switches\-only\fR
+Show only switches in output. (does not affect "check" mode)
+.TP
+\fB\-\-cas\-only\fR
+Show only CAs in output. (does not affect "check" mode)
+
+
+.SH CHECK OPTIONS
+.TP
+"Check" and "generate" options apply only when XML support was enabled for the 
build.
+
+.TP
+\fB\-check, \-c\fR
+Check links against ibfabricconf.xml config.
+
+.TP
+\fB\-config <ibfabricconf>\fR
+Specify an alternate config file (default: 
@IBDIAG_CONFIG_PATH@/ibfabricconf.xml)
+
+.TP
+\fB\-\-downnodes <nodelist>\fR
+Specify nodes which are known to be off thus indicating that links to those
+nodes are known to be down.  "nodelist" is a comma separated list of node
+description names.
+
+.TP
+\fB\-\-smlid <lid>\fR
+Specify an smlid to verify on all active ports.
+
+.TP
+\fB\-\-addr-info <lid>\fR
+Print port GUID and LID information for the ports being reported as errors.
+
+
+.SH GENERATE OPTIONS
+
+Although not the intended use case for this utility is it understood that the
+generation of this config file from an existing fabric can be very useful.  The
+following options allow for this.
+
+.TP
+\fB\-\-generate\-config <config>\fR
+Generate a config file from a scan of the fabric.  NOTE that this config file
+is somewhat generic in nature as it does not include any link parameters such
+as speed or width.  Most fabrics are somewhat homogeneous in nature.  It is
+intended that this config file be modified with these parameters as global
+settings.
+
+.TP
+\fB\-\-ignore <regex>\fR
+when generating a config skip nodes matching <regex>
+
+.TP
+\fB\-\-missing\fR
+insert place holders for disconnected ports
+
+
+.SH EXIT STATUS
+
+0 on success, -1 on failure.
+
+If check mode is used return 1 if inconsistencies are found, otherwise 0.
+
+.SH FILES
+
+\fBibfabricconf.xml\fR is an XML file which describes all the connections in a
+fabric.  This config file has the following features:
+
+.TP
+Config entry's are "name" based.
+There are no GUID's, LIDs, etc.
+As such misnamed nodes (posibly supplied by the conf file
+"ib-node-name-map" or by miss-programmed node description fields) will show
+up as errors.  The reasoning for this is iblinkinfo is a tool used by
+admins to debug problems in a known network layout.  GUID's can change as
+bad hardware is swapped out.  Therefore a logical view of the fabric
+is much more useful and presented in ibfabricconf.xml
+
+.TP
+Ports which are not specified are assumed to be down.
+Checks during a fabric scan will report active links on those ports as errors.
+
+.TP
+Properties are inherited from parent to child in the XML.
+For example if the entire fabric is to be 4X/QDR then only the fabric XML tag 
needs to
+be specified as 'speed="QDR" width="4X"'.  However, any link/node
+specification can have properties set which overrides itself and it's
+children.
+
+.TP
+Ports which are listed a second time will over ride the previous entry.
+This is very useful for overriding the internal links of the large
+switches after using the "chassis" tag.  On the other hand caution should
+be used in generating your config files.
+
+.TP
+Common "chassis" configs can be included using the "chassis" tag.
+This makes defining the internal connections of large switches very easy.  
Using a
+chassis tag will automatically create all the internal links for
+those switches.  The name of the chassis will be prepended to the
+internal switches found in the chassis.  For example:
+
+<chassis name="ibcore1" model="QLogic_9240"></chassis>
+
+results to the following names:
+
+"ibcore1 SP1a", "ibcore1 SP1b", etc.
+
+"ibcore1 L1a", "ibcore1 L2a", "ibcore1 Leaf 3 Chip A", etc.
+
+Internal switch names can be changed if the names used in the config file
+are not sufficient.
+
+(See @IBDIAG_CONFIG_PATH@/chassis_fabricconfs
+for a list of chassis which have alredy been defined.  Submitions of
+additional chasis config files are always welcome.)
+
+.TP
+A "subfabric" tag allows you to specify the properties for a group of entries.
+
+.SH AUTHOR
+.TP
+Ira Weiny
+.RI < wei...@llnl.gov >
diff --git a/src/checkfabric.c b/src/checkfabric.c
new file mode 100644
index 0000000..1aa3003
--- /dev/null
+++ b/src/checkfabric.c
@@ -0,0 +1,822 @@
+/*
+ * Copyright (c) 2011 Lawrence Livermore National Security.  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 <regex.h>
+
+#include <glib.h>
+
+/* global IB headers */
+#include <complib/cl_nodenamemap.h>
+#include <infiniband/ibnetdisc.h>
+#include <infiniband/ibfabricconf.h>
+
+/* local headers */
+#include "ibdiag_common.h"
+#include "checkfabric.h"
+
+typedef struct {
+       uint64_t guid;
+} guid_list_item_t;
+typedef struct {
+       FILE *fp;
+       char *ignore_regex;
+       int print_missing;
+       GSList * visited_nodes; /* list guid_list_item_t */
+       int vn_cnt;
+} print_node_data_t;
+
+/* list of node name strings */
+typedef struct nodelist
+{
+       int cnt;
+       GSList *list;
+} nodelist_t;
+
+/* Globals */
+static nn_map_t *node_name_map;
+static int smlid = 0;
+static ibfc_conf_t *fabricconf = NULL;
+static char *fabricconffile = NULL;
+static nodelist_t *downnodes;
+static char *fabric_name = "fabric";
+static int check_node_rc = 0;
+static int print_port_guids = 0;
+static int print_addr_info = 0;
+
+static struct {
+       int num_ports;
+       int pn_down;
+       int pn_init;
+       int pn_armed;
+       int pn_active;
+       int pn_disabled;
+       int pn_sdr;
+       int pn_ddr;
+       int pn_qdr;
+       int pn_fdr;
+       int pn_edr;
+       int pn_1x;
+       int pn_4x;
+       int pn_8x;
+       int pn_12x;
+       int pn_undef;
+} totals = {
+       num_ports   : 0,
+       pn_down     : 0,
+       pn_init     : 0,
+       pn_armed    : 0,
+       pn_active   : 0,
+       pn_disabled : 0,
+       pn_sdr      : 0,
+       pn_ddr      : 0,
+       pn_qdr      : 0,
+       pn_fdr      : 0,
+       pn_edr      : 0,
+       pn_1x       : 0,
+       pn_4x       : 0,
+       pn_8x       : 0,
+       pn_12x      : 0,
+       pn_undef    : 0
+};
+
+typedef struct port_vis {
+       struct port_vis *next;
+       uint64_t guid;
+       int pnum;
+} port_vis_t;
+
+port_vis_t *vis_head = NULL;
+
+static nodelist_t * nodelist_create(char *downnodes_str)
+{
+       char *last, *tok;
+       char *tmp_str = strdup(downnodes_str);
+       nodelist_t *rc = (nodelist_t *)calloc(1, sizeof(*rc));
+
+       if (!rc)
+               return (NULL);
+
+       tok = strtok_r(tmp_str, ",", &last);
+       while (tok) {
+               gpointer tmp = (gpointer)strdup(tok);
+               rc->list = g_slist_append(rc->list, tmp);
+               rc->cnt++;
+               tok = strtok_r(NULL, ",", &last);
+       }
+
+       free(tmp_str);
+       return (rc);
+}
+
+static void free_node(gpointer elem, gpointer user)
+{
+       free(elem);
+}
+
+static void nodelist_destroy(nodelist_t *nodelist)
+{
+       if (!nodelist)
+               return;
+
+       g_slist_foreach(nodelist->list, free_node, NULL);
+       g_slist_free(nodelist->list);
+       free(nodelist);
+}
+
+static int nodelist_find(nodelist_t *nodelist, char *target)
+{
+       int i = 0;
+       for (i = 0; i < nodelist->cnt; i++) {
+               gpointer t = g_slist_nth_data(nodelist->list, i);
+               if (t && strcmp((const char *)t, (const char *)target) == 0)
+                       return (1);
+       }
+
+       return (0);
+}
+
+
+static void mark_port_seen(uint64_t guid, int pnum)
+{
+       port_vis_t *tmp = (port_vis_t *)calloc(1, sizeof *tmp);
+       if (!tmp) {
+               fprintf(stderr, "calloc failure\n");
+               exit(1);
+       }
+       tmp->guid = guid;
+       tmp->pnum = pnum;
+       tmp->next = vis_head;
+       vis_head = tmp;
+}
+
+static int port_seen(uint64_t guid, int pnum)
+{
+       port_vis_t *cur;
+       for (cur = vis_head; cur; cur = cur->next) {
+               if (guid == cur->guid && pnum == cur->pnum)
+                       return (1);
+       }
+       return (0);
+}
+
+static void free_seen(void)
+{
+       port_vis_t *cur = vis_head;
+       while (cur) {
+               port_vis_t *tmp = cur;
+               cur = cur->next;
+               free(tmp);
+       }
+}
+
+void
+print_port_stats(void)
+{
+       printf("\nStats Summary: (%d total physical ports)\n", 
totals.num_ports);
+       if (totals.pn_down)
+               printf("   %d down ports(s)\n", totals.pn_down);
+       if (totals.pn_disabled)
+               printf("   %d disabled ports(s)\n", totals.pn_disabled);
+       if (totals.pn_1x)
+               printf("   %d link(s) at 1X\n", totals.pn_1x);
+       if (totals.pn_4x)
+               printf("   %d link(s) at 4X\n", totals.pn_4x);
+       if (totals.pn_8x)
+               printf("   %d link(s) at 8X\n", totals.pn_8x);
+       if (totals.pn_12x)
+               printf("   %d link(s) at 12X\n", totals.pn_12x);
+       if (totals.pn_sdr)
+               printf("   %d link(s) at 2.5 Gbps (SDR)\n", totals.pn_sdr);
+       if (totals.pn_ddr)
+               printf("   %d link(s) at 5.0 Gbps (DDR)\n", totals.pn_ddr);
+       if (totals.pn_qdr)
+               printf("   %d link(s) at 10.0 Gbps (QDR)\n", totals.pn_qdr);
+       if (totals.pn_fdr)
+               printf("   %d link(s) at 14.0 Gbps (FDR)\n", totals.pn_fdr);
+       if (totals.pn_edr)
+               printf("   %d link(s) at 25.0 Gbps (EDR)\n", totals.pn_edr);
+}
+
+
+static void cf_print_port(char *node_name, ibnd_node_t * node, ibnd_port_t * 
port,
+                  ibfc_port_t *portconf, int inc_attributes)
+{
+       char width[64], speed[64], state[64], physstate[64];
+       char remote_addr_str[256];
+       char remote_str[256];
+       char link_str[256];
+       char width_msg[256];
+       char speed_msg[256];
+       char ext_port_str[256];
+       int iwidth, ispeed, istate, iphystate;
+       int n = 0;
+
+       if (!port)
+               return;
+
+       iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
+       ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
+       istate = mad_get_field(port->info, 0, IB_PORT_STATE_F);
+       iphystate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F);
+
+       remote_addr_str[0] = '\0';
+       remote_str[0] = '\0';
+       link_str[0] = '\0';
+       width_msg[0] = '\0';
+       speed_msg[0] = '\0';
+
+       if (inc_attributes)
+       {
+               /* C14-24.2.1 states that a down port allows for invalid data 
to be
+                * returned for all PortInfo components except PortState and
+                * PortPhysicalState */
+               if (istate != IB_LINK_DOWN) {
+                       n = snprintf(link_str, 256, "(%s %s %6s/%8s)",
+                            mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 
64,
+                                         &iwidth),
+                            mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 
64,
+                                         &ispeed),
+                            mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
+                            mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64,
+                                         &iphystate));
+               } else {
+                       n = snprintf(link_str, 256, "(%6s/%8s)",
+                            mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
+                            mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64,
+                                         &iphystate));
+               }
+       }
+
+       if (port->remoteport) {
+               char *remap =
+                   remap_node_name(node_name_map, port->remoteport->node->guid,
+                                   port->remoteport->node->nodedesc);
+
+               if (port->remoteport->ext_portnum)
+                       snprintf(ext_port_str, 256, "%d",
+                                port->remoteport->ext_portnum);
+               else
+                       ext_port_str[0] = '\0';
+
+               get_max_msg(width_msg, speed_msg, 256, port);
+
+               if (print_addr_info) {
+                       if (print_port_guids)
+                               snprintf(remote_addr_str, 256,
+                                       " (0x%016" PRIx64 " %d)",
+                                       port->remoteport->guid,
+                                       port->remoteport->base_lid ?
+                                               port->remoteport->base_lid :
+                                               port->remoteport->node->smalid);
+                       else
+                               snprintf(remote_addr_str, 256,
+                                       " (0x%016" PRIx64 " %d)",
+                                       port->remoteport->node->guid,
+                                       port->remoteport->base_lid ?
+                                               port->remoteport->base_lid :
+                                               port->remoteport->node->smalid);
+               }
+
+               snprintf(remote_str, 256,
+                        "p:%3d[%2s] \"%s\"%s (%s %s)\n",
+                        port->remoteport->portnum, ext_port_str, remap,
+                        remote_addr_str,
+                        width_msg, speed_msg);
+               free(remap);
+       } else if (portconf) {
+               char prop[256];
+               snprintf(remote_str, 256,
+                        "p:%3d \"%s\" (Should be: %s Active)\n",
+                               ibfc_port_get_port_num(portconf),
+                               ibfc_port_get_name(portconf),
+                               ibfc_sprintf_prop(prop, 256, portconf));
+       } else
+               snprintf(remote_str, 256, " [  ] \"\" ( )\n");
+
+       if (port->ext_portnum)
+               snprintf(ext_port_str, 256, "%d", port->ext_portnum);
+       else
+               ext_port_str[0] = '\0';
+
+       if (print_addr_info)
+               printf("(0x%016" PRIx64 " %d) ",
+                       print_port_guids ? port->guid : node->guid,
+                       port->base_lid ?  port->base_lid : port->node->smalid);
+
+       printf ("\"%s\" ", node_name);
+       if (link_str[0] != '\0')
+               printf("p:%3d[%2s] <==%s==>  %s",
+                       port->portnum, ext_port_str, link_str, remote_str);
+       else
+               printf("p:%3d[%2s] <==>  %s",
+                       port->portnum, ext_port_str, remote_str);
+}
+
+void
+print_config_port(ibfc_port_t *port)
+{
+       printf ("\"%s\" p:%3d[  ] <==>  ",
+               ibfc_port_get_name(port),
+               ibfc_port_get_port_num(port));
+
+       printf ("p:%3d[  ] ", 
ibfc_port_get_port_num(ibfc_port_get_remote(port)));
+
+       printf ("\"%s\"\n",
+               ibfc_port_get_name(ibfc_port_get_remote(port)));
+}
+
+void compare_port(ibfc_port_t *portconf, char *node_name, ibnd_node_t *node, 
ibnd_port_t *port)
+{
+       int iwidth, ispeed, istate, iphysstate;
+
+       iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
+       ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
+       istate = mad_get_field(port->info, 0, IB_PORT_STATE_F);
+       iphysstate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F);
+
+       ibfc_port_t *rem_portconf = ibfc_port_get_remote(portconf);
+       char *rem_node_name = ibfc_port_get_name(rem_portconf);
+
+       if (istate != IB_LINK_ACTIVE) {
+               int print = 0;
+               int hostdown = 0;
+
+               if (downnodes &&
+                   nodelist_find(downnodes, rem_node_name)) {
+                       hostdown = 1;
+               }
+
+               if (iphysstate == IB_PORT_PHYS_STATE_DISABLED) {
+                       printf("ERR: port disabled");
+                       if (downnodes && !hostdown)
+                               printf(" (host UP): ");
+                       else
+                               printf(": ");
+                       print = 1;
+               } else {
+                       if (!downnodes || !hostdown) {
+                               printf("ERR: port down: ");
+                               print = 1;
+                       }
+               }
+               if (print) {
+                       cf_print_port(node_name, node, port, rem_portconf, 0);
+                       check_node_rc = 1;
+               }
+       } else {
+               char str[64];
+               int conf_width = ibfc_prop_get_width(
+                                       ibfc_port_get_prop(portconf));
+               int conf_speed = ibfc_prop_get_speed(
+                                       ibfc_port_get_prop(portconf));
+               int rem_port_num = ibfc_port_get_port_num(rem_portconf);
+               char *rem_remap = NULL;
+               ibnd_port_t *remport = port->remoteport;
+
+               if (iwidth != conf_width) {
+                       printf("ERR: width != %s: ",
+                               mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F,
+                                       str, 64, &conf_width));
+                       cf_print_port(node_name, node, port, NULL, 1);
+                       check_node_rc = 1;
+               }
+               if (ispeed != conf_speed) {
+                       printf("ERR: speed != %s: ",
+                               mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F,
+                                       str, 64, &conf_speed));
+                       cf_print_port(node_name, node, port, NULL, 1);
+                       check_node_rc = 1;
+               }
+
+               if (remport) {
+                       rem_remap = remap_node_name(node_name_map,
+                                       port->remoteport->node->guid,
+                                       port->remoteport->node->nodedesc);
+                       if (strcmp(rem_node_name, rem_remap) != 0
+                           ||
+                           rem_port_num != port->remoteport->portnum) {
+                               printf("ERR: invalid link : ");
+                               cf_print_port(node_name, node, port, NULL, 0);
+                               printf("     Should be    : ");
+                               print_config_port(portconf);
+                               check_node_rc = 1;
+                       }
+                       free(rem_remap);
+               } else {
+                       fprintf(stderr, "ERR: query failure: ");
+                       cf_print_port(node_name, node, port, rem_portconf, 1);
+                       check_node_rc = 1;
+               }
+       }
+}
+
+void check_config(char *node_name, ibnd_node_t *node, ibnd_port_t *port)
+{
+       int istate;
+       ibfc_port_t *portconf = NULL;
+
+       portconf = ibfc_get_port(fabricconf, node_name, port->portnum);
+       istate = mad_get_field(port->info, 0, IB_PORT_STATE_F);
+       if (portconf) {
+               compare_port(portconf, node_name, node, port);
+       } else if (istate == IB_LINK_ACTIVE) {
+               char *remote_name = NULL;
+               ibnd_node_t *remnode;
+               ibnd_port_t *remport = port->remoteport;
+               if (!remport) {
+                       printf("ERROR: ibnd error; port ACTIVE "
+                               "but no remote port! (Lights on, "
+                               "nobody home?)\n");
+                       check_node_rc = 1;
+                       goto invalid_active;
+               }
+               remnode = remport->node;
+               remote_name = remap_node_name(node_name_map, remnode->guid,
+                                       remnode->nodedesc);
+               portconf = ibfc_get_port(fabricconf, remote_name, 
remport->portnum);
+               if (portconf) {
+                       compare_port(portconf, remote_name, remnode, remport);
+               } else {
+invalid_active:
+                       printf("ERR: Unconfigured active link: ");
+                       cf_print_port(node_name, node, port, NULL, 1);
+                       check_node_rc = 1;
+               }
+               free(remote_name); /* OK; may be null */
+       }
+}
+
+void check_port(char *node_name, ibnd_node_t * node, ibnd_port_t * port)
+{
+       int iwidth, ispeed, istate, iphysstate;
+       int n_undef = totals.pn_undef;
+
+       totals.num_ports++;
+
+       iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
+       ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
+       istate = mad_get_field(port->info, 0, IB_PORT_STATE_F);
+       iphysstate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F);
+
+       switch (istate) {
+               case IB_LINK_DOWN: totals.pn_down++; break;
+               case IB_LINK_INIT: totals.pn_init++; break;
+               case IB_LINK_ARMED: totals.pn_armed++; break;
+               case IB_LINK_ACTIVE: totals.pn_active++; break;
+               default:  totals.pn_undef++; break;
+       }
+
+       switch (iphysstate) {
+               case IB_PORT_PHYS_STATE_DISABLED: totals.pn_disabled++; break;
+               default: break;
+       }
+
+       if (istate == IB_LINK_ACTIVE) {
+               switch (iwidth) {
+                       case IB_LINK_WIDTH_ACTIVE_1X: totals.pn_1x++; break;
+                       case IB_LINK_WIDTH_ACTIVE_4X: totals.pn_4x++; break;
+                       case IB_LINK_WIDTH_ACTIVE_8X: totals.pn_8x++; break;
+                       case IB_LINK_WIDTH_ACTIVE_12X: totals.pn_12x++; break;
+                       default:  totals.pn_undef++; break;
+               }
+               switch (ispeed) {
+                       case IB_LINK_SPEED_ACTIVE_2_5: totals.pn_sdr++; break;
+                       case IB_LINK_SPEED_ACTIVE_5: totals.pn_ddr++; break;
+                       case IB_LINK_SPEED_ACTIVE_10: totals.pn_qdr++; break;
+                       default:  totals.pn_undef++; break;
+               }
+       }
+
+       if (totals.pn_undef > n_undef) {
+               printf("WARN: Undefined value found: ");
+               cf_print_port(node_name, node, port, NULL, 1);
+               check_node_rc = 1;
+       }
+
+       if (fabricconf)
+               check_config(node_name, node, port);
+}
+
+static void check_addrs(ibnd_port_t *port)
+{
+       int checklid = 0;
+       char *remap = NULL;
+
+       if (!port)
+               return;
+
+       if (port->node->type == IB_NODE_SWITCH) {
+               port = port->node->ports[0];
+               if (!port)
+                       return;
+       }
+
+       remap = remap_node_name(node_name_map, port->node->guid,
+                                   port->node->nodedesc);
+
+       checklid = mad_get_field(port->info, 0, IB_PORT_SMLID_F);
+
+       if (smlid && smlid != checklid) {
+               printf("ERROR smlid %d != %d (expected) on node %s\n", checklid,
+                               smlid, remap);
+               check_node_rc = 1;
+       }
+
+       if (!port->base_lid) {
+               printf("ERROR lid == 0 found on node %s\n", remap);
+               check_node_rc = 1;
+       }
+
+       if (!port->guid) {
+               printf("ERROR guid == 0 found on node %s\n", remap);
+               check_node_rc = 1;
+       }
+
+       free(remap);
+}
+
+static void check_node(ibnd_node_t * node, void *user_data)
+{
+       int i = 0;
+       char *remap =
+           remap_node_name(node_name_map, node->guid, node->nodedesc);
+
+       for (i = 1; i <= node->numports; i++) {
+               ibnd_port_t *port = node->ports[i];
+               if (!port)
+                       continue;
+               check_addrs(port);
+               if (!port_seen(node->guid, i)) {
+                       check_port(remap, node, port);
+                       mark_port_seen(node->guid, i);
+                       if (port->remoteport) {
+                               mark_port_seen(port->remoteport->node->guid,
+                                       port->remoteport->portnum);
+                               totals.num_ports++;
+                       }
+               }
+       }
+       free(remap);
+}
+
+static int ignore_node(char *node_name, char *ignore_regex)
+{
+       static regex_t exp;
+       static int regex_compiled = 0;
+       static int regex_failed = 0;
+
+       if (!ignore_regex)
+               return 0;
+
+       if (!regex_compiled) { /* only compile it one time */
+               int rc;
+               if ((rc = regcomp(&exp, ignore_regex, REG_ICASE |
+                               REG_NOSUB | REG_EXTENDED)) != 0) {
+                       fprintf(stderr, "ERROR: regcomp failed on \"%s\": %d\n",
+                               ignore_regex, rc);
+                       regex_failed = 1;
+                       return 0;
+               }
+               regex_compiled = 1;
+       }
+
+       return (regexec(&exp, node_name, 0, NULL, 0) == 0);
+}
+
+static void mark_node_seen(print_node_data_t *data, uint64_t node_guid)
+{
+       guid_list_item_t *i = malloc(sizeof(*i));
+       if (i == NULL) {
+               fprintf(stderr, "ERROR: malloc failed\n");
+               return;
+       }
+       i->guid = node_guid;
+       data->visited_nodes = g_slist_append(data->visited_nodes, (gpointer)i);
+       data->vn_cnt++;
+}
+
+static int node_seen(print_node_data_t *data, uint64_t node_guid)
+{
+       int i = 0;
+       for (i = 0; i < data->vn_cnt; i++) {
+               gpointer t = g_slist_nth_data(data->visited_nodes, i);
+               if (((guid_list_item_t *)t)->guid == node_guid)
+                       return (1);
+       }
+       return (0);
+}
+
+static void free_visited_nodes(print_node_data_t *data)
+{
+       if (!data->visited_nodes)
+               return;
+
+       g_slist_foreach(data->visited_nodes, free_node, NULL);
+       g_slist_free(data->visited_nodes);
+}
+
+static void print_node_xml(ibnd_node_t *node, void *ud)
+{
+       print_node_data_t *data = (print_node_data_t *)ud;
+       FILE *fp = data->fp;
+
+       int header = 0;
+       int i = 0;
+       char * node_name = remap_node_name(node_name_map,
+                                       node->guid,
+                                       node->nodedesc);
+
+       if (ignore_node(node_name, data->ignore_regex))
+               goto ignore;
+
+       for (i = 1; i <= node->numports; i++) {
+               if (node->ports[i] && node->ports[i]->remoteport) {
+                       char *rem_name = remap_node_name(node_name_map,
+                                       node->ports[i]->remoteport->node->guid,
+                                       
node->ports[i]->remoteport->node->nodedesc);
+                       if (!ignore_node(rem_name, data->ignore_regex)
+                           && !node_seen(data,
+                                       
node->ports[i]->remoteport->node->guid)) {
+                               if (!header) {
+                                       fprintf(fp, "\t<linklist 
name=\"%s\">\n", node_name);
+                                       header = 1;
+                               }
+                               fprintf(fp, "\t\t<port num=\"%d\">", i);
+                               fprintf(fp, "<r_port>%d</r_port>",
+                                       node->ports[i]->remoteport->portnum);
+                               fprintf(fp, "<r_node>%s</r_node>", rem_name);
+                               fprintf(fp, "</port>\n");
+                       }
+               } else if (data->print_missing) {
+                       if (!header) {
+                               fprintf(fp, "\t<linklist name=\"%s\">\n", 
node_name);
+                               header = 1;
+                       }
+                       fprintf(fp, "<!--\n");
+                       fprintf(fp, "\t\t<port num=\"%d\">", i);
+                       fprintf(fp, "<r_port>XXXXX</r_port>");
+                       fprintf(fp, "<r_node>YYYYY</r_node>");
+                       fprintf(fp, "</port>\n");
+                       fprintf(fp, "-->\n");
+               }
+       }
+       if (header)
+               fprintf(fp, "\t</linklist>\n");
+
+       mark_node_seen(data, node->guid);
+
+ignore:
+       free(node_name);
+}
+
+
+int generate_from_fabric(ibnd_fabric_t *fabric, char *generate_file, nn_map_t 
*name_map,
+                       char *ignore_regex, int print_missing)
+{
+       print_node_data_t data;
+       FILE *fp = fopen(generate_file, "w+");
+       node_name_map = name_map;
+
+       memset(&data, 0, sizeof(data));
+
+       if (!fp) {
+               fprintf(stderr, "Failed to open %s: %s\n", generate_file, 
strerror(errno));
+               return 1;
+       }
+
+       fprintf(fp, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
+       fprintf(fp, "<!DOCTYPE ibfabric SYSTEM \"ibfabric.dtd\">\n\n");
+       fprintf(fp, "<fabric name=\"%s\">\n", fabric_name);
+
+       data.fp = fp;
+       data.ignore_regex = ignore_regex;
+       data.print_missing = print_missing;
+
+       ibnd_iter_nodes_type(fabric, print_node_xml, IB_NODE_SWITCH, (void 
*)&data);
+       ibnd_iter_nodes_type(fabric, print_node_xml, IB_NODE_CA, (void *)&data);
+       ibnd_iter_nodes_type(fabric, print_node_xml, IB_NODE_ROUTER, (void 
*)&data);
+
+       fprintf(fp, "</fabric>\n");
+
+       free_visited_nodes(&data);
+
+       return 0;
+}
+
+int check_links(ib_portid_t *port_id,
+               struct ibmad_port *ibmad_port,
+               ibnd_fabric_t *fabric,
+               nn_map_t *name_map,
+               check_flags_t *flags)
+{
+       int rc = 0;
+       node_name_map = name_map;
+       ibnd_port_t *p = NULL;
+       smlid = flags->sm_lid;
+       print_addr_info = flags->print_addr_info;
+
+       if (flags->downnodes_str)
+               downnodes = nodelist_create(flags->downnodes_str);
+
+       fabricconf = ibfc_alloc_conf();
+       if (!fabricconf) {
+               fprintf(stderr, "ERROR: Failed to alloc fabricconf\n");
+               exit(1);
+       }
+       ibfc_set_warn_dup(fabricconf, 1);
+
+       printf("Reading fabric conf file... ");
+
+       if (ibfc_parse_file(flags->fabricconffile, fabricconf)) {
+               fprintf(stderr, "WARN: Failed to parse link config file...\n");
+               ibfc_free(fabricconf);
+               fabricconf = NULL;
+               check_node_rc = -1;
+       }
+
+       printf("\nEvaluating connectively...\n");
+
+       if (!flags->all && flags->guid_str) {
+               if ((p = ibnd_find_port_guid(fabric, flags->guid)) != NULL) {
+                       check_node(p->node, NULL);
+                       rc = check_node_rc;
+               } else {
+                       fprintf(stderr, "Failed to find port: %s\n",
+                               flags->guid_str);
+                       rc = -1;
+               }
+       } else if (!flags->all && flags->dr_path) {
+               uint64_t guid;
+               uint8_t ni[IB_SMP_DATA_SIZE] = { 0 };
+
+               if (!smp_query_via(ni, port_id, IB_ATTR_NODE_INFO, 0,
+                                  ibd_timeout, ibmad_port)){
+                       rc = -1;
+                       goto Exit;
+               }
+               mad_decode_field(ni, IB_NODE_GUID_F, &guid);
+
+               if ((p = ibnd_find_port_guid(fabric, guid)) != NULL) {
+                       check_node(p->node, NULL);
+                       rc = check_node_rc;
+               } else {
+                       fprintf(stderr, "Failed to find node: %s\n",
+                               flags->dr_path);
+                       rc = -1;
+               }
+       } else {
+               ibnd_iter_nodes(fabric, check_node, NULL);
+               rc = check_node_rc;
+       }
+       print_port_stats();
+
+Exit:
+       nodelist_destroy(downnodes);
+       free_seen();
+       return rc;
+}
+
diff --git a/src/checkfabric.h b/src/checkfabric.h
new file mode 100644
index 0000000..bffa876
--- /dev/null
+++ b/src/checkfabric.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011 Lawrence Livermore National Security.  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 __CHECK_FABRIC_H_
+#define __CHECK_FABRIC_H_
+
+/* check flags */
+typedef struct {
+       int all;
+       char *guid_str;
+       uint64_t guid;
+       char *dr_path;
+       char *downnodes_str;
+       char *fabricconffile;
+       uint16_t sm_lid;
+       int print_addr_info;
+} check_flags_t;
+
+int generate_from_fabric(ibnd_fabric_t *fabric, char *generate_file,
+                       nn_map_t *name_map, char *ignore_regex,
+                       int print_missing);
+
+int check_links(ib_portid_t *port_id,
+               struct ibmad_port *ibmad_port,
+               ibnd_fabric_t *fabric,
+               nn_map_t *name_map,
+               check_flags_t *flags);
+
+#endif /* __CHECK_FABRIC_H_ */
+
diff --git a/src/iblinkinfo.c b/src/iblinkinfo.c
index 00c7bc0..d23102a 100644
--- a/src/iblinkinfo.c
+++ b/src/iblinkinfo.c
@@ -48,6 +48,7 @@
 #include <getopt.h>
 #include <errno.h>
 #include <inttypes.h>
+#include <limits.h>
 
 #include <complib/cl_nodenamemap.h>
 #include <infiniband/ibnetdisc.h>
@@ -61,8 +62,9 @@
 
 #define DIFF_FLAG_DEFAULT (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_PORT_STATE)
 
+nn_map_t *node_name_map = NULL;
+
 static char *node_name_map_file = NULL;
-static nn_map_t *node_name_map = NULL;
 static char *load_cache_file = NULL;
 static char *diff_cache_file = NULL;
 static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT;
@@ -80,6 +82,18 @@ static int add_sw_settings = 0;
 static int only_flag = 0;
 static int only_type = 0;
 
+#ifdef HAVE_XML
+#include <infiniband/ibfabricconf.h>
+#include "checkfabric.h"
+
+static int check_mode = 0;
+static char *generate_config = NULL;
+static char *ignore_regex = NULL;
+static int print_missing = 0;
+
+check_flags_t check_flags;
+#endif
+
 int filterdownport_check(ibnd_node_t * node, ibnd_port_t * port)
 {
        ibnd_node_t *fsw;
@@ -488,6 +502,57 @@ int diff_node(ibnd_node_t * node, ibnd_fabric_t * 
orig_fabric,
        return 0;
 }
 
+static int print_links(ib_portid_t *port_id,
+                      struct ibmad_port *ibmad_port,
+                      ibnd_fabric_t *fabric,
+                      ibnd_fabric_t *diff_fabric)
+{
+       int rc = 0;
+
+       if (!all && guid_str) {
+               ibnd_port_t *p = ibnd_find_port_guid(fabric, guid);
+               if (p && (!only_flag || p->node->type == only_type)) {
+                       ibnd_node_t *n = p->node;
+                       if (diff_fabric)
+                               diff_node(n, diff_fabric, fabric);
+                       else
+                               print_node(n, NULL);
+               }
+               else
+                       fprintf(stderr, "Failed to find port: %s\n", guid_str);
+       } else if (!all && dr_path) {
+               ibnd_port_t *p = NULL;
+               uint8_t ni[IB_SMP_DATA_SIZE] = { 0 };
+
+               if (!smp_query_via(ni, port_id, IB_ATTR_NODE_INFO, 0,
+                                  ibd_timeout, ibmad_port))
+                       return -1;
+               mad_decode_field(ni, IB_NODE_PORT_GUID_F, &(guid));
+
+               p = ibnd_find_port_guid(fabric, guid);
+               if (p && (!only_flag || p->node->type == only_type)) {
+                       ibnd_node_t *n = p->node;
+                       if (diff_fabric)
+                               diff_node(n, diff_fabric, fabric);
+                       else
+                               print_node(n, NULL);
+               }
+               else
+                       fprintf(stderr, "Failed to find port: %s\n", dr_path);
+       } else {
+               if (diff_fabric)
+                       diff_node(NULL, diff_fabric, fabric);
+               else {
+                       if (only_flag)
+                               ibnd_iter_nodes_type(fabric, print_node,
+                                                    only_type, NULL);
+                       else
+                               ibnd_iter_nodes(fabric, print_node, NULL);
+               }
+       }
+       return rc;
+}
+
 static int process_opt(void *context, int ch, char *optarg)
 {
        struct ibnd_config *cfg = context;
@@ -534,6 +599,32 @@ static int process_opt(void *context, int ch, char *optarg)
                only_flag = 1;
                only_type = IB_NODE_CA;
                break;
+#ifdef HAVE_XML
+       case 'c': /* check */
+               check_mode = 1;
+               break;
+       case 8: /* config */
+               check_flags.fabricconffile = strdup(optarg);
+               break;
+       case 9: /* downnodes */
+               check_flags.downnodes_str = strdup(optarg);
+               break;
+       case 10: /* smlid */
+               check_flags.sm_lid = (uint16_t)strtoul(optarg, NULL, 0);
+               break;
+       case 11: /* addr-info */
+               check_flags.print_addr_info = 1;
+               break;
+       case 12: /* generate-config */
+               generate_config = strdup(optarg);
+               break;
+       case 13: /* ignore */
+               ignore_regex = strdup(optarg);
+               break;
+       case 14: /* missing */
+               print_missing = 1;
+               break;
+#endif /* HAVE_XML */
        case 'S':
        case 'G':
                guid_str = optarg;
@@ -613,8 +704,30 @@ int main(int argc, char **argv)
                 "Output only switches"},
                {"cas-only", 7, 0, NULL,
                 "Output only CAs"},
+#ifdef HAVE_XML
+               {"\nCheck Fabric options:\n", 255, 0, NULL, ""}, /* dummy 
option */
+               {"check", 'c', 0, NULL,
+                "check fabric; against ibfabricconf.xml"},
+               {"config", 8, 1, "<ibfabricconf>",
+                "with '-c': specify an alternate config file default: 
"IBFC_DEF_CONFIG},
+               {"downnodes", 9, 1, "<nodelist>",
+                "with '-c': specify nodes which are known to be off.  "
+                "Suppreses \"down port\" errors on links connected to those 
nodes"},
+               {"smlid", 10, 1, "<smlid>",
+                "with '-c': specify an smlid to verify on all active ports\n"},
+               {"addr-info", 11, 0, "",
+                "with '-c': print node/port GUID and LID information \n"},
+
+               {"generate-config", 12, 1, "<config>",
+                "generate a config file"},
+               {"ignore", 13, 1, "<regex>",
+                "with '--generate-config': skip nodes matching regex"},
+               {"missing", 14, 0, NULL,
+                "with '--generate-config': insert place holders for 
dissconnected ports\n"},
+#endif
                {"GNDN", 'R', 0, NULL,
-                "(This option is obsolete and does nothing)"},
+                "(This option is obsolete and does nothing)\n"
+               "Common Options:\n"},
                {0}
        };
        char usage_args[] = "";
@@ -629,7 +742,7 @@ int main(int argc, char **argv)
        if (!ibmad_port) {
                fprintf(stderr, "Failed to open %s port %d\n", ibd_ca,
                        ibd_ca_port);
-               exit(1);
+               exit(-1);
        }
 
        if (ibd_timeout) {
@@ -641,7 +754,7 @@ int main(int argc, char **argv)
 
        if (dr_path && load_cache_file) {
                fprintf(stderr, "Cannot specify cache and direct route path\n");
-               exit(1);
+               exit(-1);
        }
 
        if (dr_path) {
@@ -671,7 +784,7 @@ int main(int argc, char **argv)
        if (load_cache_file) {
                if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) {
                        fprintf(stderr, "loading cached fabric failed\n");
-                       exit(1);
+                       exit(-1);
                }
        } else {
                if (resolved >= 0) {
@@ -686,52 +799,25 @@ int main(int argc, char **argv)
                if (!fabric &&
                    !(fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, 
&config))) {
                        fprintf(stderr, "discover failed\n");
-                       rc = 1;
+                       rc = -1;
                        goto close_port;
                }
        }
 
-       if (!all && guid_str) {
-               ibnd_port_t *p = ibnd_find_port_guid(fabric, guid);
-               if (p && (!only_flag || p->node->type == only_type)) {
-                       ibnd_node_t *n = p->node;
-                       if (diff_fabric)
-                               diff_node(n, diff_fabric, fabric);
-                       else
-                               print_node(n, NULL);
-               }
-               else
-                       fprintf(stderr, "Failed to find port: %s\n", guid_str);
-       } else if (!all && dr_path) {
-               ibnd_port_t *p = NULL;
-               uint8_t ni[IB_SMP_DATA_SIZE] = { 0 };
-
-               if (!smp_query_via(ni, &port_id, IB_ATTR_NODE_INFO, 0,
-                                  ibd_timeout, ibmad_port))
-                       return -1;
-               mad_decode_field(ni, IB_NODE_PORT_GUID_F, &(guid));
-
-               p = ibnd_find_port_guid(fabric, guid);
-               if (p && (!only_flag || p->node->type == only_type)) {
-                       ibnd_node_t *n = p->node;
-                       if (diff_fabric)
-                               diff_node(n, diff_fabric, fabric);
-                       else
-                               print_node(n, NULL);
-               }
-               else
-                       fprintf(stderr, "Failed to find port: %s\n", dr_path);
-       } else {
-               if (diff_fabric)
-                       diff_node(NULL, diff_fabric, fabric);
-               else {
-                       if (only_flag)
-                               ibnd_iter_nodes_type(fabric, print_node,
-                                                    only_type, NULL);
-                       else
-                               ibnd_iter_nodes(fabric, print_node, NULL);
-               }
-       }
+#ifdef HAVE_XML
+       if (generate_config)
+               rc = generate_from_fabric(fabric, generate_config, 
node_name_map,
+                                       ignore_regex, print_missing);
+       else if (check_mode) {
+               check_flags.all = all;
+               check_flags.guid_str = guid_str;
+               check_flags.guid = guid;
+               check_flags.dr_path = dr_path;
+               rc = check_links(&port_id, ibmad_port, fabric, node_name_map,
+                               &check_flags);
+       } else
+#endif
+               rc = print_links(&port_id, ibmad_port, fabric, diff_fabric);
 
        ibnd_destroy_fabric(fabric);
        if (diff_fabric)
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to