[Pkg-ofed-commits] [ibsim] 01/10: Imported Upstream version 0.6

Ana Beatriz Guerrero López ana at moszumanska.debian.org
Tue Jul 1 12:41:43 UTC 2014


This is an automated email from the git hooks/post-receive script.

ana pushed a commit to branch master
in repository ibsim.

commit 6411b539b6f0e1b06b075a1b21c9fdb890af0b4a
Author: Ana Guerrero López <ana at ekaia.org>
Date:   Tue Jul 1 14:15:22 2014 +0200

    Imported Upstream version 0.6
---
 defs.mk                 |  20 +-
 dist.sh                 |  23 --
 ibsim.spec              |  12 +-
 ibsim.spec.in           |  41 ---
 ibsim/ibsim.c           |  32 ++-
 ibsim/sim.h             | 101 +++++++-
 ibsim/sim_cmd.c         | 285 ++++++++++++++++++++-
 ibsim/sim_mad.c         | 607 ++++++++++++++++++++++++++++++++++++++++----
 ibsim/sim_net.c         |  17 +-
 tests/Makefile          |   2 +-
 tests/mcast_storm.c     | 429 ++++++++++++++++++++------------
 tests/query_many.c      | 309 +++++++++++++++++++++++
 tests/subnet_discover.c | 649 ++++++++++++++++++++++++++++++++++++++++++++++++
 umad2sim/sim_client.c   |  59 +++--
 umad2sim/sim_client.h   |   2 +-
 umad2sim/umad2sim.c     |  26 +-
 16 files changed, 2251 insertions(+), 363 deletions(-)

diff --git a/defs.mk b/defs.mk
index e3b9cc4..11256c0 100644
--- a/defs.mk
+++ b/defs.mk
@@ -2,26 +2,26 @@
 old_ofed:=/usr/local/ofed
 
 prefix:= $(strip $(if $(prefix),$(prefix),\
-	$(if $(wildcard $(old_ofed)/lib/libibumad.so \
+	$(if $(wildcard $(old_ofed)/lib64/libibumad.so \
 		$(old_ofed)/lib/libibumad.so),$(old_ofed),\
 	$(if $(wildcard /usr/local/lib/libibumad.so \
-		/usr/local/lib/libibumad.so),/usr/local,\
-	$(if $(wildcard /usr/lib /usr/lib),/usr,/tmp/unknown)))))
+		/usr/local/lib64/libibumad.so),/usr/local,\
+	$(if $(wildcard /usr/lib /usr/lib64),/usr,/tmp/unknown)))))
 
 libpath:= $(strip $(if $(libpath),$(libpath),\
-	$(if $(wildcard $(prefix)/lib/libibumad.so),\
-		$(prefix)/lib,$(prefix)/lib)))
+	$(if $(wildcard $(prefix)/lib64/libibumad.so),\
+		$(prefix)/lib64,$(prefix)/lib)))
 binpath:= $(if $(binpath),$(binpath),$(prefix)/bin)
 
-#IB_DEV_DIR:=$(HOME)/src/p
+#IB_DEV_DIR:=$(HOME)/src/m
 ifdef IB_DEV_DIR
- INCS:= $(foreach l, mad umad common, -I$(IB_DEV_DIR)/libib$(l)/include) \
+ INCS:= $(foreach l, mad umad, -I$(IB_DEV_DIR)/libib$(l)/include) \
   -I/usr/local/include
  LIBS:= \
-  $(foreach l, mad umad common, $(IB_DEV_DIR)/libib$(l)/.libs/libib$(l).so)
+  $(foreach l, mad umad, $(IB_DEV_DIR)/libib$(l)/.libs/libib$(l).so)
 else
- INCS:= -I$(dir $(libpath))/include
- LIBS:= -L$(libpath) -libmad -libumad -libcommon
+ INCS:= -I$(dir $(libpath))include
+ LIBS:= -L$(libpath) -libmad -libumad
 endif
 
 CFLAGS += -Wall -g -fpic -I. -I../include $(INCS)
diff --git a/dist.sh b/dist.sh
deleted file mode 100755
index 1ec554c..0000000
--- a/dist.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-
-ver=`cat ibsim/ibsim.c | sed -ne '/#define IBSIM_VERSION /s/^#define IBSIM_VERSION \"\(.*\)\"/\1/p'`
-rel=1
-distdir=ibsim-${ver}
-tarball=${distdir}.tar.gz
-
-test -z "$RELEASE" || rel=$RELEASE
-
-rm -f $tarball
-rm -rf $distdir
-mkdir $distdir
-
-files=`find . -name '*.[ch]' -o -name Makefile`
-cp -a --parents $files \
-	defs.mk README COPYING TODO net-examples scripts tests $distdir
-
-cat ibsim.spec.in \
-		| sed -e 's/@VERSION@/'$ver'/' -e 's/@RELEASE@/'$rel'/' -e 's/@TARBALL@/'$tarball'/' \
-		> $distdir/ibsim.spec
-
-tar czf $tarball $distdir
-rm -rf $distdir
diff --git a/ibsim.spec b/ibsim.spec
index 72a5d96..b65142a 100644
--- a/ibsim.spec
+++ b/ibsim.spec
@@ -1,17 +1,17 @@
 
-%define RELEASE  1.ofed1.4
-%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE}
+%define RELEASE 1
+%define rel %{?CUSTOM_RELEASE}%{!?CUSTOM_RELEASE:%RELEASE}
 
 Summary: InfiniBand fabric simulator for management
 Name: ibsim
-Version: 0.5
-Release: 1.ofed1.4
+Version: 0.6
+Release: %rel%{?dist}
 License: GPLv2 or BSD
 Group: System Environment/Libraries
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-Source: http://www.openfabrics.org/downloads/ibsim-0.5.tar.gz
+Source: http://www.openfabrics.org/downloads/management/ibsim-0.6.tar.gz
 Url: http://openfabrics.org/
-BuildRequires: libibmad-devel, libibcommon-devel, libibumad-devel
+BuildRequires: libibmad-devel, libibumad-devel
 
 %description
 ibsim provides simulation of infiniband fabric for using with OFA OpenSM, diagnostic and management tools.
diff --git a/ibsim.spec.in b/ibsim.spec.in
deleted file mode 100644
index 6c848af..0000000
--- a/ibsim.spec.in
+++ /dev/null
@@ -1,41 +0,0 @@
-
-%define RELEASE @RELEASE@
-%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE}
-
-Summary: InfiniBand fabric simulator for management
-Name: ibsim
-Version: @VERSION@
-Release: %rel%{?dist}
-License: GPLv2 or BSD
-Group: System Environment/Libraries
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-Source: http://www.openfabrics.org/downloads/management/@TARBALL@
-Url: http://openfabrics.org/
-BuildRequires: libibmad-devel, libibcommon-devel, libibumad-devel
-
-%description
-ibsim provides simulation of infiniband fabric for using with OFA OpenSM, diagnostic and management tools.
-
-%prep
-%setup -q
-
-%build
-export CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}"
-export LDFLAGS="${LDFLAGS:-${RPM_OPT_FLAGS}}"
-make prefix=%_prefix libpath=%_libdir binpath=%_bindir %{?_smp_mflags}
-
-%install
-export CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}"
-export LDFLAGS="${LDFLAGS:-${RPM_OPT_FLAGS}}"
-make DESTDIR=${RPM_BUILD_ROOT} prefix=%_prefix libpath=%_libdir binpath=%_bindir install
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files
-%defattr(-,root,root)
-%{_libdir}/umad2sim/libumad2sim*.so*
-%{_bindir}/ibsim
-%doc README COPYING TODO net-examples scripts
-
-%changelog
diff --git a/ibsim/ibsim.c b/ibsim/ibsim.c
index e399482..bc24f99 100644
--- a/ibsim/ibsim.c
+++ b/ibsim/ibsim.c
@@ -55,7 +55,7 @@
 #include <ibsim.h>
 #include "sim.h"
 
-#define IBSIM_VERSION "0.5"
+#define IBSIM_VERSION "0.6"
 
 #undef DEBUG
 #define PDEBUG	if (parsedebug) IBWARN
@@ -80,6 +80,7 @@ static int maxfd;
 static FILE *simout;
 static int listen_to_port = IBSIM_DEFAULT_SERVER_PORT;
 static int remote_mode = 0;
+static char* socket_basename;
 
 static size_t make_name(union name_t *name, uint32_t addr, unsigned short port,
 			const char *fmt, ...)
@@ -109,11 +110,10 @@ static size_t make_name(union name_t *name, uint32_t addr, unsigned short port,
 
 static char *get_name(union name_t *name)
 {
-	if (remote_mode) {
+	if (remote_mode)
 		return inet_ntoa(name->name_i.sin_addr);
-	} else {
+	else
 		return name->name_u.sun_path + 1;
-	}
 }
 
 /**
@@ -237,7 +237,7 @@ static int sim_ctl_new_client(Client * cl, struct sim_ctl * ctl, union name_t *f
 	}
 
 	size = make_name(&name, from->name_i.sin_addr.s_addr, id,
-			 "%s:in%d", SIM_BASENAME, id);
+			 "%s:in%d", socket_basename, id);
 
 	if (connect(cl->fd, (struct sockaddr *)&name, size) < 0)
 		IBPANIC("can't connect to in socket %s - fd %d client pid %d",
@@ -368,7 +368,6 @@ static int sim_ctl_get_pkeys(Client * cl, struct sim_ctl * ctl)
 	memcpy(ctl->data, port->pkey_tbl, size);
 	if (size < sizeof(ctl->data))
 		memset(ctl->data + size, 0, sizeof(ctl->data) - size);
-
 	return 0;
 }
 
@@ -547,6 +546,8 @@ int sim_cmd_file(FILE * f, char *s)
 	}
 
 	while (fgets(line, sizeof(line) - 1, cmd_file) != NULL) {
+		if((p = strchr(line, '\n')) != NULL)
+			*p = '\0';
 		do_cmd(line, f);
 	}
 
@@ -589,11 +590,14 @@ static int sim_run_console(int fd)
 {
 	char line[128];
 	int ret = 0;
+	char *p = NULL;
 
 	ret = readline(fd, line, sizeof(line) - 1);
 	if (ret <= 0)
 		return ret;
 
+	if((p = strchr(line, '\n')) != NULL)
+		*p = '\0';
 	do_cmd(line, simout);
 	fprintf(simout, "sim%s> ", netstarted ? "" : " (inactive)");
 	fflush(simout);
@@ -606,7 +610,11 @@ static int sim_run(int con_fd)
 	fd_set rfds;
 	int i;
 
-	if (sim_init_conn(SIM_BASENAME) < 0)
+	socket_basename=getenv("IBSIM_SOCKNAME");
+	if(!socket_basename)
+		socket_basename = SIM_BASENAME;
+
+	if (sim_init_conn(socket_basename) < 0)
 		return -1;
 
 	while (!netstarted)
@@ -646,7 +654,7 @@ int list_connections(FILE * out)
 			continue;
 		fprintf(out,
 			"Client %d: pid %d connected at \"%s\" port 0x%" PRIx64
-			", lid %d, qp %d %s\n", i, clients[i].pid,
+			", lid %u, qp %d %s\n", i, clients[i].pid,
 			clients[i].port->node->nodeid,
 			clients[i].port->portguid, clients[i].port->lid,
 			clients[i].qp, clients[i].issm ? "SM" : "");
@@ -701,7 +709,7 @@ void usage(char *prog_name)
 {
 	fprintf(stderr,
 		"Usage: %s [-f outfile -d(ebug) -p(arse_debug) -s(tart) -v(erbose) "
-		"-I(gnore_duplicate) -N nodes -S switchs -P ports -L linearcap"
+		"-I(gnore_duplicate) -N nodes -S switches -P ports -L linearcap"
 		" -M mcastcap -r(emote_mode) -l(isten_to_port) <port>] <netfile>\n",
 		prog_name);
 	fprintf(stderr, "%s %s\n", prog_name, IBSIM_VERSION);
@@ -715,6 +723,7 @@ int main(int argc, char **argv)
 	extern void free_core(void);
 	char *outfname = 0, *netfile;
 	FILE *infile, *outfile;
+	int status;
 
 	static char const str_opts[] = "rf:dpvIsN:S:P:L:M:l:Vhu";
 	static const struct option long_opts[] = {
@@ -803,8 +812,9 @@ int main(int argc, char **argv)
 		IBPANIC("not enough memory for core structure");
 
 	DEBUG("initializing net \"%s\"", netfile);
-	if (sim_init_net(netfile, outfile) < 0)
-		IBPANIC("sim_init failed");
+	status = sim_init_net(netfile, outfile);
+	if (status < 0)
+		IBPANIC("sim_init failed, status %d", status);
 
 	sim_init_console(outfile);
 
diff --git a/ibsim/sim.h b/ibsim/sim.h
index b268250..daeecec 100644
--- a/ibsim/sim.h
+++ b/ibsim/sim.h
@@ -35,7 +35,6 @@
 #ifndef __SIM_H__
 #define __SIM_H__
 
-#include <infiniband/common.h>
 #include <infiniband/mad.h>
 
 #define MAXNETNODES	2048
@@ -72,7 +71,7 @@
 #define MAXHOPS 16
 
 enum NODE_TYPES {
-	NO_NODE = 0,
+	NO_NODE,
 	HCA_NODE,
 	SWITCH_NODE,
 	ROUTER_NODE,
@@ -112,6 +111,7 @@ enum GS_PERF_COUNTER_SELECT_MASK {
 	GS_PERF_RCV_BYTES_MASK = (1UL << 13),	// PORT_RCV_DATA
 	GS_PERF_XMT_PKTS_MASK = (1UL << 14),	// PORT_XMIT_PKTS
 	GS_PERF_RCV_PKTS_MASK = (1UL << 15),	// PORT_RCV_PKTS
+	GS_PERF_XMT_WAIT_MASK = (1UL << 16),	// PORT_XMIT_WAIT
 };
 
 enum GS_PC_EXT_SELECT_MASK {
@@ -125,6 +125,35 @@ enum GS_PC_EXT_SELECT_MASK {
 	GS_PC_EXT_MCAST_RECV = 1 << 7,
 };
 
+enum RCV_ERROR_DETAILS_COUNTER_SELECT_MASK {
+	GS_PERF_LOCAL_PHYSICAL_ERRORS_MASK = (1UL << 0), // PortLocalPhysicalErrors
+	GS_PERF_MALFORMED_PACKET_ERRORS_MASK = (1UL << 1), // PortMalformedPacketErrors
+	GS_PERF_BUFFER_OVERRUN_ERRORS_MASK = (1UL << 2), // PortBufferOverrunErrors
+	GS_PERF_DLID_MAPPING_ERRORS_MASK = (1UL << 3), // PortDLIDMappingErrors
+	GS_PERF_VL_MAPPING_ERRORS_MASK = (1UL << 4), // PortVLMappingErrors
+	GS_PERF_LOOPING_ERRORS_MASK = (1UL << 5), // PortLoopingErrors
+};
+
+enum XMIT_DISCARD_DETAILS_SELECT_MASK {
+	GS_PERF_INACTIVE_DISCARDS_MASK = (1UL << 0), // PortInactiveDiscards
+	GS_PERF_NEIGHBOR_MTU_DISCARDS_MASK = (1UL << 1), // PortNeighborMTUDiscards
+	GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_MASK = (1UL << 2), // PortSwLifetimeLimitDiscards
+	GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_MASK = (1UL << 3), // PortSwHOQLifetimeLimitDiscards
+};
+
+enum OP_RCV_COUNTERS_SELECT_MASK {
+	GS_PERF_OP_RCV_PKTS_MASK = (1UL << 0), // PortOpRcvPkts
+	GS_PERF_OP_RCV_DATA_MASK = (1UL << 1), // PortOpRcvData
+};
+
+enum FLOW_CTL_COUNTERS_SELECT_MASK {
+	GS_PERF_XMIT_FLOW_PKTS_MASK = (1UL << 0), // PortXmitFlowPkts
+	GS_PERF_RCV_FLOW_PKTS_MASK = (1UL << 1), // PortRcvFlowPkts
+};
+
+/* Counter select bit masks for PortVLOpPackets[0-15], PortVLOpData[0-15],
+and PortVLXmitWaitCounters[0-15] are ommitted due to redundency. */
+
 enum GS_PERF_COUNTER_SELECT_LIMIT {
 	GS_PERF_ERR_SYM_LIMIT = 0xffff,
 	GS_PERF_LINK_RECOVERS_LIMIT = 0xff,
@@ -142,6 +171,25 @@ enum GS_PERF_COUNTER_SELECT_LIMIT {
 	GS_PERF_RCV_BYTES_LIMIT = 0xffffffff,
 	GS_PERF_XMT_PKTS_LIMIT = 0xffffffff,
 	GS_PERF_RCV_PKTS_LIMIT = 0xffffffff,
+	GS_PERF_XMT_WAIT_LIMIT = 0xffffffff,
+	GS_PERF_LOCAL_PHYSICAL_ERRORS_LIMIT = 0xffff,  // PortLocalPhysicalErrors
+	GS_PERF_MALFORMED_PACKET_ERRORS_LIMIT = 0xffff, // PortMalformedPacketErrors
+	GS_PERF_BUFFER_OVERRUN_ERRORS_LIMIT = 0xffff, // PortBufferOverrunErrors
+	GS_PERF_DLID_MAPPING_ERRORS_LIMIT = 0xffff, // PortDLIDMappingErrors
+	GS_PERF_VL_MAPPING_ERRORS_LIMIT = 0xffff, // PortVLMappingErrors
+	GS_PERF_LOOPING_ERRORS_LIMIT = 0xffff, // PortLoopingErrors
+	GS_PERF_INACTIVE_DISCARDS_LIMIT = 0xffff, // PortInactiveDiscards
+	GS_PERF_NEIGHBOR_MTU_DISCARDS_LIMIT = 0xffff, // PortNeighborMTUDiscards
+	GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_LIMIT = 0xffff, // PortSwLifetimeLimitDiscards
+	GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_LIMIT = 0xffff, // PortSwHOQLifetimeLimitDiscards
+	GS_PERF_OP_RCV_PKTS_LIMIT = 0xffffffff, // PortOpRcvPkts
+	GS_PERF_OP_RCV_DATA_LIMIT = 0xffffffff, // PortOpRcvData
+	GS_PERF_XMIT_FLOW_PKTS_LIMIT = 0xffffffff, // PortXmitFlowPkts
+	GS_PERF_RCV_FLOW_PKTS_LIMIT = 0xffffffff, // PortRcvFlowPkts
+	GS_PERF_VL_OP_PACKETS_LIMIT = 0xffff, // PortVLOpPackets[0-15]
+	GS_PERF_VL_OP_DATA_LIMIT = 0xffffffff, // PortVLOpData[0-15]
+	GS_PERF_VL_XMIT_FLOW_CTL_UPDATE_ERRORS = 0x3, // PortVLXmitFlowCtlUpdateErrors[0-15]
+	GS_PERF_VL_XMIT_WAIT_COUNTERS_LIMIT = 0xffff, // PortVLXmitWaitCounters[0-15]
 };
 
 typedef struct Port Port;
@@ -183,6 +231,49 @@ struct Portcounters {
 	uint8_t errs_rcvconstraint;
 	uint16_t errs_rcvswitchrelay;
 	uint8_t errs_excessbufovrrun;
+	uint32_t xmt_wait;
+
+	struct PortRcvErrorDetails {
+		uint16_t PortLocalPhysicalErrors;
+		uint16_t PortMalformedPacketErrors;
+		uint16_t PortBufferOverrunErrors;
+		uint16_t PortDLIDMappingErrors;
+		uint16_t PortVLMappingErrors;
+		uint16_t PortLoopingErrors;
+	} rcv_error_details;
+
+	struct PortXmitDiscardDetails {
+		uint16_t PortInactiveDiscards;
+		uint16_t PortNeighborMTUDiscards;
+		uint16_t PortSwLifetimeLimitDiscards;
+		uint16_t PortSwHOQLifetimeLimitDiscards;
+	} xmit_discard_details;
+
+	struct PortOpRcvCounters {
+		uint32_t PortOpRcvPkts;
+		uint32_t PortOpRcvData;
+	} op_rcv_counters;
+
+	struct PortFlowCtlCounters {
+		uint32_t PortXmitFlowPkts;
+		uint32_t PortRcvFlowPkts;
+	} flow_ctl_counters;
+
+	struct PortVLOpPackets {
+		uint16_t PortVLOpPackets[16];
+	} vl_op_packets;
+
+	struct PortVLOpData {
+		uint32_t PortVLOpData[16];
+	} vl_op_data;
+
+	struct PortVLXmitFlowCtlUpdateErrors {
+		uint8_t PortVLXmitFlowCtlUpdateErrors[16];
+	} vl_xmit_flow_ctl_update_errors;
+
+	struct PortVLXmitWaitCounters {
+		uint16_t PortVLXmitWait[16];
+	} vl_xmit_wait_counters;
 };
 
 struct Port {
@@ -198,8 +289,8 @@ struct Port {
 	int physstate;
 	int lmc;
 	int hoqlife;
-	uint8_t op_vls;
 	uint8_t portinfo[64];
+	uint8_t op_vls;
 
 	char remotenodeid[NODEIDLEN];
 	char remotealias[ALIASLEN + 1];
@@ -287,10 +378,10 @@ void *sim_cmd_thread(void *file);
 
 // sim_mad.c
 int process_packet(Client * cl, void *p, int size, Client ** dcl);
-int send_trap(Port * port, int trapnum);
+int send_trap(Port * port, unsigned trapnum);
 
 extern Port *default_port;
-extern int simverb, modified;
+extern int simverb;
 extern int netstarted;
 
 #endif				/* __SIM_H__ */
diff --git a/ibsim/sim_cmd.c b/ibsim/sim_cmd.c
index dd9384e..4822a0b 100644
--- a/ibsim/sim_cmd.c
+++ b/ibsim/sim_cmd.c
@@ -40,6 +40,8 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
 
 #include <ibsim.h>
 #include "sim.h"
@@ -203,7 +205,8 @@ static int do_relink(FILE * f, char *line)
 			return -1;
 		}
 
-		rport = node_get_port(lport->previous_remotenode, lport->previous_remoteport);
+		rport = node_get_port(lport->previous_remotenode,
+				      lport->previous_remoteport);
 
 		if (link_ports(lport, rport) < 0)
 			return -fprintf(f,
@@ -220,7 +223,8 @@ static int do_relink(FILE * f, char *line)
 		if (!lport->previous_remotenode)
 			continue; 
 
-		rport = node_get_port(lport->previous_remotenode, lport->previous_remoteport);
+		rport = node_get_port(lport->previous_remotenode,
+				      lport->previous_remoteport);
 
 		if (link_ports(lport, rport) < 0)
 			continue;
@@ -286,14 +290,14 @@ static int do_seterror(FILE * f, char *line)
 	char *s = line;
 	char *nodeid = 0, name[NAMELEN], *sp, *orig = 0;
 	int portnum = -1;	// def - all ports
-	int numports, set = 0, rate = 0;
+	int startport, numports, set = 0, rate = 0;
 	uint16_t attr = 0;
 
 	if (strsep(&s, "\""))
 		orig = strsep(&s, "\"");
 
 	if (!s) {
-		fprintf(f, "# unlink: bad parameter in \"%s\"\n", line);
+		fprintf(f, "# set error: bad parameter in \"%s\"\n", line);
 		return -1;
 	}
 
@@ -307,8 +311,12 @@ static int do_seterror(FILE * f, char *line)
 	}
 
 	if (sp) {
+		if (node->type == SWITCH_NODE)
+			startport = 0;
+		else
+			startport = 1;
 		portnum = strtoul(sp, 0, 0);
-		if (portnum < 1 || portnum > node->numports) {
+		if (portnum < startport || portnum > node->numports) {
 			fprintf(f, "# bad port number %d at nodeid \"%s\"\n",
 				portnum, nodeid);
 			return -1;
@@ -541,7 +549,7 @@ static void dump_port(FILE * f, Port * port, int type)
 			PORTSTATE(port->state), PHYSSTATE(port->physstate),
 			comment);
 	else
-		fprintf(f, "\t lid %d lmc %d smlid %d %s %s %s/%s%s\n",
+		fprintf(f, "\t lid %u lmc %d smlid %u %s %s %s/%s%s\n",
 			port->lid, port->lmc, port->smlid,
 			PORTLINKWIDTH(port->linkwidth),
 			PORTLINKSPEED(port->linkspeed),
@@ -578,9 +586,8 @@ static int dump_net(FILE * f, char *line)
 			nports++;
 			dump_switch(f, node->sw);
 		}
-		for (i = 0; i < nports; i++) {
+		for (i = 0; i < nports; i++)
 			dump_port(f, ports + node->portsbase + i, node->type);
-		}
 		nnodes++;
 	}
 
@@ -714,7 +721,7 @@ static int dump_route(FILE * f, char *line)
 	node = fromport->node;
 	port = fromport;
 	portnum = port->portnum;
-	fprintf(f, "From node \"%s\" port %d lid %d\n", node->nodeid, portnum,
+	fprintf(f, "From node \"%s\" port %d lid %u\n", node->nodeid, portnum,
 		from);
 	while (maxhops--) {
 		if (port->state != 4)
@@ -749,7 +756,7 @@ static int dump_route(FILE * f, char *line)
 		fprintf(f, "no route found after %d hops\n", MAXHOPS);
 		return -1;
 	}
-	fprintf(f, "To node \"%s\" port %d lid %d\n", node->nodeid, portnum,
+	fprintf(f, "To node \"%s\" port %d lid %u\n", node->nodeid, portnum,
 		to);
 	return 0;
 
@@ -798,7 +805,7 @@ static int dump_help(FILE * f)
 	fprintf(f, "sim> Commands:\n");
 	fprintf(f, "\t!<filename> - run commands from the file\n");
 	fprintf(f, "\tStart network\n");
-	fprintf(f, "\tDump [nodeid] (def all network)\n");
+	fprintf(f, "\tDump [\"nodeid\"] : dump node information in network\n");
 	fprintf(f, "\tRoute <from-lid> <to-lid>\n");
 	fprintf(f, "\tLink \"nodeid\"[port] \"remoteid\"[port]\n");
 	fprintf(f, "\tReLink \"nodeid\" : restore previously unconnected link(s) of the node\n");
@@ -817,8 +824,9 @@ static int dump_help(FILE * f)
 		"\t\t\t\tNodeDescription : 16\n"
 		"\t\t\t\tNodeInfo        : 17\n"
 		"\t\t\t\tSwitchInfo      : 18\n"
-		"\t\t\t\tPortInfo        : 19\n"
+		"\t\t\t\tPortInfo        : 21\n"
 		);
+	fprintf(f, "\tPerformanceSet \"nodeid\"[port] [attribute].[field]=[value] : set perf. counters values\n");
 	fprintf(f,
 		"\tBaselid \"nodeid\"[port] <lid> [lmc] : change port's lid (lmc)\n");
 	fprintf(f, "\tVerbose [newlevel] - show/set simulator verbosity\n");
@@ -842,6 +850,255 @@ static int do_disconnect_client(FILE * out, int id)
 	return 0;
 }
 
+static uint64_t check_limit(uint64_t *value, uint64_t limit)
+{
+	*value = (limit > *value? *value : limit);
+	return *value;
+}
+
+static int parse_vl_num(char *attr, char *field, int *vl)
+{
+	char *vl_ptr, *end_ptr;
+	errno = 0;
+	if(strlen(field) < strlen(attr) + 1)
+		return -1;
+	vl_ptr = field + strlen(attr);
+	*vl = (int) strtol(vl_ptr, &end_ptr, 10);
+	if(*vl == 0 && (errno != 0 || vl_ptr == end_ptr))
+		return -1;
+	else if(*vl > 15 || *vl < 0)
+		return -1;
+	return 0;
+}
+
+static int do_perf_counter_set(FILE *f, char *line)
+{
+	char *s = line, *orig, *sp, *nodeid, *attr, *field, *field_trim, *val_error;
+	Node *node;
+	int portnum, vl;
+	uint64_t value;
+	char name[NAMELEN];
+	Port *p;
+	Portcounters *pc;
+
+	if (strsep(&s, "\""))
+		orig = strsep(&s, "\"");
+
+	if (!s)
+		goto format_error;
+
+	nodeid = expand_name(orig, name, &sp);
+
+	if (!sp && *s == '[')
+		sp = s + 1;
+
+	if( !(node = find_node(nodeid))) {
+		fprintf(f, "# nodeid \"%s\" (%s) not found\n", orig, nodeid);
+		return -1;
+	}
+
+	if (sp) {
+		portnum = strtoul(sp, 0, 0);
+		if (portnum < 1 || portnum > node->numports) {
+			fprintf(f, "# bad port number %d at nodeid \"%s\"\n",
+				portnum, nodeid);
+			return -1;
+		}
+	}
+
+	if (!(p = node_get_port(node, portnum))) {
+		fprintf(f, "# port %d not found from node %s\n", portnum, nodeid);
+		return -1;
+	}
+
+	if (s && *s)
+		while (isspace(*s))
+			s++;
+	attr = strsep(&s, ".");
+	if(s == NULL)
+		goto format_error;
+	if(attr == NULL) {
+		fprintf(f, "# attribute not found in command\n");
+		return -1;
+	}
+
+	field = strsep(&s, "=");
+	if(s == NULL)
+		goto format_error;
+	if(field == NULL) {
+		fprintf(f, "# field not found in command\n");
+		return -1;
+	}
+	field_trim = field + strlen(field) - 1;
+	while(field_trim > field && isspace(*field_trim))
+		field_trim--;
+	*(field_trim + 1) = 0;
+
+	errno = 0;
+	value = strtoull(s, &val_error, 0);
+	if((value == 0 || value == ULLONG_MAX) && errno != 0) {
+		fprintf(f, "# value is not valid integer\n");
+		return -1;
+	}
+	if(*val_error) {
+		fprintf(f, "# value %s is not valid integer\n", s);
+		return -1;
+	}
+
+	pc = &(p->portcounters);
+
+	if(!strcasecmp(attr, "PortCounters")) {
+		if(!strcasecmp(field, "SymbolErrorCounter"))
+			pc->errs_sym = check_limit(&value, GS_PERF_ERR_SYM_LIMIT);
+		else if(!strcasecmp(field, "LinkErrorRecoveryCounter"))
+			pc->linkrecovers = check_limit(&value, GS_PERF_LINK_RECOVERS_LIMIT);
+		else if(!strcasecmp(field, "LinkDownedCounter"))
+			pc->linkdowned = check_limit(&value, GS_PERF_LINK_DOWNED_LIMIT);
+		else if(!strcasecmp(field, "PortRcvErrors"))
+			pc->errs_rcv = check_limit(&value, GS_PERF_ERR_RCV_LIMIT);
+		else if(!strcasecmp(field, "PortRcvRemotePhysicalErrors"))
+			pc->errs_remphysrcv = check_limit(&value, GS_PERF_ERR_PHYSRCV_LIMIT);
+		else if(!strcasecmp(field, "PortRcvSwitchRelayErrors"))
+			pc->errs_rcvswitchrelay = check_limit(&value, GS_PERF_ERR_SWITCH_REL_LIMIT);
+		else if(!strcasecmp(field, "PortXmitDiscards"))
+			pc->xmitdiscards = check_limit(&value, GS_PERF_XMT_DISCARDS_LIMIT);
+		else if(!strcasecmp(field, "PortXmitConstraintErrors"))
+			pc->errs_xmtconstraint = check_limit(&value, GS_PERF_ERR_XMTCONSTR_LIMIT);
+		else if(!strcasecmp(field, "PortRcvConstraintErrors"))
+			pc->errs_rcvconstraint = check_limit(&value, GS_PERF_ERR_RCVCONSTR_LIMIT);
+		else if(!strcasecmp(field, "LocalLinkIntegrityErrors"))
+			pc->errs_localinteg = check_limit(&value, GS_PERF_ERR_LOCALINTEG_LIMIT);
+		else if(!strcasecmp(field, "ExcessiveBufferOverrunErrors"))
+			pc->errs_excessbufovrrun = check_limit(&value, GS_PERF_ERR_EXCESS_OVR_LIMIT);
+		else if(!strcasecmp(field, "VL15Dropped"))
+			pc->vl15dropped = check_limit(&value, GS_PERF_VL15_DROPPED_LIMIT);
+		else if(!strcasecmp(field, "PortXmitData"))
+			pc->flow_xmt_bytes = check_limit(&value, GS_PERF_XMT_BYTES_LIMIT);
+		else if(!strcasecmp(field, "PortRcvData"))
+			pc->flow_rcv_bytes = check_limit(&value, GS_PERF_RCV_BYTES_LIMIT);
+		else if(!strcasecmp(field, "PortXmitPkts"))
+			pc->flow_xmt_pkts = check_limit(&value, GS_PERF_XMT_PKTS_LIMIT);
+		else if(!strcasecmp(field, "PortRcvPkts"))
+			pc->flow_rcv_pkts = check_limit(&value, GS_PERF_RCV_PKTS_LIMIT);
+		else if(!strcasecmp(field, "PortXmitWait"))
+			pc->xmt_wait = check_limit(&value, GS_PERF_XMT_WAIT_LIMIT);
+		else
+			goto field_not_found;
+	} else if(!strcasecmp(attr, "PortCountersExtended")) {
+		if(!strcasecmp(field, "PortXmitData"))
+			pc->ext_xmit_data = check_limit(&value, UINT64_MAX);
+		else if(!strcasecmp(field, "PortRcvData"))
+			pc->ext_recv_data = check_limit(&value, UINT64_MAX);
+		else if(!strcasecmp(field, "PortXmitPkts"))
+			pc->ext_xmit_pkts = check_limit(&value, UINT64_MAX);
+		else if(!strcasecmp(field, "PortRcvPkts"))
+			pc->ext_recv_pkts = check_limit(&value, UINT64_MAX);
+		else if(!strcasecmp(field, "PortUnicastXmitPkts"))
+			pc->ext_ucast_xmit = check_limit(&value, UINT64_MAX);
+		else if(!strcasecmp(field, "PortUnicastRcvPkts"))
+			pc->ext_ucast_recv = check_limit(&value, UINT64_MAX);
+		else if(!strcasecmp(field, "PortMultiCastXmitPkts"))
+			pc->ext_mcast_xmit = check_limit(&value, UINT64_MAX);
+		else if(!strcasecmp(field, "PortMultiCastRcvPkts"))
+			pc->ext_mcast_recv = check_limit(&value, UINT64_MAX);
+		else
+			goto field_not_found;
+	} else if(!strcasecmp(attr, "PortRcvErrorDetails")) {
+		if(!strcasecmp(field, "PortLocalPhysicalErrors"))
+			pc->rcv_error_details.PortLocalPhysicalErrors =
+				check_limit(&value, GS_PERF_LOCAL_PHYSICAL_ERRORS_LIMIT);
+		else if(!strcasecmp(field, "PortMalformedPacketErrors"))
+			pc->rcv_error_details.PortMalformedPacketErrors =
+				check_limit(&value, GS_PERF_MALFORMED_PACKET_ERRORS_LIMIT);
+		else if(!strcasecmp(field, "PortBufferOverrunErrors"))
+			pc->rcv_error_details.PortBufferOverrunErrors =
+				check_limit(&value, GS_PERF_BUFFER_OVERRUN_ERRORS_LIMIT);
+		else if(!strcasecmp(field, "PortDLIDMappingErrors"))
+			pc->rcv_error_details.PortDLIDMappingErrors =
+				check_limit(&value, GS_PERF_DLID_MAPPING_ERRORS_LIMIT);
+		else if(!strcasecmp(field, "PortVLMappingErrors"))
+			pc->rcv_error_details.PortVLMappingErrors =
+				check_limit(&value, GS_PERF_VL_MAPPING_ERRORS_LIMIT);
+		else if(!strcasecmp(field, "PortLoopingErrors"))
+			pc->rcv_error_details.PortLoopingErrors =
+				check_limit(&value, GS_PERF_LOOPING_ERRORS_LIMIT);
+		else
+			goto field_not_found;
+	} else if(!strcasecmp(attr, "PortXmitDiscardDetails")) {
+		if(!strcasecmp(field, "PortInactiveDiscards"))
+			pc->xmit_discard_details.PortInactiveDiscards =
+				check_limit(&value, GS_PERF_INACTIVE_DISCARDS_LIMIT);
+		else if(!strcasecmp(field, "PortNeighborMTUDiscards"))
+			pc->xmit_discard_details.PortNeighborMTUDiscards =
+				check_limit(&value, GS_PERF_NEIGHBOR_MTU_DISCARDS_LIMIT);
+		else if(!strcasecmp(field, "PortSwLifetimeLimitDiscards"))
+			pc->xmit_discard_details.PortSwLifetimeLimitDiscards =
+				check_limit(&value, GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_LIMIT);
+		else if(!strcasecmp(field, "PortSwHOQLifetimeLimitDiscards"))
+			pc->xmit_discard_details.PortSwHOQLifetimeLimitDiscards =
+				check_limit(&value, GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_LIMIT);
+		else
+			goto field_not_found;
+	} else if(!strcasecmp(attr, "PortOpRcvCounters")) {
+		if(!strcasecmp(field, "PortOpRcvPkts"))
+			pc->op_rcv_counters.PortOpRcvPkts = check_limit(&value,
+				GS_PERF_OP_RCV_PKTS_LIMIT);
+		else if(!strcasecmp(field, "PortOpRcvData"))
+			pc->op_rcv_counters.PortOpRcvData = check_limit(&value,
+				GS_PERF_OP_RCV_DATA_LIMIT);
+		else
+			goto field_not_found;
+	} else if(!strcasecmp(attr, "PortFlowCtlCounters")) {
+		if(!strcasecmp(field, "PortXmitFlowPkts"))
+			pc->flow_ctl_counters.PortXmitFlowPkts =
+				check_limit(&value, GS_PERF_XMIT_FLOW_PKTS_LIMIT);
+		else if(!strcasecmp(field, "PortRcvFlowPkts"))
+			pc->flow_ctl_counters.PortRcvFlowPkts =
+				check_limit(&value, GS_PERF_RCV_FLOW_PKTS_LIMIT);
+		else
+			goto field_not_found;
+	} else if(!strcasecmp(attr, "PortVLOpPackets")) {
+		if(strstr(field, "PortVLOpPackets") != field)
+			goto field_not_found;
+		if(parse_vl_num(attr, field, &vl) < 0)
+			goto field_not_found;
+		pc->vl_op_packets.PortVLOpPackets[vl] =
+			check_limit(&value, GS_PERF_VL_OP_PACKETS_LIMIT);
+	} else if(!strcasecmp(attr, "PortVLOpData")) {
+		if(strstr(field, "PortVLOpData") != field)
+			goto field_not_found;
+		if(parse_vl_num(attr, field, &vl) < 0)
+			goto field_not_found;
+		pc->vl_op_data.PortVLOpData[vl] =
+			check_limit(&value, GS_PERF_VL_OP_DATA_LIMIT);
+	} else if(!strcasecmp(attr, "PortVLXmitFlowCtlUpdateErrors")) {
+		if(strstr(field, "PortVLXmitFlowCtlUpdateErrors") != field)
+			goto field_not_found;
+		if(parse_vl_num(attr, field, &vl) < 0)
+			goto field_not_found;
+		pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[vl] =
+			check_limit(&value, GS_PERF_VL_XMIT_FLOW_CTL_UPDATE_ERRORS);
+	} else if(!strcasecmp(attr, "PortVLXmitWaitCounters")) {
+		if(strstr(field, "PortVLXmitWaitCounters") != field)
+			goto field_not_found;
+		if(parse_vl_num(attr, field, &vl) < 0)
+			goto field_not_found;
+		pc->vl_xmit_wait_counters.PortVLXmitWait[vl] =
+			check_limit(&value, GS_PERF_VL_XMIT_WAIT_COUNTERS_LIMIT);
+	} else {
+		fprintf(f, "# attribute %s not found\n", attr);
+		return -1;
+	}
+	fprintf(f, "%s.%s has been set to %"PRIu64"\n", attr, field, value);
+	return 0;
+field_not_found:
+	fprintf(f, "# field %s cannot be found in attribute %s\n", field, attr);
+	return -1;
+format_error:
+	fprintf(f, "# command does not match: PerformanceSet \"nodeid\"[port] [attribute].[field]=[value]\n");
+	return -1;
+}
+
 int netstarted;
 
 int do_cmd(char *buf, FILE *f)
@@ -856,7 +1113,7 @@ int do_cmd(char *buf, FILE *f)
 		cmd_len++;
 
 	if (*line == '#')
-		fprintf(f, line);
+		fprintf(f, "%s", line);
 	else if (*line == '!')
 		r = sim_cmd_file(f, line);
 	else if (!strncasecmp(line, "Dump", cmd_len))
@@ -906,6 +1163,8 @@ int do_cmd(char *buf, FILE *f)
 	 */
 	else if (!strncasecmp(line, "ReLink", cmd_len))
 		r = do_relink(f, line);
+	else if (!strncasecmp(line, "PerformanceSet", cmd_len))
+		r = do_perf_counter_set(f, line);
 	else if (*line != '\n' && *line != '\0')
 		fprintf(f, "command \'%s\' unknown - skipped\n", line);
 
diff --git a/ibsim/sim_mad.c b/ibsim/sim_mad.c
index f530a7a..223d507 100644
--- a/ibsim/sim_mad.c
+++ b/ibsim/sim_mad.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2009 HNR Consulting. All rights reserved.
  *
  * This file is part of ibsim.
  *
@@ -58,7 +59,10 @@ typedef int (EncodeTrapfn) (Port * port, char *data);
 
 static Smpfn do_nodeinfo, do_nodedesc, do_switchinfo, do_portinfo,
     do_linearforwtbl, do_multicastforwtbl, do_portcounters, do_extcounters,
-    do_pkeytbl, do_sl2vl, do_vlarb, do_guidinfo, do_nothing;
+    do_rcv_error_details, do_xmit_discard_details, do_op_rcv_counters,
+    do_flow_ctl_counters, do_vl_op_packets, do_vl_op_data,
+    do_vl_xmit_flow_ctl_update_errors, do_vl_xmit_wait_counters, do_pkeytbl,
+    do_sl2vl, do_vlarb, do_guidinfo, do_cpi;
 
 static EncodeTrapfn encode_trap128;
 static EncodeTrapfn encode_trap144;
@@ -78,14 +82,21 @@ static Smpfn *attrs[IB_PERFORMANCE_CLASS + 1][0xff] = {
 
 			[IB_ATTR_LAST] 0,
 			},
-	[IB_PERFORMANCE_CLASS] {[CLASS_PORT_INFO] = do_nothing,
+	[IB_PERFORMANCE_CLASS] {[CLASS_PORT_INFO] = do_cpi,
 				[IB_GSI_PORT_SAMPLES_CONTROL] = 0,
 				[IB_GSI_PORT_SAMPLES_RESULT] = 0,
 				[IB_GSI_PORT_COUNTERS] = do_portcounters,
 				[IB_GSI_PORT_COUNTERS_EXT] = do_extcounters,
+				[IB_GSI_PORT_RCV_ERROR_DETAILS] = do_rcv_error_details,
+				[IB_GSI_PORT_XMIT_DISCARD_DETAILS] = do_xmit_discard_details,
+				[IB_GSI_PORT_PORT_OP_RCV_COUNTERS] = do_op_rcv_counters,
+				[IB_GSI_PORT_PORT_FLOW_CTL_COUNTERS] = do_flow_ctl_counters,
+				[IB_GSI_PORT_PORT_VL_OP_PACKETS] = do_vl_op_packets,
+				[IB_GSI_PORT_PORT_VL_OP_DATA] = do_vl_op_data,
+				[IB_GSI_PORT_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS] = do_vl_xmit_flow_ctl_update_errors,
+				[IB_GSI_PORT_PORT_VL_XMIT_WAIT_COUNTERS] = do_vl_xmit_wait_counters,
 
 				[IB_GSI_ATTR_LAST] 0,
-
 				},
 };
 
@@ -94,7 +105,6 @@ static EncodeTrapfn *encodetrap[] = {
 	[TRAP_144] encode_trap144,
 
 	[TRAP_NUM_LAST] 0,
-
 };
 
 extern Node *nodes;
@@ -104,6 +114,10 @@ extern Port **lids;
 extern int netnodes, netports, netswitches;
 extern int maxlinearcap;
 
+typedef void (*pc_reset_function)(Portcounters * pc, unsigned mask);
+typedef void (*pc_get_function)(Portcounters * pc, uint8_t * data);
+typedef void (*pc_sum_function)(Portcounters * totals, Portcounters * pc);
+
 static uint64_t update_trid(uint8_t *mad, unsigned response, Client *cl)
 {
 	uint64_t trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
@@ -219,16 +233,29 @@ static int reply_MAD(void *buf, ib_rpc_t * rpc, ib_dr_path_t * path,
 	return 0;
 }
 
-static int do_nothing(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+static int do_cpi(Port * port, unsigned op, uint32_t mod, uint8_t * data)
 {
-	return 0;
+	Node *node = port->node;
+	int status = 0;
+
+	if (op != IB_MAD_METHOD_GET)
+		status = ERR_METHOD_UNSUPPORTED;
+	memset(data, 0, IB_SMP_DATA_SIZE);
+	mad_set_field(data, 0, IB_CPI_BASEVER_F, 1);
+	mad_set_field(data, 0, IB_CPI_CLASSVER_F, 1);
+	if (node->type != SWITCH_NODE)
+		mad_set_field(data, 0, IB_CPI_CAPMASK_F, 0x200);
+	else
+		mad_set_field(data, 0, IB_CPI_CAPMASK_F, 0x300);
+	mad_set_field(data, 0, IB_CPI_RESP_TIME_VALUE_F, 0x12);
+	return status;
 }
 
 static int do_nodedesc(Port * port, unsigned op, uint32_t mod, uint8_t * data)
 {
 	int status = 0;
 
-	if (op != 1)		// get
+	if (op != IB_MAD_METHOD_GET)
 		status = ERR_METHOD_UNSUPPORTED;
 	memcpy(data, port->node->nodedesc, IB_SMP_DATA_SIZE);
 
@@ -241,7 +268,7 @@ static int do_nodeinfo(Port * port, unsigned op, uint32_t mod, uint8_t * data)
 	int status = 0;
 	uint64_t portguid = node->nodeguid + port->portnum;
 
-	if (op != IB_MAD_METHOD_GET)	// get
+	if (op != IB_MAD_METHOD_GET)
 		status = ERR_METHOD_UNSUPPORTED;
 	memcpy(data, node->nodeinfo, IB_SMP_DATA_SIZE);
 
@@ -261,7 +288,7 @@ static int do_switchinfo(Port * port, unsigned op, uint32_t mod, uint8_t * data)
 	if (!sw)		// not a Switch?
 		return ERR_ATTR_UNSUPPORTED;
 
-	if (op == 2) {		// Set
+	if (op == IB_MAD_METHOD_SET) {
 		if (mad_get_field(data, 0, IB_SW_STATE_CHANGE_F))
 			sw->portchange = 0;
 		sw->linearFDBtop =
@@ -327,11 +354,10 @@ static int do_sl2vl(Port * port, unsigned op, uint32_t mod, uint8_t * data)
 
 	sl2vl = port->sl2vl + 8 * n;
 
-	if (op == IB_MAD_METHOD_SET) {
+	if (op == IB_MAD_METHOD_SET)
 		memcpy(sl2vl, data, 8);
-	} else {
+	else
 		memcpy(data, sl2vl, 8);
-	}
 
 	return 0;
 }
@@ -366,10 +392,10 @@ static int do_vlarb(Port * port, unsigned op, uint32_t mod, uint8_t * data)
 
 	size *= sizeof(*vlarb);
 
-	if (op == IB_MAD_METHOD_SET) {
+	if (op == IB_MAD_METHOD_SET)
 		memcpy(vlarb, data, size);
-	} else {
-		memset(data, 0, 64);
+	else {
+		memset(data, 0, IB_SMP_DATA_SIZE);
 		memcpy(data, vlarb, size);
 	}
 
@@ -385,7 +411,7 @@ static int do_guidinfo(Port * port, unsigned op, uint32_t mod, uint8_t * data)
 	if (op != IB_MAD_METHOD_GET)    // only get currently supported (non compliant)
 		status = ERR_METHOD_UNSUPPORTED;
 
-	memset(data, 0, 64);
+	memset(data, 0, IB_SMP_DATA_SIZE);
 	if (mod == 0) {
 		if (node->type == SWITCH_NODE)
 			mad_encode_field(data, IB_GUID_GUID0_F, &node->nodeguid);
@@ -413,7 +439,7 @@ do_portinfo(Port * port, unsigned op, uint32_t portnum, uint8_t * data)
 	DEBUG("in node %" PRIx64 " port %" PRIx64 ": port %" PRIx64 " (%d(%d))",
 	      node->nodeguid, port->portguid, p->portguid, p->portnum, portnum);
 
-	if (op == IB_MAD_METHOD_SET) {	// set
+	if (op == IB_MAD_METHOD_SET) {
 		unsigned val;
 		if (node->type != SWITCH_NODE && port->portnum != p->portnum)
 			return ERR_BAD_PARAM;	// on HCA or rtr can't "set" on other port
@@ -459,7 +485,7 @@ do_portinfo(Port * port, unsigned op, uint32_t portnum, uint8_t * data)
 			if (p->lid > 0 && p->lid < maxlinearcap
 			    && lids[p->lid] != p && lids[p->lid])
 				IBWARN
-				    ("Port %s:%d overwrite lid table entry for lid %d (was %s:%d)",
+				    ("Port %s:%d overwrite lid table entry for lid %u (was %s:%d)",
 				     node->nodeid, p->portnum, p->lid,
 				     lids[p->lid]->node->nodeid,
 				     lids[p->lid]->portnum);
@@ -473,6 +499,7 @@ do_portinfo(Port * port, unsigned op, uint32_t portnum, uint8_t * data)
 
 	update_portinfo(p);
 	memcpy(data, p->portinfo, IB_SMP_DATA_SIZE);
+	mad_set_field(data, 0, IB_PORT_LOCAL_PORT_F, port->portnum);
 
 	return 0;
 }
@@ -488,10 +515,9 @@ static int do_linearforwtbl(Port * port, unsigned op, uint32_t mod,
 	if (mod < 0 || mod > 767)
 		return ERR_BAD_PARAM;
 
-	if (op == IB_MAD_METHOD_SET) {	// Set
+	if (op == IB_MAD_METHOD_SET)
 		mad_get_array(data, 0, IB_LINEAR_FORW_TBL_F,
 			      sw->fdb + mod * 64);
-	}
 
 	mad_set_array(data, 0, IB_LINEAR_FORW_TBL_F, sw->fdb + mod * 64);
 
@@ -518,16 +544,15 @@ static int do_multicastforwtbl(Port * port, unsigned op, uint32_t mod,
 	}
 
 	blockposition = (numBlock32 * NUMBEROFPORTMASK + numPortMsk) * 64;
-	if (op == IB_MAD_METHOD_SET) {	// Set
+	if (op == IB_MAD_METHOD_SET)
 		mad_get_array(data, 0, IB_MULTICAST_FORW_TBL_F,
 			      sw->mfdb + blockposition);
-	}
 	mad_set_array(data, 0, IB_MULTICAST_FORW_TBL_F,
 		      sw->mfdb + blockposition);
 	return 0;
 }
 
-static void pc_reset(Portcounters * pc, uint mask)
+static void pc_reset(Portcounters * pc, unsigned mask)
 {
 	if (mask & GS_PERF_ERR_SYM_MASK)
 		pc->errs_sym = 0;
@@ -561,6 +586,8 @@ static void pc_reset(Portcounters * pc, uint mask)
 		pc->flow_xmt_pkts = 0;
 	if (mask & GS_PERF_RCV_PKTS_MASK)
 		pc->flow_rcv_pkts = 0;
+	if (mask & GS_PERF_XMT_WAIT_MASK)
+		pc->xmt_wait = 0;
 }
 
 static inline uint32_t addval(uint32_t val, uint32_t delta, uint32_t max)
@@ -603,7 +630,7 @@ static int pc_updated(Port ** srcport, Port * destport)
 	uint32_t madsize_div_4 = 72;	//real data divided by 4
 
 	if (*srcport != destport) {
-		//PKT get out of port ..
+		//PKT got out of port ..
 		srcpc->flow_xmt_pkts =
 		    addval(srcpc->flow_xmt_pkts, 1, GS_PERF_XMT_PKTS_LIMIT);
 		srcpc->flow_xmt_bytes =
@@ -619,7 +646,7 @@ static int pc_updated(Port ** srcport, Port * destport)
 			VERB("drop pkt due error rate %d", destport->errrate);
 			return 0;
 		}
-		//PKT get in to the port ..
+		//PKT got into the port ..
 		destpc->flow_rcv_pkts =
 		    addval(destpc->flow_rcv_pkts, 1, GS_PERF_RCV_PKTS_LIMIT);
 		destpc->flow_rcv_bytes =
@@ -635,6 +662,9 @@ static int pc_updated(Port ** srcport, Port * destport)
 
 static void pc_sum(Portcounters * totals, Portcounters * pc)
 {
+	totals->xmt_wait =
+	    addval(totals->xmt_wait, pc->xmt_wait,
+		   GS_PERF_XMT_WAIT_LIMIT);
 	totals->flow_xmt_pkts =
 	    addval(totals->flow_xmt_pkts, pc->flow_xmt_pkts,
 		   GS_PERF_XMT_PKTS_LIMIT);
@@ -685,6 +715,7 @@ static void pc_sum(Portcounters * totals, Portcounters * pc)
 
 static void pc_get(Portcounters * pc, uint8_t * data)
 {
+	mad_set_field(data, 0, IB_PC_XMT_WAIT_F, pc->xmt_wait);
 	mad_set_field(data, 0, IB_PC_XMT_PKTS_F, pc->flow_xmt_pkts);
 	mad_set_field(data, 0, IB_PC_XMT_BYTES_F, pc->flow_xmt_bytes);
 	mad_set_field(data, 0, IB_PC_RCV_PKTS_F, pc->flow_rcv_pkts);
@@ -710,7 +741,7 @@ static int do_portcounters(Port * port, unsigned op, uint32_t unused,
 	Node *node = port->node;
 	int portnum = mad_get_field(data, 0, IB_PC_PORT_SELECT_F);
 	Portcounters totals;
-	uint mask;
+	unsigned mask, mask2;
 	Port *p;
 	int i;
 
@@ -725,6 +756,9 @@ static int do_portcounters(Port * port, unsigned op, uint32_t unused,
 	      node->nodeguid, port->portguid, portnum);
 
 	mask = mad_get_field(data, 0, IB_PC_COUNTER_SELECT_F);
+	mask2 = mad_get_field(data, 0, IB_PC_COUNTER_SELECT2_F);
+	if (mask2)
+		mask |= GS_PERF_XMT_WAIT_MASK;
 
 	if (portnum != 0xff) {
 		if (!(p = node_get_port(node, portnum)))
@@ -740,13 +774,10 @@ static int do_portcounters(Port * port, unsigned op, uint32_t unused,
 	memset(&totals, 0, sizeof totals);
 
 	for (i = 0; i <= node->numports; i++) {
-
 		if (!(p = node_get_port(node, i)))
 			return ERR_BAD_PARAM;
-
 		if (op == IB_MAD_METHOD_SET)
 			pc_reset(&p->portcounters, mask);
-
 		pc_sum(&totals, &p->portcounters);
 	}
 
@@ -766,7 +797,7 @@ static void pc_ext_sum(Portcounters * total, Portcounters * pc)
 	ADDVAL64(total->ext_mcast_recv, pc->ext_mcast_recv);
 }
 
-static void pc_ext_reset(Portcounters * pc, uint mask)
+static void pc_ext_reset(Portcounters * pc, unsigned mask)
 {
 	if (mask & GS_PC_EXT_XMIT_DATA)
 		pc->ext_xmit_data = 0;
@@ -844,6 +875,482 @@ do_extcounters(Port * port, unsigned op, uint32_t unused, uint8_t * data)
 	return 0;
 }
 
+static int do_portcounters_common(Port * port, unsigned op, uint32_t unused,
+				   uint8_t * data,
+				   pc_reset_function pc_reset_ptr,
+				   pc_get_function pc_get_ptr,
+				   pc_sum_function pc_sum_ptr)
+{
+	Node *node = port->node;
+	unsigned portnum;
+	Portcounters totals;
+	unsigned mask;
+	Port *p;
+	int i;
+
+	portnum = mad_get_field(data, 0, IB_PC_PORT_SELECT_F);
+	if (node->type != SWITCH_NODE && portnum != port->portnum)
+		return ERR_BAD_PARAM;
+
+	if (node->type == SWITCH_NODE && portnum > node->numports
+	    && portnum != 0xff)
+		return ERR_BAD_PARAM;
+
+	DEBUG("in node %" PRIx64 " port %" PRIx64 " portnum %u",
+	      node->nodeguid, port->portguid, portnum);
+
+	mask = mad_get_field(data, 0, IB_PC_COUNTER_SELECT_F);
+
+	if (portnum != 0xff) {
+		if (!(p = node_get_port(node, portnum)))
+			return ERR_BAD_PARAM;
+		if (op == IB_MAD_METHOD_SET)
+			pc_reset_ptr(&p->portcounters, mask);
+		pc_get_ptr(&p->portcounters, data);
+		return 0;
+	}
+
+	memset(&totals, 0, sizeof totals);
+
+	for (i = 0; i <= node->numports; i++) {
+		if (!(p = node_get_port(node, i)))
+			return ERR_BAD_PARAM;
+		if (op == IB_MAD_METHOD_SET)
+			pc_reset_ptr(&p->portcounters, mask);
+		pc_sum_ptr(&totals, &p->portcounters);
+	}
+
+	pc_get_ptr(&totals, data);
+	return 0;
+}
+
+static void pc_rcv_error_details_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field(data, 0, IB_PC_RCV_LOCAL_PHY_ERR_F,
+		      pc->rcv_error_details.PortLocalPhysicalErrors);
+	mad_set_field(data, 0, IB_PC_RCV_MALFORMED_PKT_ERR_F,
+		      pc->rcv_error_details.PortMalformedPacketErrors);
+	mad_set_field(data, 0, IB_PC_RCV_BUF_OVR_ERR_F,
+		      pc->rcv_error_details.PortBufferOverrunErrors);
+	mad_set_field(data, 0, IB_PC_RCV_DLID_MAP_ERR_F,
+		      pc->rcv_error_details.PortDLIDMappingErrors);
+	mad_set_field(data, 0, IB_PC_RCV_VL_MAP_ERR_F,
+		      pc->rcv_error_details.PortVLMappingErrors);
+	mad_set_field(data, 0, IB_PC_RCV_LOOPING_ERR_F,
+		      pc->rcv_error_details.PortLoopingErrors);
+}
+
+static void pc_rcv_error_details_sum(Portcounters * totals, Portcounters * pc)
+{
+	totals->rcv_error_details.PortLocalPhysicalErrors =
+		addval(totals->rcv_error_details.PortLocalPhysicalErrors,
+		pc->rcv_error_details.PortLocalPhysicalErrors,
+		GS_PERF_LOCAL_PHYSICAL_ERRORS_LIMIT);
+	totals->rcv_error_details.PortMalformedPacketErrors =
+		addval(totals->rcv_error_details.PortMalformedPacketErrors,
+		pc->rcv_error_details.PortMalformedPacketErrors,
+		GS_PERF_MALFORMED_PACKET_ERRORS_LIMIT);
+	totals->rcv_error_details.PortBufferOverrunErrors =
+		addval(totals->rcv_error_details.PortBufferOverrunErrors,
+		pc->rcv_error_details.PortBufferOverrunErrors,
+		GS_PERF_BUFFER_OVERRUN_ERRORS_LIMIT);
+	totals->rcv_error_details.PortDLIDMappingErrors =
+		addval(totals->rcv_error_details.PortDLIDMappingErrors,
+		pc->rcv_error_details.PortDLIDMappingErrors,
+		GS_PERF_DLID_MAPPING_ERRORS_LIMIT);
+	totals->rcv_error_details.PortVLMappingErrors =
+		addval(totals->rcv_error_details.PortVLMappingErrors,
+		pc->rcv_error_details.PortVLMappingErrors,
+		GS_PERF_VL_MAPPING_ERRORS_LIMIT);
+	totals->rcv_error_details.PortLoopingErrors =
+		addval(totals->rcv_error_details.PortLoopingErrors,
+		pc->rcv_error_details.PortLoopingErrors,
+		GS_PERF_LOOPING_ERRORS_LIMIT);
+}
+
+static void pc_rcv_error_details_reset(Portcounters * pc, unsigned mask)
+{
+	if(mask & GS_PERF_LOCAL_PHYSICAL_ERRORS_MASK)
+		pc->rcv_error_details.PortLocalPhysicalErrors = 0;
+	if(mask & GS_PERF_MALFORMED_PACKET_ERRORS_MASK)
+		pc->rcv_error_details.PortMalformedPacketErrors = 0;
+	if(mask & GS_PERF_BUFFER_OVERRUN_ERRORS_MASK)
+		pc->rcv_error_details.PortBufferOverrunErrors = 0;
+	if(mask & GS_PERF_DLID_MAPPING_ERRORS_MASK)
+		pc->rcv_error_details.PortDLIDMappingErrors = 0;
+	if(mask & GS_PERF_VL_MAPPING_ERRORS_MASK)
+		pc->rcv_error_details.PortVLMappingErrors = 0;
+	if(mask & GS_PERF_LOOPING_ERRORS_MASK)
+		pc->rcv_error_details.PortLoopingErrors = 0;
+}
+
+static int do_rcv_error_details(Port * port, unsigned op, uint32_t unused, uint8_t * data)
+{
+	return do_portcounters_common(port, op, unused, data, pc_rcv_error_details_reset,
+		pc_rcv_error_details_get, pc_rcv_error_details_sum);
+}
+
+static void pc_xmit_discard_details_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field(data, 0, IB_PC_XMT_INACT_DISC_F,
+		pc->xmit_discard_details.PortInactiveDiscards);
+	mad_set_field(data, 0, IB_PC_XMT_NEIGH_MTU_DISC_F,
+		pc->xmit_discard_details.PortNeighborMTUDiscards);
+	mad_set_field(data, 0, IB_PC_XMT_SW_LIFE_DISC_F,
+		pc->xmit_discard_details.PortSwLifetimeLimitDiscards);
+	mad_set_field(data, 0, IB_PC_XMT_SW_HOL_DISC_F,
+		pc->xmit_discard_details.PortSwHOQLifetimeLimitDiscards);
+}
+
+static void pc_xmit_discard_details_sum(Portcounters * totals, Portcounters * pc)
+{
+	totals->xmit_discard_details.PortInactiveDiscards =
+		addval(totals->xmit_discard_details.PortInactiveDiscards,
+		pc->xmit_discard_details.PortInactiveDiscards,
+		GS_PERF_INACTIVE_DISCARDS_LIMIT);
+	totals->xmit_discard_details.PortNeighborMTUDiscards =
+		addval(totals->xmit_discard_details.PortNeighborMTUDiscards,
+		pc->xmit_discard_details.PortNeighborMTUDiscards,
+		GS_PERF_NEIGHBOR_MTU_DISCARDS_LIMIT);
+	totals->xmit_discard_details.PortSwLifetimeLimitDiscards =
+		addval(totals->xmit_discard_details.PortSwLifetimeLimitDiscards,
+		pc->xmit_discard_details.PortSwLifetimeLimitDiscards,
+		GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_LIMIT);
+	totals->xmit_discard_details.PortSwHOQLifetimeLimitDiscards =
+		addval(totals->xmit_discard_details.PortSwHOQLifetimeLimitDiscards,
+		pc->xmit_discard_details.PortSwHOQLifetimeLimitDiscards,
+		GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_LIMIT);
+}
+
+static void pc_xmit_discard_details_reset(Portcounters * pc, unsigned mask)
+{
+	if(mask & GS_PERF_INACTIVE_DISCARDS_MASK)
+		pc->xmit_discard_details.PortInactiveDiscards = 0;
+	if(mask & GS_PERF_NEIGHBOR_MTU_DISCARDS_MASK)
+		pc->xmit_discard_details.PortNeighborMTUDiscards = 0;
+	if(mask & GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_MASK)
+		pc->xmit_discard_details.PortSwLifetimeLimitDiscards = 0;
+	if(mask & GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_MASK)
+		pc->xmit_discard_details.PortSwHOQLifetimeLimitDiscards = 0;
+}
+
+static int do_xmit_discard_details(Port * port, unsigned op, uint32_t unused, uint8_t * data)
+{
+	return do_portcounters_common(port, op, unused, data, pc_xmit_discard_details_reset,
+		pc_xmit_discard_details_get, pc_xmit_discard_details_sum);
+}
+
+static void pc_op_rcv_counters_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field(data, 0, IB_PC_PORT_OP_RCV_PKTS_F,
+		pc->op_rcv_counters.PortOpRcvPkts);
+	mad_set_field(data, 0, IB_PC_PORT_OP_RCV_DATA_F,
+		pc->op_rcv_counters.PortOpRcvData);
+}
+
+static void pc_op_rcv_counters_sum(Portcounters * totals, Portcounters * pc)
+{
+	totals->op_rcv_counters.PortOpRcvPkts =
+		addval(totals->op_rcv_counters.PortOpRcvPkts,
+		pc->op_rcv_counters.PortOpRcvPkts, GS_PERF_OP_RCV_PKTS_LIMIT);
+	totals->op_rcv_counters.PortOpRcvData =
+		addval(totals->op_rcv_counters.PortOpRcvData,
+		pc->op_rcv_counters.PortOpRcvData, GS_PERF_OP_RCV_DATA_LIMIT);
+}
+
+static void pc_op_rcv_counters_reset(Portcounters * pc, unsigned mask)
+{
+	if(mask & GS_PERF_OP_RCV_PKTS_MASK)
+		pc->op_rcv_counters.PortOpRcvPkts = 0;
+	if(mask & GS_PERF_OP_RCV_DATA_MASK)
+		pc->op_rcv_counters.PortOpRcvData = 0;
+}
+
+static int do_op_rcv_counters(Port * port, unsigned op, uint32_t unused, uint8_t * data)
+{
+	return do_portcounters_common(port, op, unused, data, pc_op_rcv_counters_reset,
+		pc_op_rcv_counters_get, pc_op_rcv_counters_sum);
+}
+
+static void pc_flow_ctl_counters_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field(data, 0, IB_PC_PORT_XMIT_FLOW_PKTS_F,
+		pc->flow_ctl_counters.PortXmitFlowPkts);
+	mad_set_field(data, 0, IB_PC_PORT_RCV_FLOW_PKTS_F,
+		pc->flow_ctl_counters.PortRcvFlowPkts);
+}
+
+static void pc_flow_ctl_counters_sum(Portcounters * totals, Portcounters * pc)
+{
+	totals->flow_ctl_counters.PortXmitFlowPkts =
+		addval(totals->flow_ctl_counters.PortXmitFlowPkts,
+		pc->flow_ctl_counters.PortXmitFlowPkts,
+		GS_PERF_XMIT_FLOW_PKTS_LIMIT);
+	totals->flow_ctl_counters.PortRcvFlowPkts =
+		addval(totals->flow_ctl_counters.PortRcvFlowPkts,
+		pc->flow_ctl_counters.PortRcvFlowPkts,
+		GS_PERF_RCV_FLOW_PKTS_LIMIT);
+}
+
+static void pc_flow_ctl_counters_reset(Portcounters * pc, unsigned mask)
+{
+	if(mask & GS_PERF_XMIT_FLOW_PKTS_MASK)
+		pc->flow_ctl_counters.PortXmitFlowPkts = 0;
+	if(mask & GS_PERF_RCV_FLOW_PKTS_MASK)
+		pc->flow_ctl_counters.PortRcvFlowPkts = 0;
+}
+
+static int do_flow_ctl_counters(Port * port, unsigned op, uint32_t unused, uint8_t * data)
+{
+	return do_portcounters_common(port, op, unused, data, pc_flow_ctl_counters_reset,
+		pc_flow_ctl_counters_get, pc_flow_ctl_counters_sum);
+}
+
+static void pc_vl_op_packets_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS0_F,
+		pc->vl_op_packets.PortVLOpPackets[0]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS1_F,
+		pc->vl_op_packets.PortVLOpPackets[1]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS2_F,
+		pc->vl_op_packets.PortVLOpPackets[2]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS3_F,
+		pc->vl_op_packets.PortVLOpPackets[3]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS4_F,
+		pc->vl_op_packets.PortVLOpPackets[4]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS5_F,
+		pc->vl_op_packets.PortVLOpPackets[5]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS6_F,
+		pc->vl_op_packets.PortVLOpPackets[6]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS7_F,
+		pc->vl_op_packets.PortVLOpPackets[7]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS8_F,
+		pc->vl_op_packets.PortVLOpPackets[8]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS9_F,
+		pc->vl_op_packets.PortVLOpPackets[9]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS10_F,
+		pc->vl_op_packets.PortVLOpPackets[10]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS11_F,
+		pc->vl_op_packets.PortVLOpPackets[11]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS12_F,
+		pc->vl_op_packets.PortVLOpPackets[12]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS13_F,
+		pc->vl_op_packets.PortVLOpPackets[13]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS14_F,
+		pc->vl_op_packets.PortVLOpPackets[14]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS15_F,
+		pc->vl_op_packets.PortVLOpPackets[15]);
+}
+
+static void pc_vl_op_packets_sum(Portcounters * totals, Portcounters * pc)
+{
+	int i;
+	for(i = 0; i < 16; i++)
+		totals->vl_op_packets.PortVLOpPackets[i] =
+			addval(totals->vl_op_packets.PortVLOpPackets[i],
+			       pc->vl_op_packets.PortVLOpPackets[i],
+			       GS_PERF_VL_OP_PACKETS_LIMIT);
+}
+
+static void pc_vl_op_packets_reset(Portcounters * pc, unsigned mask)
+{
+	int i;
+	for(i = 0; i < 16; i++)
+		if(mask & (1UL << i))
+			pc->vl_op_packets.PortVLOpPackets[i] = 0;
+}
+
+static int do_vl_op_packets(Port * port, unsigned op, uint32_t unused, uint8_t * data)
+{
+	return do_portcounters_common(port, op, unused, data, pc_vl_op_packets_reset,
+				      pc_vl_op_packets_get, pc_vl_op_packets_sum);
+}
+
+static void pc_vl_op_data_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA0_F,
+		pc->vl_op_data.PortVLOpData[0]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA1_F,
+		pc->vl_op_data.PortVLOpData[1]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA2_F,
+		pc->vl_op_data.PortVLOpData[2]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA3_F,
+		pc->vl_op_data.PortVLOpData[3]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA4_F,
+		pc->vl_op_data.PortVLOpData[4]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA5_F,
+		pc->vl_op_data.PortVLOpData[5]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA6_F,
+		pc->vl_op_data.PortVLOpData[6]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA7_F,
+		pc->vl_op_data.PortVLOpData[7]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA8_F,
+		pc->vl_op_data.PortVLOpData[8]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA9_F,
+		pc->vl_op_data.PortVLOpData[9]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA10_F,
+		pc->vl_op_data.PortVLOpData[10]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA11_F,
+		pc->vl_op_data.PortVLOpData[11]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA12_F,
+		pc->vl_op_data.PortVLOpData[12]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA13_F,
+		pc->vl_op_data.PortVLOpData[13]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA14_F,
+		pc->vl_op_data.PortVLOpData[14]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA15_F,
+		pc->vl_op_data.PortVLOpData[15]);
+}
+
+static void pc_vl_op_data_sum(Portcounters * totals, Portcounters * pc)
+{
+	int i;
+	for(i = 0; i < 16; i++)
+		totals->vl_op_data.PortVLOpData[i] =
+			addval(totals->vl_op_data.PortVLOpData[i],
+			       pc->vl_op_data.PortVLOpData[i], GS_PERF_VL_OP_DATA_LIMIT);
+}
+
+static void pc_vl_op_data_reset(Portcounters * pc, unsigned mask)
+{
+	int i;
+	for(i = 0; i < 16; i++)
+	{
+		if(mask & (1UL << i))
+			pc->vl_op_data.PortVLOpData[i] = 0;
+	}
+}
+
+static int do_vl_op_data(Port * port, unsigned op, uint32_t unused, uint8_t * data)
+{
+	return do_portcounters_common(port, op, unused, data, pc_vl_op_data_reset,
+		pc_vl_op_data_get, pc_vl_op_data_sum);
+}
+
+static void pc_vl_xmit_flow_ctl_update_errors_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS0_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[0]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS1_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[1]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS2_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[2]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS3_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[3]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS4_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[4]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS5_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[5]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS6_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[6]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS7_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[7]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS8_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[8]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS9_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[9]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS10_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[10]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS11_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[11]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS12_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[12]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS13_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[13]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS14_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[14]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS15_F,
+		      pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[15]);
+}
+
+static void pc_vl_xmit_flow_ctl_update_errors_sum(Portcounters * totals, Portcounters * pc)
+{
+	int i;
+	for(i = 0; i < 16; i++)
+		totals->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[i] =
+			addval(totals->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[i],
+			       pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[i],
+			       GS_PERF_VL_XMIT_FLOW_CTL_UPDATE_ERRORS);
+}
+
+static void pc_vl_xmit_flow_ctl_update_errors_reset(Portcounters * pc, unsigned mask)
+{
+	int i;
+	for(i = 0; i < 16; i++)
+		if(mask & (1UL << i))
+			pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[i] = 0;
+}
+
+static int do_vl_xmit_flow_ctl_update_errors(Port * port, unsigned op, uint32_t unused, uint8_t * data)
+{
+	return do_portcounters_common(port, op, unused, data, pc_vl_xmit_flow_ctl_update_errors_reset,
+		pc_vl_xmit_flow_ctl_update_errors_get, pc_vl_xmit_flow_ctl_update_errors_sum);
+}
+
+static void pc_vl_xmit_wait_counters_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT0_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[0]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT1_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[1]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT2_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[2]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT3_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[3]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT4_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[4]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT5_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[5]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT6_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[6]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT7_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[7]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT8_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[8]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT9_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[9]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT10_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[10]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT11_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[11]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT12_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[12]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT13_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[13]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT14_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[14]);
+	mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT15_F,
+		      pc->vl_xmit_wait_counters.PortVLXmitWait[15]);
+}
+
+static void pc_vl_xmit_wait_counters_sum(Portcounters * totals, Portcounters * pc)
+{
+	int i;
+	for(i = 0; i < 16; i++)
+		totals->vl_xmit_wait_counters.PortVLXmitWait[i] =
+			addval(totals->vl_xmit_wait_counters.PortVLXmitWait[i],
+			       pc->vl_xmit_wait_counters.PortVLXmitWait[i],
+			       GS_PERF_VL_XMIT_WAIT_COUNTERS_LIMIT);
+}
+
+static void pc_vl_xmit_wait_counters_reset(Portcounters * pc, unsigned mask)
+{
+	int i;
+	for(i = 0; i < 16; i++)
+		if(mask & (1UL << i))
+			pc->vl_xmit_wait_counters.PortVLXmitWait[i] = 0;
+}
+
+static int do_vl_xmit_wait_counters(Port * port, unsigned op, uint32_t unused,
+				     uint8_t * data)
+{
+	return do_portcounters_common(port, op, unused, data,
+				      pc_vl_xmit_wait_counters_reset,
+				      pc_vl_xmit_wait_counters_get,
+				      pc_vl_xmit_wait_counters_sum);
+}
+
+
 static char *pathstr(int lid, ib_dr_path_t * path)
 {
 	static char buf[1024] = "local";
@@ -851,7 +1358,7 @@ static char *pathstr(int lid, ib_dr_path_t * path)
 	int i;
 
 	if (0 && lid != -1) {
-		sprintf(buf, "lid 0x%x", lid);
+		sprintf(buf, "lid %u", lid);
 		return buf;
 	}
 	for (i = 0; i < path->cnt + 1; i++) {
@@ -870,12 +1377,12 @@ static int switch_lookup(Node * node, int lid)
 {
 	int outport;
 
-	DEBUG("node 0x%" PRIx64 " lid %d", node->nodeguid, lid);
+	DEBUG("node 0x%" PRIx64 " lid %u", node->nodeguid, lid);
 	if (!node->sw)
 		return -1;
 
 	if (lid > node->sw->linearFDBtop || (outport = node->sw->fdb[lid]) < 0) {
-		IBWARN("sw guid %" PRIx64 ": bad lid %d", node->nodeguid, lid);
+		IBWARN("sw guid %" PRIx64 ": bad lid %u", node->nodeguid, lid);
 		return -1;
 	}
 
@@ -895,7 +1402,7 @@ static int port_get_remote(Port * port, Node ** remotenode, Port ** remoteport)
 
 static int is_port_lid(Port * port, int lid)
 {
-	DEBUG("port 0x%" PRIx64 " lid %d lmc %d target lid %d",
+	DEBUG("port 0x%" PRIx64 " lid %u lmc %d target lid %u",
 	      port->portguid, port->lid, port->lmc, lid);
 	if (lid < port->lid || lid > port->lid + (1 << port->lmc) - 1)
 		return 0;
@@ -929,7 +1436,7 @@ static Port *lid_route_MAD(Port * port, int lid)
 	Node *node = port->node;
 	Port *tport = port;
 
-	DEBUG("Node %" PRIx64 " port %" PRIx64 " (%d) lid %d",
+	DEBUG("Node %" PRIx64 " port %" PRIx64 " (%d) lid %u",
 	      node->nodeguid, port->portguid, port->portnum, lid);
 
 	if (lid == 0) {
@@ -955,7 +1462,7 @@ static Port *lid_route_MAD(Port * port, int lid)
 
 		if (portnum < 0 || portnum > node->numports) {
 			pc_add_error_rcvswitchrelay(port);
-			DEBUG("illegal lid %d (outport %d node %s ports %d)",
+			DEBUG("illegal lid %u (outport %d node %s ports %d)",
 			      lid, portnum, node->nodeid, node->numports);
 			return 0;
 		}
@@ -1108,9 +1615,7 @@ static Port *route_MAD(Port * port, int response, int lid, ib_dr_path_t * path)
 	    direct_route_out_MAD(port, path);
 }
 
-int modified;
-
-Smpfn *get_handle_fn(ib_rpc_t rpc, int response)
+static Smpfn *get_handle_fn(ib_rpc_t rpc, int response)
 {
 	Smpfn *fn;
 
@@ -1120,14 +1625,14 @@ Smpfn *get_handle_fn(ib_rpc_t rpc, int response)
 	if (rpc.mgtclass == IB_SMI_CLASS || rpc.mgtclass == IB_SMI_DIRECT_CLASS) {
 		if (rpc.attr.id >= IB_ATTR_LAST
 		    || !(fn = attrs[rpc.mgtclass & 0xf][rpc.attr.id]))
-			return 0;	// not supported attribute ???
+			return 0;	// attribute/method not supported ???
 		return fn;
 	}
 
 	if (rpc.mgtclass == IB_PERFORMANCE_CLASS) {
 		if (rpc.attr.id >= IB_GSI_ATTR_LAST
 		    || !(fn = attrs[rpc.mgtclass & 0xf][rpc.attr.id]))
-			return 0;	// not supported attribute ???
+			return 0;	// attribute/method not supported ???
 		return fn;
 	}
 
@@ -1161,13 +1666,13 @@ int process_packet(Client * cl, void *p, int size, Client ** dcl)
 		return -1;
 
 	if (rpc.method == 0x7) {
-		IBWARN("got trap repress - drop");
+		IBWARN("lid %u got trap repress - dropping", ntohs(r->dlid));
 		*dcl = 0;
 		return 0;
 	}
 
 	if (!(port = route_MAD(cl->port, response, ntohs(r->dlid), &path))) {
-		IBWARN("routing failed: no route to dest lid %d path %s",
+		IBWARN("routing failed: no route to dest lid %u path %s",
 		       ntohs(r->dlid), pathstr(0, &path));
 		goto _dropped;
 	}
@@ -1198,9 +1703,6 @@ int process_packet(Client * cl, void *p, int size, Client ** dcl)
 	if ((status = fn(port, rpc.method, rpc.attr.mod, data)) < 0)
 		goto _dropped;
 
-	if (rpc.method == 2)
-		modified++;
-
 	reply_MAD(r->mad, &rpc, &path, status, data);
 
 	tlid = r->dlid;
@@ -1231,7 +1733,7 @@ static int encode_trap128(Port * port, char *data)
 	if (port->node->type != SWITCH_NODE)
 		return -1;
 	if (!port->lid || !port->smlid) {
-		VERB("switch trap 128 for lid %d with smlid %d",
+		VERB("switch trap 128 for lid %u with smlid %u",
 		     port->lid, port->smlid);
 		return -1;
 	}
@@ -1251,7 +1753,7 @@ static int encode_trap128(Port * port, char *data)
 static int encode_trap144(Port * port, char *data)
 {
 	if (!port->lid || !port->smlid) {
-		VERB("switch trap 144 for lid %d with smlid %d",
+		VERB("switch trap 144 for lid %u with smlid %u",
 		     port->lid, port->smlid);
 		return -1;
 	}
@@ -1281,27 +1783,28 @@ static int encode_trap_header(char *buf)
 	return 0;
 }
 
-int send_trap(Port * port, int trapnum)
+int send_trap(Port * port, unsigned trapnum)
 {
 	struct sim_request req;
 	Client *cl;
 	int ret, lid = port->lid;
 	char *data = req.mad + 64;	/* data offset */
-	EncodeTrapfn *encode_trapfn = encodetrap[trapnum];
+	EncodeTrapfn *encode_trapfn;
 	Port *destport;
 
-	if (!encode_trapfn) {
+	if (trapnum >= TRAP_NUM_LAST) {
 		IBWARN("trap number %d not supported", trapnum);
 		return -1;
 	}
 
+	encode_trapfn = encodetrap[trapnum];
 	memset(req.mad, 0, sizeof(req.mad));
 	encode_trap_header(req.mad);
 	if (encode_trapfn(port, data) < 0)
 		return -1;
 
 	if (!(destport = lid_route_MAD(port, port->smlid))) {
-		IBWARN("routing failed: no route to dest lid %d", port->smlid);
+		IBWARN("routing failed: no route to dest lid %u", port->smlid);
 		return -1;
 	}
 
diff --git a/ibsim/sim_net.c b/ibsim/sim_net.c
index ee268e0..10820ba 100644
--- a/ibsim/sim_net.c
+++ b/ibsim/sim_net.c
@@ -67,7 +67,7 @@ Port *default_port;
 static const uint8_t smaport[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x48,
+	0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48,
 	0x00, 0x00, 0x0F, 0xF9, 0x00, 0x03, 0x03, 0x01,
 	0x14, 0x52, 0x00, 0x11, 0x10, 0x40, 0x00, 0x08,
 	0x08, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
@@ -80,7 +80,7 @@ static const uint8_t swport[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x02,
-	0x14, 0x52, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08,
+	0x12, 0x52, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08,
 	0x08, 0x04, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -100,9 +100,9 @@ static const uint8_t swport_down[] = {
 static const uint8_t hcaport[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x02, 0x00, 0x01, 0x00, 0x50, 0x02, 0x48,
+	0x00, 0x02, 0x00, 0x01, 0x00, 0x50, 0x00, 0x48,
 	0x00, 0x00, 0x0F, 0xF9, 0x01, 0x03, 0x03, 0x02,
-	0x14, 0x52, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08,
+	0x12, 0x52, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08,
 	0x08, 0x04, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x20, 0x1F, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -111,7 +111,7 @@ static const uint8_t hcaport[] = {
 static const uint8_t hcaport_down[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x02, 0x00, 0x01, 0x00, 0x10, 0x02, 0x48,
+	0x00, 0x02, 0x00, 0x01, 0x00, 0x10, 0x00, 0x48,
 	0x00, 0x00, 0x0F, 0xF9, 0x01, 0x03, 0x03, 0x01,
 	0x11, 0x22, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08,
 	0x08, 0x04, 0xE9, 0x10, 0x00, 0x00, 0x00, 0x00,
@@ -322,6 +322,8 @@ static Node *new_node(int type, char *nodename, char *nodedesc, int nodeports)
 		guids[type]++;	// reserve single guid;
 	} else {
 		memcpy(nd->nodeinfo, hcanodeinfo, sizeof(nd->nodeinfo));
+		if (type == ROUTER_NODE)
+			mad_set_field(nd->nodeinfo, 0, IB_NODE_TYPE_F, ROUTER_NODE);
 		guids[type] += nodeports + 1;	// reserve guids;
 	}
 
@@ -403,7 +405,7 @@ static int is_linkwidth_valid(int width)
 
 static int is_linkspeed_valid(int speed)
 {
-	/* speed is 2.5G, 5.0G, or 10.0 G */
+	/* speed is 2.5G, 5.0G, or 10.0G */
 	if (speed < 1 || speed > 7) {
 		IBWARN("bad speed %d - should be between 1 to 7", speed);
 		return 0;
@@ -677,7 +679,6 @@ static int parse_port(char *line, Node * node, int type, int maxports)
 			IBWARN("bad port option");
 			return -1;
 		}
-		line = s + 1;
 	}
 	if (type != SWITCH_NODE && line && parse_port_lid_and_lmc(port, line) < 0) {
 		IBWARN("cannot parse lid, lmc");
@@ -1114,7 +1115,7 @@ int link_ports(Port * lport, Port * rport)
 	rport->remoteport = lport->portnum;
 	set_portinfo(rport, rnode->type == SWITCH_NODE ? swport : hcaport);
 	memcpy(rport->remotenodeid, lnode->nodeid, sizeof(rport->remotenodeid));
-	lport->state = rport->state = 2;	// Initialilze
+	lport->state = rport->state = 2;	// Initialize
 	lport->physstate = rport->physstate = 5;	// LinkUP
 	if (lnode->sw)
 		lnode->sw->portchange = 1;
diff --git a/tests/Makefile b/tests/Makefile
index dd4cd55..a48cfc4 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,4 +1,4 @@
-progs:= mcast_storm
+progs:= subnet_discover query_many mcast_storm
 
 -include ../defs.mk
 
diff --git a/tests/mcast_storm.c b/tests/mcast_storm.c
index b2bf19a..61f0348 100644
--- a/tests/mcast_storm.c
+++ b/tests/mcast_storm.c
@@ -29,6 +29,7 @@
 #define TMO 100
 
 #define DEFAULT_PREFIX 0xfe80000000000000ULL
+#define DEFAULT_MGID_PREFIX 0xff00000000000000ULL
 
 /* Multicast Member Record Component Masks */
 #define IB_MCR_COMPMASK_MGID        (1ULL<<0)
@@ -57,39 +58,97 @@ struct addr_data {
 	ib_portid_t dport;
 };
 
+struct mcmember_params {
+	uint32_t qkey;
+	uint16_t mlid;
+	uint8_t mtu;
+	int tclass;
+	uint16_t pkey;
+	uint8_t rate;
+	int sl;
+	int flow_label;
+	int hop_limit;
+	uint8_t scope;
+	uint8_t join_state;
+	int proxy_join;
+};
+
+static const struct mcmember_params null_params = {
+	.tclass = -1,
+	.sl = -1,
+	.flow_label = -1,
+	.hop_limit = -1,
+	.proxy_join = -1,
+};
+
+static const struct mcmember_params mcmember_params_join = {
+	.tclass = -1,
+	.sl = -1,
+	.flow_label = -1,
+	.hop_limit = -1,
+	.join_state = 1,
+	.proxy_join = -1,
+};
+
+static const struct mcmember_params mcmember_params_create = {
+	.qkey = 0x80010000,
+	.mtu = 4,
+	.tclass = 0,
+	.pkey = 0xffff,
+	.rate = 3,
+	.sl = 0,
+	.flow_label = 0,
+	.hop_limit = -1,
+	.join_state = 1,
+	.proxy_join = -1,
+};
+
 static ibmad_gid_t mgid_ipoib = {
 	0xff, 0x12, 0x40, 0x1b, 0xff, 0xff, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
 };
 
-uint64_t build_mcm_rec(uint8_t * data, ibmad_gid_t mgid, ibmad_gid_t port_gid,
-		       uint8_t join_state)
+static int64_t add_rid(uint8_t *data, ibmad_gid_t mgid, ibmad_gid_t port_gid)
 {
-	memset(data, 0, IB_SA_DATA_SIZE);
 	mad_set_array(data, 0, IB_SA_MCM_MGID_F, mgid);
 	mad_set_array(data, 0, IB_SA_MCM_PORTGID_F, port_gid);
-	mad_set_field(data, 0, IB_SA_MCM_JOIN_STATE_F, join_state);
 
-	return IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID |
-	    IB_MCR_COMPMASK_JOIN_STATE;
+	return IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID;
 }
 
-uint64_t build_mcm_create_rec(uint8_t * data, ibmad_gid_t mgid,
-			      ibmad_gid_t port_gid, uint8_t join_state)
+static uint64_t build_mcm_rec(uint8_t * data, const struct mcmember_params *p)
 {
-	uint64_t comp_mask = build_mcm_rec(data, mgid, port_gid, join_state);
-
-	mad_set_field(data, 0, IB_SA_MCM_QKEY_F, 0x80010000);
-	mad_set_field(data, 0, IB_SA_MCM_SL_F, 0);
-	mad_set_field(data, 0, IB_SA_MCM_MTU_F, 4);
-	mad_set_field(data, 0, IB_SA_MCM_RATE_F, 3);
-	mad_set_field(data, 0, IB_SA_MCM_TCLASS_F, 0);
-	mad_set_field(data, 0, IB_SA_MCM_PKEY_F, 0xffff);
-	mad_set_field(data, 0, IB_SA_MCM_FLOW_LABEL_F, 0);
-
-	return comp_mask | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_SL |
-	    IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_PKEY |
-	    IB_MCR_COMPMASK_TCLASS | IB_MCR_COMPMASK_FLOW;
+#define SET_FIELD1(val, mask, field) \
+	if (val) { \
+		mad_set_field(data, 0, field, val); \
+		comp_mask |= mask; \
+	}
+
+#define SET_FIELD(obj, name, mask, field) \
+	if (obj->name != null_params.name) { \
+		mad_set_field(data, 0, field, obj->name); \
+		comp_mask |= mask; \
+	}
+
+	uint64_t comp_mask = 0;
+
+	memset(data, 0, IB_SA_DATA_SIZE);
+
+	if (!p)
+		return comp_mask;
+
+	SET_FIELD(p, qkey, IB_MCR_COMPMASK_QKEY, IB_SA_MCM_QKEY_F);
+	SET_FIELD(p, mlid, IB_MCR_COMPMASK_MLID, IB_SA_MCM_MLID_F);
+	SET_FIELD(p, mtu, IB_MCR_COMPMASK_MTU, IB_SA_MCM_MTU_F);
+	SET_FIELD(p, tclass, IB_MCR_COMPMASK_TCLASS, IB_SA_MCM_TCLASS_F);
+	SET_FIELD(p, pkey, IB_MCR_COMPMASK_PKEY, IB_SA_MCM_PKEY_F);
+	SET_FIELD(p, rate, IB_MCR_COMPMASK_RATE, IB_SA_MCM_RATE_F);
+	SET_FIELD(p, sl, IB_MCR_COMPMASK_SL, IB_SA_MCM_SL_F);
+	SET_FIELD(p, flow_label, IB_MCR_COMPMASK_FLOW, IB_SA_MCM_FLOW_LABEL_F);
+	SET_FIELD(p, join_state, IB_MCR_COMPMASK_JOIN_STATE, IB_SA_MCM_JOIN_STATE_F);
+	SET_FIELD(p, proxy_join, IB_MCR_COMPMASK_PROXY, IB_SA_MCM_PROXY_JOIN_F);
+
+	return comp_mask;
 }
 
 static void build_mcm_rec_umad(void *umad, ib_portid_t * dport, int method,
@@ -155,46 +214,29 @@ static int recv_res(struct addr_data *a, uint8_t * umad, int length)
 	return 1;
 }
 
-static int send_create(struct addr_data *a, uint8_t * umad, int len,
-		       ibmad_gid_t mgid, ibmad_gid_t port_gid)
-{
-	uint8_t data[IB_SA_DATA_SIZE];
-	uint64_t comp_mask;
-
-	comp_mask = build_mcm_create_rec(data, mgid, port_gid, 1);
-
-	return send_req(a, umad, len, IB_MAD_METHOD_SET, comp_mask, data);
-}
-
 static int send_join(struct addr_data *a, uint8_t * umad, int len,
-		     ibmad_gid_t mgid, ibmad_gid_t port_gid)
+		     ibmad_gid_t mgid, ibmad_gid_t port_gid,
+		     uint64_t comp_mask, uint8_t data[])
 {
-	uint8_t data[IB_SA_DATA_SIZE];
-	uint64_t comp_mask;
-
-	comp_mask = build_mcm_rec(data, mgid, port_gid, 1);
+	comp_mask |= add_rid(data, mgid, port_gid);
 
 	return send_req(a, umad, len, IB_MAD_METHOD_SET, comp_mask, data);
 }
 
 static int send_leave(struct addr_data *a, uint8_t * umad, int len,
-		      ibmad_gid_t mgid, ibmad_gid_t port_gid)
+		      ibmad_gid_t mgid, ibmad_gid_t port_gid,
+		      uint64_t comp_mask, uint8_t data[])
 {
-	uint8_t data[IB_SA_DATA_SIZE];
-	uint64_t comp_mask;
-
-	comp_mask = build_mcm_rec(data, mgid, port_gid, 1);
+	comp_mask |= add_rid(data, mgid, port_gid);
 
 	return send_req(a, umad, len, IB_MAD_METHOD_DELETE, comp_mask, data);
 }
 
 static int send_query(struct addr_data *a, uint8_t * umad, int len,
-		      ibmad_gid_t mgid, ibmad_gid_t port_gid)
+		      ibmad_gid_t mgid, ibmad_gid_t port_gid,
+		      uint64_t comp_mask, uint8_t data[])
 {
-	uint8_t data[IB_SA_DATA_SIZE];
-	uint64_t comp_mask;
-
-	comp_mask = build_mcm_rec(data, mgid, port_gid, 1);
+	comp_mask |= add_rid(data, mgid, port_gid);
 
 	return send_req(a, umad, len, IB_MAD_METHOD_GET, comp_mask, data);
 }
@@ -221,8 +263,7 @@ static int recv_all(struct addr_data *a, void *umad, int len)
 		method = mad_get_field(mad, 0, IB_MAD_METHOD_F);
 		status = mad_get_field(mad, 0, IB_MAD_STATUS_F);
 
-		if (status &&
-		    (method & 0x7f) == (IB_MAD_METHOD_GET_RESPONSE & 0x7f)) {
+		if (status) {
 			trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
 			info("mad trid 0x%016" PRIx64
 			     ": method = %x status = %x.\n",
@@ -236,60 +277,32 @@ static int recv_all(struct addr_data *a, void *umad, int len)
 }
 
 static int rereg_port(struct addr_data *a, uint8_t * umad, int len,
-		      ibmad_gid_t mgid, struct gid_list *list)
+		      ibmad_gid_t mgid, struct gid_list *list,
+		      uint64_t comp_mask, uint8_t data[])
 {
-	if (send_leave(a, umad, len, mgid, list->gid))
+	if (send_leave(a, umad, len, mgid, list->gid, comp_mask, data))
 		return -1;
 
-	if (send_join(a, umad, len, mgid, list->gid))
+	if (send_join(a, umad, len, mgid, list->gid, comp_mask, data))
 		return -1;
-	list->trid = mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F);
-
-	return 0;
-}
 
-static int rereg_send_all(struct addr_data *a, ibmad_gid_t mgid,
-			  struct gid_list *list, unsigned cnt)
-{
-	uint8_t *umad;
-	int len = 256;
-	int i;
-
-	info("%s:... cnt = %u\n", __func__, cnt);
-
-	umad = calloc(1, len + umad_size());
-	if (!umad) {
-		err("cannot alloc mem for umad: %s\n", strerror(errno));
-		return -1;
-	}
-
-	for (i = 0; i < cnt; i++)
-		rereg_port(a, umad, len, mgid, &list[i]);
-
-	info("%s: sent %u requests\n", __func__, cnt * 2);
-
-	free(umad);
+	list->trid = mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F);
 
 	return 0;
 }
 
-static int rereg_recv_all(struct addr_data *a, ibmad_gid_t mgid,
-			  struct gid_list *list, unsigned cnt)
+static int rereg_recv_all(struct addr_data *a, void *umad, int len,
+			  ibmad_gid_t mgid,
+			  struct gid_list *list, unsigned cnt,
+			  uint64_t comp_mask, uint8_t data[])
 {
-	uint8_t *umad, *mad;
-	int len = 256;
+	uint8_t *mad;
 	uint64_t trid;
 	unsigned n, method, status;
 	int i;
 
 	info("%s...\n", __func__);
 
-	umad = calloc(1, len + umad_size());
-	if (!umad) {
-		err("cannot alloc mem for umad: %s\n", strerror(errno));
-		return -1;
-	}
-
 	n = 0;
 	while (recv_res(a, umad, len) > 0) {
 		dbg("rereg_recv_all: done %d\n", n);
@@ -316,34 +329,30 @@ static int rereg_recv_all(struct addr_data *a, ibmad_gid_t mgid,
 			info("guid 0x%016" PRIx64
 			     ": method = %x status = %x. Resending\n",
 			     get_guid_ho(list[i].gid), method, status);
-			rereg_port(a, umad, len, mgid, &list[i]);
+			rereg_port(a, umad, len, mgid, &list[i],
+				   comp_mask, data);
 		}
 	}
 
 	info("%s: got %u responses\n", __func__, n);
 
-	free(umad);
 	return 0;
 }
 
-static int rereg_query_all(struct addr_data *a, ibmad_gid_t mgid,
-			   struct gid_list *list, unsigned cnt)
+static int rereg_query_all(struct addr_data *a, void *umad, int len,
+			   ibmad_gid_t mgid,
+			   struct gid_list *list, unsigned cnt,
+			   uint64_t comp_mask, uint8_t data[])
 {
-	uint8_t *umad, *mad;
-	int len = 256;
+	uint8_t *mad;
 	unsigned method, status;
 	int i, ret;
 
 	info("%s...\n", __func__);
 
-	umad = calloc(1, len + umad_size());
-	if (!umad) {
-		err("cannot alloc mem for umad: %s\n", strerror(errno));
-		return -1;
-	}
-
 	for (i = 0; i < cnt; i++) {
-		ret = send_query(a, umad, len, mgid, list[i].gid);
+		ret = send_query(a, umad, len, mgid, list[i].gid,
+				 comp_mask, data);
 		if (ret < 0) {
 			err("%s: rereg_send failed.\n", __func__);
 			continue;
@@ -367,7 +376,6 @@ static int rereg_query_all(struct addr_data *a, ibmad_gid_t mgid,
 
 	info("%s: %u queried.\n", __func__, cnt);
 
-	free(umad);
 	return 0;
 }
 
@@ -378,33 +386,18 @@ struct test_data {
 	struct gid_list *gids;
 	unsigned mgids_size;
 	struct gid_list *mgids;
+	const struct mcmember_params *params;
 };
 
 #define MAX_CLIENTS 100
 
 static int run_port_rereg_test(struct addr_data *a, struct test_data *td)
 {
-	int cnt, i, size = td->gids_size;
-
-	for (cnt = size; cnt;) {
-		i = cnt > MAX_CLIENTS ? MAX_CLIENTS : cnt;
-		rereg_send_all(a, td->mgids[0].gid, td->gids + (size - cnt), i);
-		rereg_recv_all(a, td->mgids[0].gid, td->gids, size);
-		cnt -= i;
-	}
-
-	rereg_query_all(a, td->mgids[0].gid, td->gids, size);
-
-	return 0;
-}
-
-static int run_mcast_joins_test(struct addr_data *a, struct test_data *td)
-{
+	uint8_t data[256];
+	uint64_t comp_mask;
 	uint8_t *umad;
 	int len = 256;
-	unsigned i, j;
-
-	info("%s...\n", __func__);
+	int cnt, i, n, size = td->gids_size;
 
 	umad = calloc(1, len + umad_size());
 	if (!umad) {
@@ -412,38 +405,55 @@ static int run_mcast_joins_test(struct addr_data *a, struct test_data *td)
 		return -1;
 	}
 
-	for (i = 0; i < td->gids_size; i++)
-		for (j = 0; j < td->mgids_size; j++)
-			if (send_create(a, umad, len,
-					td->mgids[j].gid, td->gids[i].gid))
-				return -1;
+	if (!td->params)
+		td->params = &mcmember_params_join;
 
-	if (recv_all(a, umad, len) < 0)
-		return -1;
+	comp_mask = build_mcm_rec(data, td->params);
+
+	for (cnt = size; cnt;) {
+		n = cnt > MAX_CLIENTS ? MAX_CLIENTS : cnt;
+		for (i = 0; i < n; i++) {
+			rereg_port(a, umad, len, td->mgids[0].gid,
+				   &td->gids[size - cnt + i], comp_mask, data);
+			info("%s: sent %u requests\n", __func__, n * 2);
+		}
+		rereg_recv_all(a, umad, len, td->mgids[0].gid, td->gids, size,
+			       comp_mask, data);
+		cnt -= i;
+	}
+
+	rereg_query_all(a, umad, len, td->mgids[0].gid, td->gids, size,
+			comp_mask, data);
 
 	free(umad);
 
 	return 0;
 }
 
-static int run_mcast_leave_test(struct addr_data *a, struct test_data *td)
+static int run_mcast_member_test(struct addr_data *a, struct test_data *td,
+				 int (*func)(struct addr_data *a,
+					     uint8_t * umad, int len,
+					     ibmad_gid_t mgid, ibmad_gid_t gid,
+					     uint64_t comp_mask, uint8_t *data))
 {
+	uint8_t data[256];
+	uint64_t comp_mask;
 	uint8_t *umad;
 	int len = 256;
 	unsigned i, j;
 
-	info("%s...\n", __func__);
-
 	umad = calloc(1, len + umad_size());
 	if (!umad) {
 		err("cannot alloc mem for umad: %s\n", strerror(errno));
 		return -1;
 	}
 
+	comp_mask = build_mcm_rec(data, td->params);
+
 	for (i = 0; i < td->gids_size; i++)
 		for (j = 0; j < td->mgids_size; j++)
-			if (send_leave(a, umad, len,
-				       td->mgids[j].gid, td->gids[i].gid))
+			if (func(a, umad, len, td->mgids[j].gid,
+				 td->gids[i].gid, comp_mask, data))
 				return -1;
 
 	if (recv_all(a, umad, len) < 0)
@@ -454,6 +464,20 @@ static int run_mcast_leave_test(struct addr_data *a, struct test_data *td)
 	return 0;
 }
 
+static int run_mcast_joins_test(struct addr_data *a, struct test_data *td)
+{
+	if (!td->params)
+		td->params = &mcmember_params_create;
+	return run_mcast_member_test(a, td, send_join);
+}
+
+static int run_mcast_leave_test(struct addr_data *a, struct test_data *td)
+{
+	if (!td->params)
+		td->params = &mcmember_params_join;
+	return run_mcast_member_test(a, td, send_leave);
+}
+
 /* main stuff */
 
 struct test {
@@ -462,14 +486,15 @@ struct test {
 	const char *description;
 };
 
-static int run_test(const struct test *t, struct test_data *td)
+static int run_test(const struct test *t, struct test_data *td,
+		    struct ibmad_port *mad_port)
 {
 	struct addr_data addr;
 	int ret;
 
 	info("Running \'%s\'...\n", t->name);
 
-	ib_resolve_smlid(&addr.dport, TMO);
+	ib_resolve_smlid_via(&addr.dport, TMO, mad_port);
 	if (!addr.dport.lid) {
 		/* dport.lid = 1; */
 		err("No SM. Exit.\n");
@@ -479,7 +504,7 @@ static int run_test(const struct test *t, struct test_data *td)
 	if (!addr.dport.qkey)
 		addr.dport.qkey = IB_DEFAULT_QP1_QKEY;
 
-	addr.port = madrpc_portid();
+	addr.port = mad_rpc_portid(mad_port);
 	addr.agent = umad_register(addr.port, IB_SA_CLASS, 2, 0, NULL);
 	addr.timeout = TMO;
 
@@ -528,13 +553,55 @@ static int make_gids_list(ibmad_gid_t gid, unsigned n, struct gid_list **gid_lis
 	return i;
 }
 
+static int parse_gid_str(ibmad_gid_t gid, char *str, uint64_t default_prefix)
+{
+	uint64_t guid, prefix = 0;
+	char *p, *e;
+
+	p = str;
+	while (isspace(*p))
+		p++;
+	e = strchr(p, '\n');
+	if (e) {
+		while (isspace(*e))
+			*e-- = '\0';
+	}
+
+	if (*p == '\0' || *p == '#')
+		return 1;
+
+	if (inet_pton(AF_INET6, p, gid) > 0)
+		return 0;
+
+	e = strchr(p, ':');
+	if (e) {
+		prefix = strtoull(p, NULL, 0);
+		guid = strtoull(e + 1, NULL, 0);
+	} else if (strlen(p) > 18) {
+		e = p + strlen(p) - 16;
+		guid = strtoull(e, NULL, 16);
+		*e = '\0';
+		prefix = strtoull(p, NULL, 0);
+	} else
+		guid = strtoull(p, NULL, 0);
+
+	if (!guid)
+		return -1;
+
+	if (!prefix)
+		prefix = default_prefix;
+
+	make_gid(gid, prefix, guid);
+
+	return 0;
+}
+
 static int parse_gids_file(const char *guid_file, struct gid_list **gid_list)
 {
 	char line[256];
+	ibmad_gid_t gid;
 	FILE *f;
-	uint64_t guid, prefix;
 	struct gid_list *list = NULL;
-	char *e;
 	unsigned list_size = 0;
 	int i = 0;
 
@@ -546,12 +613,8 @@ static int parse_gids_file(const char *guid_file, struct gid_list **gid_list)
 	}
 
 	while (fgets(line, sizeof(line), f)) {
-		guid = strtoull(line, &e, 0);
-		if (e && isxdigit(*e)) {
-			prefix = guid;
-			guid = strtoull(line, NULL, 0);
-		} else
-			prefix = DEFAULT_PREFIX;
+		if (parse_gid_str(gid, line, DEFAULT_PREFIX))
+			continue;
 
 		if (i >= list_size) {
 			list_size += 256;
@@ -564,7 +627,7 @@ static int parse_gids_file(const char *guid_file, struct gid_list **gid_list)
 			memset(&list[i], 0, 256 * sizeof(list[0]));
 		}
 
-		make_gid(list[i].gid, prefix, guid);
+		memcpy(list[i].gid, gid, 16);
 		i++;
 	}
 	fclose(f);
@@ -622,6 +685,16 @@ int main(int argc, char **argv)
 		{"MGID", 1, 0, 'M'},
 		{"ipv4", 0, 0, 'i'},
 		{"increment", 1, 0, 'I'},
+		{"qkey", 1, 0, 'q'},
+		{"mlid", 1, 0, 'z'},
+		{"mtu", 1, 0, 'y'},
+		{"tclass", 1, 0, 't'},
+		{"pkey", 1, 0, 'p'},
+		{"rate", 1, 0, 'r'},
+		{"sl", 1, 0, 's'},
+		{"flowlabel", 1, 0, 'f'},
+		{"joinstate", 1, 0, 'j'},
+		{"proxy", 0, 0, 'x'},
 		{"version", 0, 0, 'V'},
 		{"verbose", 0, 0, 'v'},
 		{"help", 0, 0, 'h'},
@@ -636,14 +709,18 @@ int main(int argc, char **argv)
 
 	char opt_str[256];
 	int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS };
+	struct mcmember_params params;
 	struct test_data tdata;
 	ibmad_gid_t gid, mgid = {};
 	uint64_t guid = 0;
 	const char *guid_file = NULL, *mgid_file = NULL;
+	struct ibmad_port *mad_port;
 	const struct test *t;
 	unsigned is_mgid = 0, is_ipv4 = 1, increment = 0;
 	int ret, ch;
 
+	params = null_params;
+
 	make_str_opts(opt_str, sizeof(opt_str), long_opts);
 
 	while ((ch = getopt_long(argc, argv, opt_str, long_opts, NULL)) != -1) {
@@ -652,18 +729,11 @@ int main(int argc, char **argv)
 			guid = strtoull(optarg, NULL, 0);
 			break;
 		case 'M':
-			{ char *e; uint64_t val1, val2;
-			int len = strlen(optarg);
-			if (len > 16)
-				e = optarg + len - 16;
-			else
-				e = optarg;
-			val2 = strtoull(e, NULL, 16);
-			*e = '\0';
-			val1 = strtoull(optarg, NULL, 16);
-			make_gid(mgid, val1, val2);
-			is_mgid = 1;
+			if (parse_gid_str(mgid, optarg, DEFAULT_MGID_PREFIX)) {
+				err("cannot parse MGID \'%s\'", optarg);
+				exit(2);
 			}
+			is_mgid = 1;
 			break;
 		case 'I':
 			increment = strtoul(optarg, NULL, 0);
@@ -674,6 +744,36 @@ int main(int argc, char **argv)
 		case 'm':
 			mgid_file = optarg;
 			break;
+		case 'q':
+			params.qkey = strtoul(optarg, NULL, 0);
+			break;
+		case 'z':
+			params.mlid = strtoul(optarg, NULL, 0);
+			break;
+		case 'y':
+			params.mtu = strtoul(optarg, NULL, 0);
+			break;
+		case 't':
+			params.tclass = strtoul(optarg, NULL, 0);
+			break;
+		case 'p':
+			params.pkey = strtoul(optarg, NULL, 0);
+			break;
+		case 'r':
+			params.rate = strtoul(optarg, NULL, 0);
+			break;
+		case 's':
+			params.sl = strtoul(optarg, NULL, 0);
+			break;
+		case 'f':
+			params.flow_label = strtoul(optarg, NULL, 0);
+			break;
+		case 'j':
+			params.join_state = strtoul(optarg, NULL, 0);
+			break;
+		case 'x':
+			params.proxy_join = 1;
+			break;
 		case 'v':
 			break;
 		case 'V':
@@ -686,7 +786,11 @@ int main(int argc, char **argv)
 		}
 	}
 
-	madrpc_init(NULL, 0, mgmt_classes, 2);
+	mad_port = mad_rpc_open_port(NULL, 0, mgmt_classes, 2);
+	if (!mad_port) {
+		err("Cannot open local port...\n");
+		exit(-1);
+	}
 
 	memset(&tdata, 0, sizeof(tdata));
 
@@ -698,7 +802,7 @@ int main(int argc, char **argv)
 		guid = get_guid_ho(tdata.gids[0].gid);
 	} else {
 		ib_portid_t portid = {0};
-		if (ib_resolve_self(&portid, NULL, &gid) < 0) {
+		if (ib_resolve_self_via(&portid, NULL, &gid, mad_port) < 0) {
 			err("Cannot resolve self port...\n");
 			exit(1);
 		}
@@ -717,7 +821,7 @@ int main(int argc, char **argv)
 	else if (is_ipv4)
 		ret = make_gids_list(mgid_ipoib, increment, &tdata.mgids);
 	else {
-		make_gid(gid, 0xff00000000000000ULL, guid);
+		make_gid(gid, DEFAULT_MGID_PREFIX, guid);
 		ret = make_gids_list(gid, increment, &tdata.mgids);
 	}
 
@@ -725,14 +829,17 @@ int main(int argc, char **argv)
 		return ret;
 	tdata.mgids_size = ret;
 
+	if (memcmp(&params, &null_params, sizeof(params)))
+		tdata.params = ¶ms;
+
 	if (argc <= optind)
-		return run_test(&tests[0], &tdata);
+		return run_test(&tests[0], &tdata, mad_port);
 
 	do {
 		t = find_test(tests, argv[optind]);
 		if (!t)
 			usage(argv[0], long_opts, tests);
-		ret = run_test(t, &tdata);
+		ret = run_test(t, &tdata, mad_port);
 		if (ret)
 			break;
 	} while (argc > ++optind);
@@ -742,5 +849,7 @@ int main(int argc, char **argv)
 	if (tdata.mgids)
 		free(tdata.mgids);
 
+	mad_rpc_close_port(mad_port);
+
 	return ret;
 }
diff --git a/tests/query_many.c b/tests/query_many.c
new file mode 100644
index 0000000..6e0b9f6
--- /dev/null
+++ b/tests/query_many.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2009 Voltaire, Inc. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <sys/time.h>
+
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+static unsigned number_queries = 1;
+static uint8_t dr_path[64];
+static size_t dr_path_size = 0;
+static uint16_t attribute_id = IB_ATTR_NODE_INFO;
+static uint32_t attribute_mod = 0;
+
+static unsigned timeout = 100;
+static unsigned retries = 3;
+static unsigned verbose = 0;
+
+#define ERROR(fmt, ...) fprintf(stderr, "ERR: " fmt, ##__VA_ARGS__)
+#define VERBOSE(fmt, ...) if (verbose) fprintf(stderr, fmt, ##__VA_ARGS__)
+#define NOISE(fmt, ...) if (verbose > 1) fprintf(stderr, fmt, ##__VA_ARGS__)
+
+static const char *print_path(uint8_t path[], size_t path_cnt)
+{
+	static char buf[256];
+	int i, n = 0;
+	for (i = 0; i <= path_cnt; i++)
+		n += snprintf(buf + n, sizeof(buf) - n, "%u,", path[i]);
+	buf[n] = '\0';
+	return buf;
+}
+
+static size_t parse_direct_path(const char *str, uint8_t path[], size_t size)
+{
+	size_t i;
+
+	for (i = 0; i < size; i++) {
+		path[i] = strtoul(str, NULL, 0);
+		str = strchr(str, ',');
+		if (!str)
+			break;
+		str++;
+	}
+
+	return i;
+}
+
+static void build_umad_req(void *umad, uint8_t * path, unsigned path_cnt,
+			   uint64_t trid, uint8_t method,
+			   uint16_t attr_id, uint32_t attr_mod, uint64_t mkey)
+{
+	void *mad = umad_get_mad(umad);
+
+	memset(umad, 0, umad_size() + IB_MAD_SIZE);
+	umad_set_addr(umad, 0xffff, 0, 0, 0);
+	mad_set_field(mad, 0, IB_MAD_METHOD_F, method);
+	mad_set_field(mad, 0, IB_MAD_CLASSVER_F, 1);
+	mad_set_field(mad, 0, IB_MAD_MGMTCLASS_F, IB_SMI_DIRECT_CLASS);
+	mad_set_field(mad, 0, IB_MAD_BASEVER_F, 1);
+	mad_set_field(mad, 0, IB_DRSMP_HOPCNT_F, path_cnt);
+	mad_set_field(mad, 0, IB_DRSMP_HOPPTR_F, 0);
+	mad_set_field64(mad, 0, IB_MAD_TRID_F, trid);
+	mad_set_field(mad, 0, IB_DRSMP_DRDLID_F, 0xffff);
+	mad_set_field(mad, 0, IB_DRSMP_DRSLID_F, 0xffff);
+	mad_set_array(mad, 0, IB_DRSMP_PATH_F, path);
+	mad_set_field(mad, 0, IB_MAD_ATTRID_F, attr_id);
+	mad_set_field(mad, 0, IB_MAD_ATTRMOD_F, attr_mod);
+	mad_set_field64(mad, 0, IB_MAD_MKEY_F, mkey);
+}
+
+static void check_diff(const char *name, void *mad,
+		       struct timeval *tv1, struct timeval *tv)
+{
+	unsigned long diff = (tv1->tv_sec - tv->tv_sec) * 1000000 +
+	    tv1->tv_usec - tv->tv_usec;
+
+	if (diff > 1000) {
+		uint8_t path[256];
+		uint8_t method = mad_get_field(mad, 0, IB_MAD_METHOD_F);
+		uint64_t trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
+		uint16_t attr_id = mad_get_field(mad, 0, IB_MAD_ATTRID_F);
+		uint32_t attr_mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F);
+		size_t path_cnt = mad_get_field(mad, 0, IB_DRSMP_HOPCNT_F);
+		mad_get_array(mad, 0, IB_DRSMP_PATH_F, path);
+		printf("LONG %s (%lu) %016" PRIx64 ": method %x, attr %x,"
+		       " mod %x, path %s\n", name, diff, trid, method,
+		       attr_id, attr_mod, print_path(path, path_cnt));
+		fflush(stdout);
+	}
+}
+
+static int send_query(int fd, int agent, void *umad, uint64_t trid,
+		      uint8_t * path, size_t path_cnt, uint16_t attr_id,
+		      uint32_t attr_mod)
+{
+	struct timeval tv, tv1;
+	int ret;
+
+	build_umad_req(umad, path, path_cnt, trid, IB_MAD_METHOD_GET, attr_id,
+		       attr_mod, 0);
+
+	gettimeofday(&tv, NULL);
+
+	ret = umad_send(fd, agent, umad, IB_MAD_SIZE, timeout, retries);
+
+	gettimeofday(&tv1, NULL);
+
+	if (ret < 0) {
+		ERROR("umad_send failed: trid 0x%016" PRIx64
+		      ", attr_id %x, attr_mod %x: %s\n",
+		      trid, attr_id, attr_mod, strerror(errno));
+		return -1;
+	}
+
+	VERBOSE("send %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id,
+		attr_mod, print_path(path, path_cnt));
+
+	check_diff("SEND", umad_get_mad(umad), &tv1, &tv);
+
+	return ret;
+}
+
+static int recv_response(int fd, int agent, uint8_t * umad, uint8_t path[])
+{
+	struct timeval tv, tv1;
+	void *mad;
+	uint64_t trid;
+	uint32_t attr_mod;
+	uint16_t attr_id, status;
+	size_t path_size;
+	int len = IB_MAD_SIZE, ret;
+
+	gettimeofday(&tv, NULL);
+
+	do {
+		ret = umad_recv(fd, umad, &len, timeout);
+	} while (ret >= 0 && ret != agent);
+
+	gettimeofday(&tv1, NULL);
+
+	if (ret < 0 || umad_status(umad)) {
+		ERROR("umad_recv failed: umad status %x: %s\n",
+		      umad_status(umad), strerror(errno));
+		return -1;
+	}
+
+	check_diff("RESP", umad_get_mad(umad), &tv1, &tv);
+
+	mad = umad_get_mad(umad);
+	status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F);
+	trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
+	attr_id = mad_get_field(mad, 0, IB_MAD_ATTRID_F);
+	attr_mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F);
+	path_size = mad_get_field(mad, 0, IB_DRSMP_HOPCNT_F);
+	mad_get_array(mad, 0, IB_DRSMP_PATH_F, path);
+
+	if (status) {
+		ERROR("error response 0x%016" PRIx64 ": attr_id %x"
+		      ", attr_mod %x from %s with status %x\n", trid,
+		      attr_id, attr_mod, print_path(path, path_size), status);
+		return -1;
+	}
+
+	VERBOSE("recv %016" PRIx64 ": attr %x, mod %x from %s\n", trid, attr_id,
+		attr_mod, print_path(path, path_size));
+
+	return ret;
+}
+
+static int query(int fd, int agent)
+{
+	uint8_t path[64] = { 0 };
+	uint64_t trid = 0x20090000;
+	void *umad;
+	unsigned n = 0;
+	int ret = 0;
+
+	umad = malloc(IB_MAD_SIZE + umad_size());
+	if (!umad)
+		return -ENOMEM;
+
+	while (n++ < number_queries)
+		send_query(fd, agent, umad, trid++, dr_path, dr_path_size,
+			   attribute_id, attribute_mod);
+
+	n = 0;
+	do {
+		ret = recv_response(fd, agent, umad, path);
+	} while (ret >= 0 && ++n < number_queries);
+
+	free(umad);
+
+	return ret;
+}
+
+static int umad_query(char *card_name, unsigned int port_num)
+{
+	int fd, agent, ret;
+
+	ret = umad_init();
+	if (ret) {
+		ERROR("cannot init umad\n");
+		return -1;
+	}
+
+	fd = umad_open_port(card_name, port_num);
+	if (fd < 0) {
+		ERROR("cannot open umad port %s:%u: %s\n",
+		      card_name ? card_name : "NULL", port_num,
+		      strerror(errno));
+		return -1;
+	}
+
+	agent = umad_register(fd, IB_SMI_DIRECT_CLASS, 1, 0, NULL);
+	if (agent < 0) {
+		ERROR("cannot register SMI DR class for umad port %s:%u: %s\n",
+		      card_name ? card_name : "NULL", port_num,
+		      strerror(errno));
+		return -1;
+	}
+
+	ret = query(fd, agent);
+	if (ret)
+		ERROR("Failed.\n");
+
+	umad_unregister(fd, agent);
+	umad_close_port(fd);
+
+	umad_done();
+
+	return ret;
+}
+
+int main(int argc, char **argv)
+{
+	const struct option long_opts[] = {
+		{"number", 1, 0, 'n'},
+		{"drpath", 1, 0, 'd'},
+		{"attribute", 1, 0, 'a'},
+		{"modifier", 1, 0, 'm'},
+		{"Card", 1, 0, 'C'},
+		{"Port", 1, 0, 'P'},
+		{"timeout", 1, 0, 't'},
+		{"retries", 1, 0, 'r'},
+		{}
+	};
+	char *card_name = NULL;
+	unsigned int port_num = 0;
+	int ch, ret;
+
+	while (1) {
+		ch = getopt_long(argc, argv, "n:d:a:m:C:P:t:r:v", long_opts, NULL);
+		if (ch == -1)
+			break;
+		switch (ch) {
+		case 'n':
+			number_queries = strtoul(optarg, NULL, 0);
+			break;
+		case 'd':
+			dr_path_size = parse_direct_path(optarg, dr_path,
+							 sizeof(dr_path));
+			break;
+		case 'a':
+			attribute_id = strtoul(optarg, NULL, 0);
+			break;
+		case 'm':
+			attribute_mod = strtoul(optarg, NULL, 0);
+			break;
+		case 'C':
+			card_name = optarg;
+			break;
+		case 'P':
+			port_num = strtoul(optarg, NULL, 0);
+			break;
+		case 't':
+			timeout = strtoul(optarg, NULL, 0);
+			break;
+		case 'r':
+			retries = strtoul(optarg, NULL, 0);
+			break;
+		case 'v':
+			verbose++;
+			break;
+		default:
+			printf("Usage: %s [-n num_queries] [-d path]"
+			       " [-a attr] [-m mod]"
+			       " [-C card_name] [-P port_num]"
+			       " [-t timeout] [-r retries] [-v[v]]\n", argv[0]);
+			exit(2);
+			break;
+		}
+	}
+
+	ret = umad_query(card_name, port_num);
+
+	return ret;
+}
diff --git a/tests/subnet_discover.c b/tests/subnet_discover.c
new file mode 100644
index 0000000..44cd86e
--- /dev/null
+++ b/tests/subnet_discover.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2009 Voltaire, Inc. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <getopt.h>
+
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#define MAX_HOPS 63
+
+struct port {
+	struct node *node;
+	uint64_t guid;
+	struct port *remote;
+	uint8_t port_info[IB_SMP_DATA_SIZE];
+};
+
+struct node {
+	uint64_t guid;
+	unsigned num_ports;
+	unsigned is_switch;
+	size_t path_size;
+	uint8_t path[64];
+	uint8_t node_info[IB_SMP_DATA_SIZE];
+	uint8_t node_desc[IB_SMP_DATA_SIZE];
+	uint8_t switch_info[IB_SMP_DATA_SIZE];
+	struct port ports[];
+};
+
+static struct node *node_array[32 * 1024];
+static unsigned node_count = 0;
+static unsigned trid_cnt = 0;
+static unsigned outstanding = 0;
+static unsigned max_outstanding = 8;
+static unsigned timeout = 100;
+static unsigned retries = 3;
+static unsigned verbose = 0;
+
+static unsigned total_mads = 0;
+static unsigned max_hops = 0;
+
+#define ERROR(fmt, ...) fprintf(stderr, "ERR: " fmt, ##__VA_ARGS__)
+#define VERBOSE(fmt, ...) if (verbose) fprintf(stderr, fmt, ##__VA_ARGS__)
+#define VERBOSE1(fmt, ...) if (verbose > 1) fprintf(stderr, fmt, ##__VA_ARGS__)
+#define VERBOSE2(fmt, ...) if (verbose > 2) fprintf(stderr, fmt, ##__VA_ARGS__)
+#define NOISE(fmt, ...) VERBOSE2(fmt, ##__VA_ARGS__)
+
+static const char *print_path(uint8_t path[], size_t path_cnt)
+{
+	static char buf[256];
+	int i, n = 0;
+	for (i = 0; i <= path_cnt; i++)
+		n += snprintf(buf + n, sizeof(buf) - n, "%u,", path[i]);
+	buf[n] = '\0';
+	return buf;
+}
+
+#define DBG_DUMP_FUNC(name) static void dbg_dump_##name(void *data) \
+{ \
+	char buf[2048]; \
+	mad_dump_##name(buf, sizeof(buf), data, IB_SMP_DATA_SIZE); \
+	NOISE("### "#name":\n%s\n", buf); \
+}
+
+DBG_DUMP_FUNC(nodeinfo);
+DBG_DUMP_FUNC(nodedesc);
+DBG_DUMP_FUNC(portinfo);
+DBG_DUMP_FUNC(switchinfo);
+
+static void build_umad_req(void *umad, uint8_t path[], unsigned path_cnt,
+			   uint64_t trid, uint8_t method,
+			   uint16_t attr_id, uint32_t attr_mod, uint64_t mkey)
+{
+	void *mad = umad_get_mad(umad);
+
+	memset(umad, 0, umad_size() + IB_MAD_SIZE);
+	umad_set_addr(umad, 0xffff, 0, 0, 0);
+	mad_set_field(mad, 0, IB_MAD_METHOD_F, method);
+	mad_set_field(mad, 0, IB_MAD_CLASSVER_F, 1);
+	mad_set_field(mad, 0, IB_MAD_MGMTCLASS_F, IB_SMI_DIRECT_CLASS);
+	mad_set_field(mad, 0, IB_MAD_BASEVER_F, 1);
+	mad_set_field(mad, 0, IB_DRSMP_HOPCNT_F, path_cnt);
+	mad_set_field(mad, 0, IB_DRSMP_HOPPTR_F, 0);
+	mad_set_field64(mad, 0, IB_MAD_TRID_F, trid);
+	mad_set_field(mad, 0, IB_DRSMP_DRDLID_F, 0xffff);
+	mad_set_field(mad, 0, IB_DRSMP_DRSLID_F, 0xffff);
+	mad_set_array(mad, 0, IB_DRSMP_PATH_F, path);
+	mad_set_field(mad, 0, IB_MAD_ATTRID_F, attr_id);
+	mad_set_field(mad, 0, IB_MAD_ATTRMOD_F, attr_mod);
+	mad_set_field64(mad, 0, IB_MAD_MKEY_F, mkey);
+}
+
+static int send_request(int fd, int agent, uint64_t trid, uint8_t * path,
+			size_t path_cnt, uint16_t attr_id, uint32_t attr_mod)
+{
+	uint8_t umad[IB_MAD_SIZE + umad_size()];
+	int ret;
+
+	build_umad_req(umad, path, path_cnt, trid, IB_MAD_METHOD_GET, attr_id,
+		       attr_mod, 0);
+
+	ret = umad_send(fd, agent, umad, IB_MAD_SIZE, timeout, retries);
+	if (ret < 0) {
+		ERROR("umad_send failed: trid 0x%016" PRIx64
+		      ", attr_id %x, attr_mod %x: %s\n",
+		      trid, attr_id, attr_mod, strerror(errno));
+		return -1;
+	}
+
+	VERBOSE1("send %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id,
+		 attr_mod, print_path(path, path_cnt));
+
+	return ret;
+}
+
+static struct request_queue {
+	struct request_queue *next;
+	uint64_t trid;
+	uint16_t attr_id;
+	uint32_t attr_mod;
+	size_t path_cnt;
+	uint8_t path[0];
+} request_queue;
+
+static struct request_queue *request_last = &request_queue;
+
+static unsigned tr_table_size;
+static struct request_queue **tr_table;
+
+static void add_to_tr_table(struct request_queue *q, uint64_t trid)
+{
+	unsigned n = trid >> 16;
+	if (n >= tr_table_size) {
+		unsigned new_size = tr_table_size ? tr_table_size * 2 : 4096;
+		if (n > new_size)
+			new_size = n + 1;
+		tr_table = realloc(tr_table, new_size * sizeof(tr_table[0]));
+		if (!tr_table) {
+			ERROR("cannot realloc request table\n");
+			tr_table_size = 0;
+			return;
+		}
+		memset(tr_table + tr_table_size, 0,
+		       (new_size - tr_table_size) * sizeof(tr_table[0]));
+		tr_table_size = new_size;
+	}
+
+	tr_table[n] = q;
+}
+
+static void clean_from_tr_table(uint64_t trid)
+{
+	unsigned n = (trid >> 16) & 0xffff;
+	if (n >= tr_table_size) {
+		ERROR("invalid request table index %u\n", n);
+		return;
+	}
+	free(tr_table[n]);
+	tr_table[n] = NULL;
+}
+
+static void free_unresponded()
+{
+	struct request_queue *q;
+	unsigned i;
+
+	for (i = 0 ; i < tr_table_size; i++) {
+		if (!(q = tr_table[i]))
+			continue;
+		fprintf(stderr, "Unresponded transaction %016" PRIx64 ": %s "
+			"attr_id %x, attr_mod %x\n", q->trid,
+			print_path(q->path, q->path_cnt), q->attr_id,
+			q->attr_mod);
+		free(q);
+	}
+}
+
+static void run_request_queue(int fd, int agent)
+{
+	struct request_queue *q = request_queue.next;
+
+	while (q) {
+		if (outstanding >= max_outstanding)
+			break;
+		if (send_request(fd, agent, q->trid, q->path, q->path_cnt,
+				 q->attr_id, q->attr_mod) < 0)
+			break;
+		q = q->next;
+		outstanding++;
+		total_mads++;
+	}
+	request_queue.next = q;
+	if (!q)
+		request_last = &request_queue;
+}
+
+static int queue_request(uint64_t trid, uint8_t * path, size_t path_cnt,
+			 uint16_t attr_id, uint32_t attr_mod)
+{
+	struct request_queue *q = malloc(sizeof(*q) + path_cnt + 1);
+	if (!q)
+		return -1;
+	q->next = NULL;
+	q->trid = trid;
+	q->attr_id = attr_id;
+	q->attr_mod = attr_mod;
+	memcpy(q->path, path, path_cnt + 1);
+	q->path_cnt = path_cnt;
+
+	request_last->next = q;
+	request_last = q;
+
+	add_to_tr_table(q, trid);
+
+	return 0;
+}
+
+static int send_query(int fd, int agent, unsigned node_id, uint8_t path[],
+		      size_t path_cnt, uint16_t attr_id, uint32_t attr_mod)
+{
+	uint64_t trid;
+	int ret;
+
+	trid = (trid_cnt++ << 16) | (node_id & 0xffff);
+
+	ret = queue_request(trid, path, path_cnt, attr_id, attr_mod);
+	if (ret < 0) {
+		ERROR("queue failed: trid 0x%016" PRIx64 ", attr_id %x,"
+		      " attr_mod %x\n", trid, attr_id, attr_mod);
+		return -1;
+	}
+
+	VERBOSE1("queue %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id,
+		 attr_mod, print_path(path, path_cnt));
+
+	run_request_queue(fd, agent);
+
+	return ret;
+}
+
+static int recv_response(int fd, int agent, uint8_t * umad, size_t length)
+{
+	int len = length, ret;
+
+	do {
+		ret = umad_recv(fd, umad, &len, timeout);
+	} while (ret >= 0 && ret != agent);
+
+	if (ret < 0 || umad_status(umad)) {
+		ERROR("umad_recv failed: umad status %x: %s\n",
+		      umad_status(umad), strerror(errno));
+		return len > umad_size() ? 1 : -1;
+	}
+
+	return 0;
+}
+
+static int query_node_info(int fd, int agent, unsigned node_id,
+			   uint8_t path[], size_t path_cnt)
+{
+	return send_query(fd, agent, node_id, path, path_cnt,
+			  IB_ATTR_NODE_INFO, 0);
+}
+
+static int query_node_desc(int fd, int agent, unsigned node_id,
+			   uint8_t path[], size_t path_cnt)
+{
+	return send_query(fd, agent, node_id, path, path_cnt,
+			  IB_ATTR_NODE_DESC, 0);
+}
+
+static int query_switch_info(int fd, int agent, unsigned node_id,
+			     uint8_t path[], size_t path_cnt)
+{
+	return send_query(fd, agent, node_id, path, path_cnt,
+			  IB_ATTR_SWITCH_INFO, 0);
+}
+
+static int query_port_info(int fd, int agent, unsigned node_id,
+			   uint8_t path[], size_t path_cnt, unsigned port_num)
+{
+	return send_query(fd, agent, node_id, path, path_cnt,
+			  IB_ATTR_PORT_INFO, port_num);
+}
+
+static int add_node(uint8_t * node_info, uint8_t path[], size_t path_size)
+{
+	struct node *node;
+	unsigned i, num_ports = mad_get_field(node_info, 0, IB_NODE_NPORTS_F);
+
+	node = malloc(sizeof(*node) + (num_ports + 1) * sizeof(node->ports[0]));
+	if (!node)
+		return -1;
+	memset(node, 0,
+	       sizeof(*node) + (num_ports + 1) * sizeof(node->ports[0]));
+
+	node->num_ports = num_ports;
+	node->guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F);
+	node->is_switch = ((mad_get_field(node_info, 0, IB_NODE_TYPE_F)) ==
+			   IB_NODE_SWITCH);
+	memcpy(node->path, path, path_size + 1);
+	node->path_size = path_size;
+	memcpy(node->node_info, node_info, sizeof(node->node_info));
+	for (i = 0; i <= num_ports; i++)
+		node->ports[i].node = node;
+
+	node_array[node_count] = node;
+
+	return node_count++;
+}
+
+static int find_node(uint8_t * node_info)
+{
+	uint64_t guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F);
+	unsigned i;
+
+	for (i = 0; i < node_count; i++)
+		if (node_array[i]->guid == guid)
+			return i;
+	return -1;
+}
+
+static int process_port_info(void *umad, unsigned node_id, int fd, int agent,
+			     uint8_t path[], size_t path_cnt)
+{
+	struct node *node = node_array[node_id];
+	struct port *port;
+	uint8_t *port_info = umad + umad_size() + IB_SMP_DATA_OFFS;
+	unsigned port_num, local_port;
+
+	dbg_dump_portinfo(port_info);
+
+	port_num = mad_get_field(umad_get_mad(umad), 0, IB_MAD_ATTRMOD_F);
+	local_port = mad_get_field(port_info, 0, IB_PORT_LOCAL_PORT_F);
+
+	port = &node->ports[port_num];
+	memcpy(port->port_info, port_info, sizeof(port->port_info));
+
+	if (port_num &&
+	    mad_get_field(port_info, 0, IB_PORT_PHYS_STATE_F) == 5 &&
+	    ((node->is_switch && port_num != local_port) ||
+	     (node_id == 0 && port_num == local_port)) &&
+	    path_cnt++ < MAX_HOPS) {
+		if (path_cnt > max_hops)
+			max_hops = path_cnt;
+		path[path_cnt] = port_num;
+		return query_node_info(fd, agent, node_id, path, path_cnt);
+	}
+
+	return 0;
+}
+
+static int process_switch_info(unsigned node_id, uint8_t * switch_info)
+{
+	struct node *node = node_array[node_id];
+
+	dbg_dump_switchinfo(switch_info);
+	memcpy(node->switch_info, switch_info, sizeof(node->switch_info));
+
+	return 0;
+}
+
+static int process_node_desc(unsigned node_id, uint8_t * node_desc)
+{
+	struct node *node = node_array[node_id];
+
+	dbg_dump_nodedesc(node_desc);
+	memcpy(node->node_desc, node_desc, sizeof(node->node_desc));
+
+	return 0;
+}
+
+static void connect_ports(unsigned node1_id, unsigned port1_num,
+			  unsigned node2_id, unsigned port2_num)
+{
+	struct port *port1 = &node_array[node1_id]->ports[port1_num];
+	struct port *port2 = &node_array[node2_id]->ports[port2_num];
+	VERBOSE1("connecting %u:%u <--> %u:%u\n",
+		 node1_id, port1_num, node2_id, port2_num);
+	port1->remote = port2;
+	port2->remote = port1;
+}
+
+static int process_node(void *umad, unsigned remote_id, int fd, int agent,
+			uint8_t path[], size_t path_cnt)
+{
+	struct node *node;
+	uint8_t *node_info = umad_get_mad(umad) + IB_SMP_DATA_OFFS;
+	unsigned port_num = mad_get_field(node_info, 0, IB_NODE_LOCAL_PORT_F);
+	unsigned node_is_new = 0;
+	int i, id;
+
+	dbg_dump_nodeinfo(node_info);
+
+	if ((id = find_node(node_info)) < 0) {
+		id = add_node(node_info, path, path_cnt);
+		if (id < 0)
+			return -1;
+		node_is_new = 1;
+	}
+
+	node = node_array[id];
+
+	VERBOSE("%-5s %-6s with guid 0x%" PRIx64 " discovered at %s\n",
+		node_is_new ? "new" : "known",
+		node->is_switch ? "Switch" : "Ca", node->guid,
+		print_path(path, path_cnt));
+
+	node->ports[port_num].guid =
+	    mad_get_field64(node_info, 0, IB_NODE_PORT_GUID_F);
+
+	if (id)			/* skip connect for very first node */
+		connect_ports(id, port_num, remote_id, path[path_cnt]);
+
+	if (!node_is_new)
+		return 0;
+
+	query_node_desc(fd, agent, id, path, path_cnt);
+
+	if (node->is_switch)
+		query_switch_info(fd, agent, id, path, path_cnt);
+
+	for (i = !node->is_switch; i <= node->num_ports; i++)
+		query_port_info(fd, agent, id, path, path_cnt, i);
+
+	return 0;
+}
+
+static int recv_smp_resp(int fd, int agent, uint8_t * umad, uint8_t path[])
+{
+	void *mad;
+	uint64_t trid;
+	uint8_t method;
+	uint16_t status;
+	uint16_t attr_id;
+	uint32_t attr_mod;
+	size_t path_cnt;
+	unsigned node_id;
+	int ret;
+
+	ret = recv_response(fd, agent, umad, IB_MAD_SIZE);
+
+	mad = umad_get_mad(umad);
+	status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F);
+	method = mad_get_field(mad, 0, IB_MAD_METHOD_F);
+	trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
+	attr_id = mad_get_field(mad, 0, IB_MAD_ATTRID_F);
+	attr_mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F);
+	path_cnt = mad_get_field(mad, 0, IB_DRSMP_HOPCNT_F);
+	mad_get_array(mad, 0, IB_DRSMP_PATH_F, path);
+
+	if (method != IB_MAD_METHOD_GET)
+		return 0;
+
+	outstanding--;
+	run_request_queue(fd, agent);
+
+	if (ret < 0)
+		return ret;
+	else if (ret || status) {
+		ERROR("error response 0x%016" PRIx64 ": attr_id %x"
+		      ", attr_mod %x from %s with status %x\n", trid,
+		      attr_id, attr_mod, print_path(path, path_cnt), status);
+		return -1;
+	}
+
+	clean_from_tr_table(trid);
+
+	node_id = trid & 0xffff;
+
+	VERBOSE1("recv %016" PRIx64 ": attr %x, mod %x from %s\n", trid,
+		 attr_id, attr_mod, print_path(path, path_cnt));
+
+	switch (attr_id) {
+	case IB_ATTR_NODE_INFO:
+		process_node(umad, node_id, fd, agent, path, path_cnt);
+		break;
+	case IB_ATTR_NODE_DESC:
+		process_node_desc(node_id, mad + IB_SMP_DATA_OFFS);
+		break;
+	case IB_ATTR_SWITCH_INFO:
+		process_switch_info(node_id, mad + IB_SMP_DATA_OFFS);
+		break;
+	case IB_ATTR_PORT_INFO:
+		process_port_info(umad, node_id, fd, agent, path, path_cnt);
+		break;
+	default:
+		VERBOSE("unsolicited response 0x%016" PRIx64 ": attr_id %x"
+			", attr_mod %x\n", trid, attr_id, attr_mod);
+		return 0;
+	}
+
+	return ret;
+}
+
+static int discover(int fd, int agent)
+{
+	uint8_t umad[IB_MAD_SIZE + umad_size()];
+	uint8_t path[64] = { 0 };
+	int ret;
+
+	ret = query_node_info(fd, agent, 0, path, 0);
+	if (ret < 0)
+		return ret;
+
+	while (outstanding)
+		if (recv_smp_resp(fd, agent, umad, path))
+			ret = 1;
+
+	free_unresponded();
+
+	return ret;
+}
+
+static int umad_discover(char *card_name, unsigned int port_num)
+{
+	int fd, agent, ret;
+
+	ret = umad_init();
+	if (ret) {
+		ERROR("cannot init umad\n");
+		return -1;
+	}
+
+	fd = umad_open_port(card_name, port_num);
+	if (fd < 0) {
+		ERROR("cannot open umad port %s:%u: %s\n",
+		      card_name ? card_name : "NULL", port_num,
+		      strerror(errno));
+		return -1;
+	}
+
+	agent = umad_register(fd, IB_SMI_DIRECT_CLASS, 1, 0, NULL);
+	if (agent < 0) {
+		ERROR("cannot register SMI DR class for umad port %s:%u: %s\n",
+		      card_name ? card_name : "NULL", port_num,
+		      strerror(errno));
+		return -1;
+	}
+
+	ret = discover(fd, agent);
+	if (ret)
+		fprintf(stderr, "\nThere are problems during discovery.\n");
+
+	umad_unregister(fd, agent);
+	umad_close_port(fd);
+
+	umad_done();
+
+	return ret;
+}
+
+static void print_subnet()
+{
+	struct node *node;
+	struct port *local, *remote;
+	unsigned i, j;
+
+	printf("\n# The subnet discovered using %u mads, reaching %d hops\n\n",
+	       total_mads, max_hops);
+
+	for (i = 0; i < node_count; i++) {
+		node = node_array[i];
+		printf("%s %u \"%s-%016" PRIx64 "\" \t# %s %s\n",
+		       node->is_switch ? "Switch" : "Ca", node->num_ports,
+		       node->is_switch ? "S" : "H", node->guid,
+		       print_path(node->path, node->path_size), node->node_desc);
+		for (j = 1; j <= node->num_ports; j++) {
+			local = &node->ports[j];
+			remote = local->remote;
+			if (!remote)
+				continue;
+			printf("[%u] \t\"%s-%016" PRIx64 "\"[%lu] \t# %s\n", j,
+			       remote->node->is_switch ? "S" : "H",
+			       remote->node->guid, remote - remote->node->ports,
+			       remote->node->node_desc);
+		}
+		printf("\n");
+	}
+}
+
+int main(int argc, char **argv)
+{
+	const struct option long_opts[] = {
+		{"Card", 1, 0, 'C'},
+		{"Port", 1, 0, 'P'},
+		{"maxsmps", 1, 0, 'n'},
+		{"timeout", 1, 0, 't'},
+		{"retries", 1, 0, 'r'},
+		{"verbose", 0, 0, 'v'},
+		{"help", 0, 0, 'h'},
+		{}
+	};
+	char *card_name = NULL;
+	unsigned int port_num = 0;
+	int ch, ret;
+
+	while (1) {
+		ch = getopt_long(argc, argv, "C:P:n:t:r:vh", long_opts, NULL);
+		if (ch == -1)
+			break;
+		switch (ch) {
+		case 'C':
+			card_name = optarg;
+			break;
+		case 'P':
+			port_num = strtoul(optarg, NULL, 0);
+			break;
+		case 'n':
+			max_outstanding = strtoul(optarg, NULL, 0);
+			if (!max_outstanding)
+				max_outstanding = -1;
+			break;
+		case 't':
+			timeout = strtoul(optarg, NULL, 0);
+			break;
+		case 'r':
+			retries = strtoul(optarg, NULL, 0);
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'h':
+		default:
+			printf("usage: %s [-C card_name] [-P port_num]"
+			       " [-n maxsmps] [-t timeout] [-r retries]"
+			       " [-v[v]]\n", argv[0]);
+			exit(2);
+			break;
+		}
+	}
+
+	ret = umad_discover(card_name, port_num);
+
+	print_subnet();
+
+	return ret;
+}
diff --git a/umad2sim/sim_client.c b/umad2sim/sim_client.c
index 30430b7..cec72d9 100644
--- a/umad2sim/sim_client.c
+++ b/umad2sim/sim_client.c
@@ -45,7 +45,6 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
-#include <infiniband/common.h>
 #include <infiniband/mad.h>
 
 #include <ibsim.h>
@@ -60,6 +59,7 @@
 #endif
 
 static unsigned int remote_mode = 0;
+static char* socket_basename;
 
 static int sim_ctl(struct sim_client *sc, int type, void *data, int len)
 {
@@ -143,11 +143,10 @@ static size_t make_name(union name_t *name, char *host, unsigned port,
 
 static char *get_name(union name_t *name)
 {
-	if (remote_mode) {
+	if (remote_mode)
 		return inet_ntoa(name->name_i.sin_addr);
-	} else {
+	else
 		return name->name_u.sun_path + 1;
-	}
 }
 
 static int sim_attach(int fd, union name_t *name, size_t size)
@@ -159,8 +158,7 @@ static int sim_attach(int fd, union name_t *name, size_t size)
 		DEBUG("attempt to connect to %s (attempt %d)",
 		      get_name(name), retries);
 
-		if ((r =
-		     connect(fd, (struct sockaddr *)name, size)) >= 0)
+		if ((r = connect(fd, (struct sockaddr *)name, size)) >= 0)
 			break;
 
 		if (r < 0 && errno == ECONNREFUSED) {
@@ -175,12 +173,16 @@ static int sim_attach(int fd, union name_t *name, size_t size)
 	return 0;
 }
 
-static int sim_connect(struct sim_client *sc, int id, int qp, char *nodeid)
+static int sim_connect(struct sim_client *sc, int id, int qp, char *nodeid,
+		       char *issm)
 {
 	struct sim_client_info info = { 0 };
 
 	info.id = id;
-	info.issm = 0;
+	if (issm)
+		info.issm = 1;
+	else
+		info.issm = 0;
 	info.qp = qp;
 
 	if (nodeid)
@@ -202,7 +204,7 @@ static int sim_disconnect(struct sim_client *sc)
 	return sim_ctl(sc, SIM_CTL_DISCONNECT, 0, 0);
 }
 
-static int sim_init(struct sim_client *sc, int qp, char *nodeid)
+static int sim_init(struct sim_client *sc, char *nodeid, char *issm)
 {
 	union name_t name;
 	socklen_t size;
@@ -214,12 +216,15 @@ static int sim_init(struct sim_client *sc, int qp, char *nodeid)
 
 	connect_port = getenv("IBSIM_SERVER_PORT");
 	connect_host = getenv("IBSIM_SERVER_NAME");
+	socket_basename = getenv("IBSIM_SOCKNAME");
+
+	if(!socket_basename)
+		socket_basename = SIM_BASENAME;
 
 	if (connect_host && *connect_host)
 		remote_mode = 1;
 
-	DEBUG("init client pid=%d, qp=%d nodeid=%s",
-	      pid, qp, nodeid ? nodeid : "none");
+	DEBUG("init client pid=%d, nodeid=%s", pid, nodeid ? nodeid : "none");
 
 	if ((fd = socket(remote_mode ? PF_INET : PF_LOCAL, SOCK_DGRAM, 0)) < 0)
 		IBPANIC("can't get socket (fd)");
@@ -227,7 +232,7 @@ static int sim_init(struct sim_client *sc, int qp, char *nodeid)
 	if ((ctlfd = socket(remote_mode ? PF_INET : PF_LOCAL, SOCK_DGRAM, 0)) < 0)
 		IBPANIC("can't get socket (ctlfd)");
 
-	size = make_name(&name, NULL, 0, "%s:ctl%d", SIM_BASENAME, pid);
+	size = make_name(&name, NULL, 0, "%s:ctl%d", socket_basename, pid);
 
 	if (bind(ctlfd, (struct sockaddr *)&name, size) < 0)
 		IBPANIC("can't bind ctl socket");
@@ -236,13 +241,13 @@ static int sim_init(struct sim_client *sc, int qp, char *nodeid)
 	      pid, ctlfd, get_name(&name));
 
 	port = connect_port ? atoi(connect_port) : IBSIM_DEFAULT_SERVER_PORT;
-	size = make_name(&name, connect_host, port, "%s:ctl", SIM_BASENAME);
+	size = make_name(&name, connect_host, port, "%s:ctl", socket_basename);
 
 	sim_attach(ctlfd, &name, size);
 
 	sc->fd_ctl = ctlfd;
 
-	size = make_name(&name, NULL, 0, "%s:in%d", SIM_BASENAME, pid);
+	size = make_name(&name, NULL, 0, "%s:in%d", socket_basename, pid);
 
 	if (bind(fd, (struct sockaddr *)&name, size) < 0)
 		IBPANIC("can't bind input socket");
@@ -253,13 +258,13 @@ static int sim_init(struct sim_client *sc, int qp, char *nodeid)
 		IBPANIC("can't read data from bound socket");
 	port = ntohs(name.name_i.sin_port);
 
-	sc->clientid = sim_connect(sc, remote_mode ? port : pid, qp, nodeid);
+	sc->clientid = sim_connect(sc, remote_mode ? port : pid, 0, nodeid, issm);
 	if (sc->clientid < 0)
 		IBPANIC("connect failed");
 
 	port = connect_port ? atoi(connect_port) : IBSIM_DEFAULT_SERVER_PORT;
 	size = make_name(&name, connect_host, port + sc->clientid + 1,
-			 "%s:out%d", SIM_BASENAME, sc->clientid);
+			 "%s:out%d", socket_basename, sc->clientid);
 
 	sim_attach(fd, &name, size);
 
@@ -280,31 +285,35 @@ int sim_client_set_sm(struct sim_client *sc, unsigned issm)
 	return sim_ctl(sc, SIM_CTL_SET_ISSM, &issm, sizeof(int));
 }
 
-int sim_client_init(struct sim_client *sc, char *nodeid)
+int sim_client_init(struct sim_client *sc)
 {
-	if (!nodeid)
-		nodeid = getenv("SIM_HOST");
-	if (sim_init(sc, 0, nodeid) < 0)
+	char *nodeid;
+	char *issm;
+
+	nodeid = getenv("SIM_HOST");
+	issm = getenv("SIM_SET_ISSM");
+	if (sim_init(sc, nodeid, issm) < 0)
 		return -1;
-	if (sim_ctl(sc, SIM_CTL_GET_VENDOR, &sc->vendor, sizeof(sc->vendor)) <
-	    0)
+	if (sim_ctl(sc, SIM_CTL_GET_VENDOR, &sc->vendor,
+		    sizeof(sc->vendor)) < 0)
 		goto _exit;
 	if (sim_ctl(sc, SIM_CTL_GET_NODEINFO, sc->nodeinfo,
 		    sizeof(sc->nodeinfo)) < 0)
 		goto _exit;
-	sc->portinfo[0] = 0;
+
+	sc->portinfo[0] = 0;	// portno requested
 	if (sim_ctl(sc, SIM_CTL_GET_PORTINFO, sc->portinfo,
 		    sizeof(sc->portinfo)) < 0)
 		goto _exit;
 	if (sim_ctl(sc, SIM_CTL_GET_PKEYS, sc->pkeys, sizeof(sc->pkeys)) < 0)
 		goto _exit;
-	if (getenv("SIM_SET_ISSM"))
+	if (issm)
 		sim_client_set_sm(sc, 1);
 	return 0;
   _exit:
 	sim_disconnect(sc);
 	sc->fd_ctl = sc->fd_pktin = sc->fd_pktout = -1;
-	return 0;
+	return -1;
 }
 
 void sim_client_exit(struct sim_client *sc)
diff --git a/umad2sim/sim_client.h b/umad2sim/sim_client.h
index 605b305..80ed442 100644
--- a/umad2sim/sim_client.h
+++ b/umad2sim/sim_client.h
@@ -47,7 +47,7 @@ struct sim_client {
 };
 
 extern int sim_client_set_sm(struct sim_client *sc, unsigned issm);
-extern int sim_client_init(struct sim_client *sc, char *nodeid);
+extern int sim_client_init(struct sim_client *sc);
 extern void sim_client_exit(struct sim_client *sc);
 
 #endif				/* _SIM_CLIENT_H_ */
diff --git a/umad2sim/umad2sim.c b/umad2sim/umad2sim.c
index f896540..55440ec 100644
--- a/umad2sim/umad2sim.c
+++ b/umad2sim/umad2sim.c
@@ -50,11 +50,9 @@
 #include <dlfcn.h>
 #include <netinet/in.h>
 
-#include <infiniband/common.h>
 #include <infiniband/umad.h>
 #include <infiniband/mad.h>
 
-#include <ibsim.h>
 #include <sim_client.h>
 
 #ifdef UMAD2SIM_NOISY_DEBUG
@@ -96,9 +94,16 @@ static ssize_t(*real_write) (int fd, const void *buf, size_t count);
 static int (*real_poll) (struct pollfd * pfds, nfds_t nfds, int timeout);
 static int (*real_ioctl) (int d, int request, ...);
 static DIR *(*real_opendir) (const char *dir);
+#if __GLIBC_PREREQ(2,10)
+static int (*real_scandir) (const char *dir, struct dirent *** namelist,
+			    int (*filter) (const struct dirent *),
+			    int (*compar) (const struct dirent **,
+					   const struct dirent **));
+#else
 static int (*real_scandir) (const char *dir, struct dirent *** namelist,
 			    int (*filter) (const struct dirent *),
 			    int (*compar) (const void *, const void *));
+#endif
 
 static char sysfs_infiniband_dir[] = SYS_INFINIBAND;
 static char sysfs_infiniband_mad_dir[] = IB_UMAD_ABI_DIR;
@@ -443,8 +448,8 @@ static ssize_t umad2sim_write(struct umad2sim_dev *dev,
 	{ static int err_count;
 	if (++err_count == 15)
 		return -1;
-	if (mad_get_field(umad_get_mad(umad), 0, IB_MAD_METHOD_F) == 0x7) {
-		printf("Drop trap repress...\n");
+	if (mad_get_field(umad_get_mad(umad), 0, IB_MAD_METHOD_F) == IB_MAD_METHOD_TRAP_REPRESS) {
+		printf("Dropping trap repress...\n");
 		return  -1;
 	}
 	}
@@ -563,7 +568,7 @@ static struct umad2sim_dev *umad2sim_dev_create(unsigned num, const char *name)
 	dev->num = num;
 	strncpy(dev->name, name, sizeof(dev->name) - 1);
 
-	if (sim_client_init(&dev->sim_client, NULL) < 0)
+	if (sim_client_init(&dev->sim_client) < 0)
 		goto _error;
 
 	dev->port = mad_get_field(&dev->sim_client.portinfo, 0,
@@ -696,9 +701,15 @@ DIR *opendir(const char *path)
 	return real_opendir(path);
 }
 
+#if __GLIBC_PREREQ(2,10)
+int scandir(const char *path, struct dirent ***namelist,
+	    int (*filter) (const struct dirent *),
+	    int (*compar) (const struct dirent **, const struct dirent **))
+#else
 int scandir(const char *path, struct dirent ***namelist,
 	    int (*filter) (const struct dirent *),
 	    int (*compar) (const void *, const void *))
+#endif
 {
 	char new_path[4096];
 
@@ -815,7 +826,7 @@ int ioctl(int fd, unsigned long request, ...)
 		return real_ioctl(fd, request, arg);
 }
 
-int poll(struct pollfd *pfds, unsigned long nfds, int timeout)
+int poll(struct pollfd *pfds, nfds_t nfds, int timeout)
 {
 	int saved_fds[nfds];
 	unsigned i;
@@ -828,7 +839,8 @@ int poll(struct pollfd *pfds, unsigned long nfds, int timeout)
 			struct umad2sim_dev *dev = devices[pfds[i].fd - 1024];
 			saved_fds[i] = pfds[i].fd;
 			pfds[i].fd = dev->sim_client.fd_pktin;
-		}
+		} else
+			saved_fds[i] = 0;
 	}
 
 	ret = real_poll(pfds, nfds, timeout);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ofed/ibsim.git



More information about the Pkg-ofed-commits mailing list