[Pkg-ofed-commits] [ibsim] 01/05: Imported Upstream version 0.5

Ana Beatriz Guerrero López ana at moszumanska.debian.org
Tue Jul 1 07:17:05 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 8655f33a7e068539de8bb6991c968c7685f0ba1c
Author: Ana Guerrero López <ana at ekaia.org>
Date:   Mon Jun 30 22:08:21 2014 +0200

    Imported Upstream version 0.5
---
 COPYING                            |  340 +++++++++
 Makefile                           |    7 +
 README                             |  103 +++
 TODO                               |    8 +
 defs.mk                            |   67 ++
 dist.sh                            |   23 +
 ibsim.spec                         |   41 ++
 ibsim.spec.in                      |   41 ++
 ibsim/Makefile                     |    6 +
 ibsim/ibsim.c                      |  816 +++++++++++++++++++++
 ibsim/sim.h                        |  296 ++++++++
 ibsim/sim_cmd.c                    |  913 ++++++++++++++++++++++++
 ibsim/sim_mad.c                    | 1343 +++++++++++++++++++++++++++++++++++
 ibsim/sim_net.c                    | 1362 ++++++++++++++++++++++++++++++++++++
 include/ibsim.h                    |  111 +++
 net-examples/examples.README       |   10 +
 net-examples/net                   |   39 ++
 net-examples/net.1                 |   29 +
 net-examples/net.2sw2path          |   35 +
 net-examples/net.2sw2path4hca      |   43 ++
 net-examples/net.2sw2path4hca2port |   39 ++
 scripts/run_opensm.sh              |   50 ++
 tests/Makefile                     |    7 +
 tests/get_all_ca_port_guids.sh     |    3 +
 tests/mcast_storm.c                |  746 ++++++++++++++++++++
 umad2sim/Makefile                  |   11 +
 umad2sim/sim_client.c              |  314 +++++++++
 umad2sim/sim_client.h              |   53 ++
 umad2sim/umad2sim.c                |  841 ++++++++++++++++++++++
 29 files changed, 7697 insertions(+)

diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..7a8e8ab
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program 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.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..665e186
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,7 @@
+subdirs:= ibsim umad2sim
+
+all clean dep install:
+	$(foreach dir, $(subdirs), make -C $(dir) $@ && ) echo "Done."
+
+dist:
+	./dist.sh RELEASE=$(RELEASE)
diff --git a/README b/README
new file mode 100644
index 0000000..8606da5
--- /dev/null
+++ b/README
@@ -0,0 +1,103 @@
+Voltaire Infiniband Fabric Simulator - ibsim
+============================================
+
+Basic Description and main features.
+-----------------------------------
+
+ibsim emulates the fabric behavior by using MAD communication with the
+SM/SA and the PerfMgr. This simple tool is ideally suitable for various
+research, development, debug and testing tasks where IB subnet
+management is involved.
+
+For generation and reception of this MAD traffic it replaces the
+/dev/umadX file descriptor interface between libibumad and ib_umad
+kernel module by using preloaded libumad2sim.so shared library (umad2sim
+wrapper - part of ibsim distribution). This conveys MADs to/from
+SM/SA/PerfMgr to ibsim.
+
+
+   OpenSM      Diags utils    App (using libibumad)
+     |             |           |
+     V             V           |
+ libosmvendor   libibmad       |
+     |             |           |
+     V             V           V
+               libibumad
+                   |
+                   V
+                     --> LD_PRELOAD=libumad2sim.so <--> ibsim
+    ---------------------------------
+        ib stack (ib_umad.ko)
+
+
+Any libibumad based application may work with ibsim. Kernel support
+and userspace application recompilation are not required.
+
+ibsim works locally via unix sockets or remotely via inet sockets.
+
+For fabric topology description, ibsim uses a text file in the format
+compatible with ibnetdiscover command output (for examples see
+net-examples/) and it can be generated using a real cluster snapshot.
+
+ibsim has a simple console command interface and can simulate random
+packets drops and link up/down events. It is possible to run batch
+commands from file via pipe or named fifo.
+
+
+Building and using ibsim
+------------------------
+
+1. cd to unpacked simulator directory.
+
+2. make ibsim and umad2sim wrapper:
+
+    $ make
+
+   Notes:
+   - by default this will build ibsim against installed in /usr/local
+     version of libib* libraries. If you like to build it against
+     development tree use IB_DEV_DIR variable (or export it into
+     environment):
+
+       $ make IB_DEV_DIR=${HOME}/src/management
+
+   - 'make dep', 'make clean' and 'make install' are available now
+
+3. run ibsim:
+
+    $ ./ibsim/ibsim -s <netfile>
+
+   , where <netfile> is network definition file, it is compatible with
+   output of ibnetdiscover command (+some more options are available as
+   well). Some examples can be found under 'net-examples' directory.
+
+   Notes:
+   - '-s' option is in order to start the IB network immediately, the
+     ibsim console may be used instead.
+   - '-h' option shows ibsim command line usage and 'help' and '?'
+     ibsim console commands show brief console help.
+
+4. run libibumad based application with preloaded umad2sim wrapper:
+
+    $ LD_PRELOAD=./umad2sim/libumad2sim.so ibnetdiscover
+
+   , or
+
+    $ LD_PRELOAD=./umad2sim/libumad2sim.so opensm -f -
+
+   Notes:
+   - in order to run OpenSM as non-privileged user you may need to
+     export OSM_CACHE_DIR variable and to use '-f' option in order to
+     specify writable path to OpenSM log file.
+   - Point of attachment is indicated by SIM_HOST environment variable.
+     If not specified, first entry in topology file is used. For OpenSM,
+     if -g option is used, it must be the same as this.
+
+5. Enjoy and comment.
+
+
+Feedback.
+---------
+
+Please send your feedback and patches to the maintainer:
+Sasha Khapyorsky <sashak at voltaire.com>
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..616ed71
--- /dev/null
+++ b/TODO
@@ -0,0 +1,8 @@
+* transaction management
+  - multiple transactions per client
+  - hops simulation
+  - RMPP
+* more attributes handled
+* MKey support
+* cleaner (less) debug/warning messages
+* support for combined routing
diff --git a/defs.mk b/defs.mk
new file mode 100644
index 0000000..e3b9cc4
--- /dev/null
+++ b/defs.mk
@@ -0,0 +1,67 @@
+
+old_ofed:=/usr/local/ofed
+
+prefix:= $(strip $(if $(prefix),$(prefix),\
+	$(if $(wildcard $(old_ofed)/lib/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)))))
+
+libpath:= $(strip $(if $(libpath),$(libpath),\
+	$(if $(wildcard $(prefix)/lib/libibumad.so),\
+		$(prefix)/lib,$(prefix)/lib)))
+binpath:= $(if $(binpath),$(binpath),$(prefix)/bin)
+
+#IB_DEV_DIR:=$(HOME)/src/p
+ifdef IB_DEV_DIR
+ INCS:= $(foreach l, mad umad common, -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)
+else
+ INCS:= -I$(dir $(libpath))/include
+ LIBS:= -L$(libpath) -libmad -libumad -libcommon
+endif
+
+CFLAGS += -Wall -g -fpic -I. -I../include $(INCS)
+LDFLAGS+= -fpic
+
+srcs?=$(wildcard *.c)
+objs?=$(srcs:.c=.o)
+
+.PHONY: all clean dep install
+
+all:
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+%.so:
+	$(CC) -shared $(LDFLAGS) -o $@ $^ $(LIBS)
+
+$(progs):
+	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+dep:
+	$(CC) -M $(CFLAGS) $(srcs) > .depend
+-include .depend
+
+clean:
+	$(RM) $(objs) $(libs) $(progs)
+	$(RM) .build_profile
+	$(RM) *.o *.a *.so *~
+
+install: all
+	install -d $(DESTDIR)$(binpath)
+	install -d $(DESTDIR)$(libpath)/umad2sim
+	$(foreach p, $(progs), install $(p) $(DESTDIR)$(binpath))
+	$(foreach l, $(libs), install $(l) $(DESTDIR)$(libpath)/umad2sim)
+
+$(objs): .build_profile
+.build_profile::
+	@echo CFLAGS=$(CFLAGS) > .build_profile.new
+	@if ( test -f .build_profile \
+	   && diff .build_profile .build_profile.new > /dev/null ) ; then \
+		rm .build_profile.new ; \
+	else mv .build_profile.new .build_profile ; fi
diff --git a/dist.sh b/dist.sh
new file mode 100755
index 0000000..1ec554c
--- /dev/null
+++ b/dist.sh
@@ -0,0 +1,23 @@
+#!/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
new file mode 100644
index 0000000..72a5d96
--- /dev/null
+++ b/ibsim.spec
@@ -0,0 +1,41 @@
+
+%define RELEASE  1.ofed1.4
+%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE}
+
+Summary: InfiniBand fabric simulator for management
+Name: ibsim
+Version: 0.5
+Release: 1.ofed1.4
+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
+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.spec.in b/ibsim.spec.in
new file mode 100644
index 0000000..6c848af
--- /dev/null
+++ b/ibsim.spec.in
@@ -0,0 +1,41 @@
+
+%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/Makefile b/ibsim/Makefile
new file mode 100644
index 0000000..5d1ac62
--- /dev/null
+++ b/ibsim/Makefile
@@ -0,0 +1,6 @@
+progs:=ibsim
+
+-include ../defs.mk
+
+all: $(progs)
+ibsim: $(objs)
diff --git a/ibsim/ibsim.c b/ibsim/ibsim.c
new file mode 100644
index 0000000..e399482
--- /dev/null
+++ b/ibsim/ibsim.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <inttypes.h>
+
+#include <ibsim.h>
+#include "sim.h"
+
+#define IBSIM_VERSION "0.5"
+
+#undef DEBUG
+#define PDEBUG	if (parsedebug) IBWARN
+#define DEBUG	if (simverb > 1 || ibdebug) IBWARN
+#define VERB	if (simverb || ibdebug) IBWARN
+
+extern int maxnetnodes;
+extern int maxnetswitches;
+extern int maxnetports;
+extern int maxlinearcap;
+extern int maxmcastcap;
+extern int maxnetaliases;
+extern int ignoreduplicate;
+
+int ibdebug;
+int parsedebug;
+int simverb;
+
+static Client clients[IBSIM_MAX_CLIENTS];
+static int simctl = -1;
+static int maxfd;
+static FILE *simout;
+static int listen_to_port = IBSIM_DEFAULT_SERVER_PORT;
+static int remote_mode = 0;
+
+static size_t make_name(union name_t *name, uint32_t addr, unsigned short port,
+			const char *fmt, ...)
+{
+	size_t size;
+	memset(name, 0, sizeof(*name));
+	if (remote_mode) {
+		struct sockaddr_in *name_i = &name->name_i;
+	        name_i->sin_family = AF_INET;
+		name_i->sin_addr.s_addr = addr ? addr : htonl(INADDR_ANY);
+	        name_i->sin_port = htons(port);
+		size = sizeof(*name_i);
+	} else {
+		va_list args;
+		struct sockaddr_un *name_u = &name->name_u;
+		size = sizeof(*name_u) -
+				((void *)name_u->sun_path + 1 - (void*)name_u);
+		name_u->sun_family = AF_UNIX;
+		name_u->sun_path[0] = 0;	// abstract name space
+		va_start(args, fmt);
+		size = vsnprintf(name_u->sun_path + 1, size, fmt, args);
+		va_end(args);
+		size += 1 + ((void *)name_u->sun_path + 1 - (void*)name_u);
+	}
+	return size;
+}
+
+static char *get_name(union name_t *name)
+{
+	if (remote_mode) {
+		return inet_ntoa(name->name_i.sin_addr);
+	} else {
+		return name->name_u.sun_path + 1;
+	}
+}
+
+/**
+ * initialize the in/out connections
+ *
+ * @param basename base name for abstract namespace
+ *
+ * @return unix status
+ */
+static int sim_init_conn(char *basename)
+{
+	union name_t name;
+	size_t size;
+	int fd, i;
+
+	DEBUG("initializing network connections (basename \"%s\")", basename);
+
+	// create ctl channel
+	fd = simctl = socket(remote_mode ? PF_INET : PF_LOCAL, SOCK_DGRAM, 0);
+	if (fd < 0)
+		IBPANIC("can't create socket for ctl");
+	if (maxfd < fd)
+		maxfd = fd;
+
+	size = make_name(&name, 0, listen_to_port, "%s:ctl", basename);
+
+	if (bind(fd, (struct sockaddr *)&name, size) < 0)
+		IBPANIC("can't bind socket %d to name %s",
+			fd, get_name(&name));
+
+	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+		IBPANIC("can't set non blocking flags for ctl");
+
+	for (i = 0; i < IBSIM_MAX_CLIENTS; i++) {
+		fd = socket(remote_mode ? PF_INET : PF_LOCAL, SOCK_DGRAM, 0);
+		if (fd < 0)
+			IBPANIC("can't create socket for conn %d", i);
+		if (maxfd < fd)
+			maxfd = fd;
+
+		size = make_name(&name, 0, listen_to_port + i + 1,
+				 "%s:out%d", basename, i);
+		if (bind(fd, (struct sockaddr *)&name, size) < 0)
+			IBPANIC("can't bind socket %d to name %s",
+				fd, get_name(&name));
+
+		if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+			IBPANIC("can't set non blocking flags for "
+			        "client conn %d", i);
+
+		DEBUG("opening net connection fd %d %s", fd, get_name(&name));
+
+		clients[i].fd = fd;
+	}
+	return 0;
+}
+
+static int sm_exists(Node * node)
+{
+	Client *cl, *e;
+
+	for (cl = clients, e = cl + IBSIM_MAX_CLIENTS; cl < e; cl++) {
+		if (!cl->pid)
+			continue;
+		if (cl->port->node != node)
+			continue;
+		if (cl->issm)
+			return 1;
+	}
+	return 0;
+}
+
+static int sim_ctl_new_client(Client * cl, struct sim_ctl * ctl, union name_t *from)
+{
+	union name_t name;
+	size_t size;
+	Node *node;
+	struct sim_client_info *scl = (void *)ctl->data;
+	int id = scl->id;
+	int i;
+
+	DEBUG("connecting client pid %d", id);
+
+	// allocated free client
+	for (i = 0; i < IBSIM_MAX_CLIENTS; i++) {
+		cl = clients + i;
+		if (!cl->pid)
+			break;
+	}
+
+	if (i >= IBSIM_MAX_CLIENTS) {
+		IBWARN("can't open new connection for client pid %d", id);
+		ctl->type = SIM_CTL_ERROR;
+		return -1;
+	}
+
+	if (scl->nodeid[0]) {
+		if (!(node = find_node(scl->nodeid)) &&
+		    !(node = find_node_by_desc(scl->nodeid))) {
+			IBWARN("client %d attempt to attach to unknown host"
+			       " \"%s\"", i, scl->nodeid);
+			ctl->type = SIM_CTL_ERROR;
+			return -1;
+		}
+		cl->port = node_get_port(node, 0);
+		VERB("Attaching client %d at node \"%s\" port 0x%" PRIx64,
+		     i, node->nodeid, cl->port->portguid);
+	} else {
+		VERB("Attaching client %d at default node \"%s\" port 0x%"
+		     PRIx64, i, default_port->node->nodeid,
+		     default_port->portguid);
+		cl->port = default_port;
+	}
+
+	if (scl->issm && sm_exists(cl->port->node)) {
+		IBWARN("client %d (pid %d) connection attempt failed:"
+		       " SM already exists on \"%s\"",
+		       i, id, cl->port->node->nodeid);
+		ctl->type = SIM_CTL_ERROR;
+		return -1;
+	}
+
+	size = make_name(&name, from->name_i.sin_addr.s_addr, id,
+			 "%s:in%d", SIM_BASENAME, id);
+
+	if (connect(cl->fd, (struct sockaddr *)&name, size) < 0)
+		IBPANIC("can't connect to in socket %s - fd %d client pid %d",
+			get_name(&name), cl->fd, id);
+
+	cl->pid = id;
+	cl->id = i;
+	cl->qp = scl->qp;
+	cl->issm = scl->issm;
+
+	strncpy(scl->nodeid, cl->port->node->nodeid, sizeof(scl->nodeid) - 1);
+
+	scl->id = i;
+
+	DEBUG("client %d (%s) is connected - fd %d",
+	      i, get_name(&name), cl->fd);
+
+	return 1;
+}
+
+static int sim_ctl_disconnect_client(Client * cl, struct sim_ctl * ctl)
+{
+	int client = ctl->clientid;
+
+	VERB("disconnecting client %d", client);
+	if (client >= IBSIM_MAX_CLIENTS) {
+		IBWARN("no connection for client %d", client);
+		ctl->type = SIM_CTL_ERROR;
+		return -1;
+	}
+	if (!cl->pid) {
+		DEBUG("client %d is not connected", client);
+		return 0;	// ?
+	}
+
+	DEBUG("Detaching client %d from node \"%s\" port 0x%" PRIx64,
+	      client, cl->port->node->nodeid, cl->port->portguid);
+	cl->pid = 0;
+
+	return 0;
+}
+
+static int sim_ctl_get_port(Client * cl, struct sim_ctl * ctl)
+{
+	struct sim_port *p = (void *)ctl->data;
+
+	p->lid = cl->port->lid;
+	p->state = cl->port->state;
+	return 0;
+}
+
+static int sim_ctl_get_gid(Client * cl, struct sim_ctl * ctl)
+{
+	char *gid = (void *)ctl->data;
+
+	mad_get_array(cl->port->portinfo, 0, IB_PORT_GID_PREFIX_F, gid);
+	memcpy(gid + 8, &cl->port->node->nodeguid, 8);
+	return 0;
+}
+
+static int sim_ctl_get_guid(Client * cl, struct sim_ctl * ctl)
+{
+	char *guid = (void *)ctl->data;
+
+	memcpy(guid, &cl->port->node->nodeguid, 8);
+	return 0;
+}
+
+static int sim_ctl_get_nodeinfo(Client * cl, struct sim_ctl * ctl)
+{
+	memcpy(ctl->data, cl->port->node->nodeinfo, sizeof(ctl->data));
+	return 0;
+}
+
+static int sim_ctl_get_portinfo(Client * cl, struct sim_ctl * ctl)
+{
+	Port *p;
+	uint8_t port_num = ctl->data[0];
+	if (port_num == 0 || port_num > cl->port->node->numports)
+		p = cl->port;
+	else if (cl->port->node->type == SWITCH_NODE)
+		p = node_get_port(cl->port->node, port_num);
+	else
+		p = node_get_port(cl->port->node, port_num - 1);
+	update_portinfo(p);
+	memcpy(ctl->data, p->portinfo, sizeof(ctl->data));
+	return 0;
+}
+
+static void set_issm(Port *port, unsigned issm)
+{
+	uint32_t old_capmask, capmask;
+
+	capmask = mad_get_field(port->portinfo, 0, IB_PORT_CAPMASK_F);
+	old_capmask = capmask;
+	if (issm)
+		capmask |= CAPMASK_ISSM;
+	else
+		capmask &= ~CAPMASK_ISSM;
+	mad_set_field(port->portinfo, 0, IB_PORT_CAPMASK_F, capmask);
+	if (old_capmask != capmask && capmask&(CAPMASK_ISNOTICE|CAPMASK_ISTRAP)
+	    && capmask&CAPMASK_ISCAPMASKTRAP)
+		send_trap(port, TRAP_144);
+}
+
+static int sim_ctl_set_issm(Client * cl, struct sim_ctl * ctl)
+{
+	int issm = *(int *)ctl->data;
+
+	VERB("set issm %d port %" PRIx64, issm, cl->port->portguid);
+	cl->issm = issm;
+	set_issm(cl->port, issm);
+
+	return 0;
+}
+
+static int sim_ctl_get_pkeys(Client * cl, struct sim_ctl * ctl)
+{
+	Port *port = cl->port;
+	unsigned size = (port->node->sw && port->portnum) ?
+	    mad_get_field(port->node->sw->switchinfo, 0,
+			  IB_SW_PARTITION_ENFORCE_CAP_F) :
+	    mad_get_field(port->node->nodeinfo, 0, IB_NODE_PARTITION_CAP_F);
+
+	size *= sizeof(port->pkey_tbl[0]);
+	if (size > sizeof(ctl->data))
+		size = sizeof(ctl->data);
+	memcpy(ctl->data, port->pkey_tbl, size);
+	if (size < sizeof(ctl->data))
+		memset(ctl->data + size, 0, sizeof(ctl->data) - size);
+
+	return 0;
+}
+
+static int sim_ctl_get_vendor(Client * cl, struct sim_ctl * ctl)
+{
+	struct sim_vendor *v = (void *)ctl->data;
+
+	v->vendor_id =
+	    mad_get_field(cl->port->node->nodeinfo, 0, IB_NODE_VENDORID_F);
+	v->vendor_part_id =
+	    mad_get_field(cl->port->node->nodeinfo, 0, IB_NODE_DEVID_F);
+	v->hw_ver =
+	    mad_get_field(cl->port->node->nodeinfo, 0, IB_NODE_REVISION_F);
+	v->fw_ver = 1;
+	return 0;
+}
+
+static int sim_ctl(int fd)
+{
+	union name_t from;
+	socklen_t addrlen = sizeof from;
+	struct sim_ctl ctl = { 0 };
+	Client *cl;
+
+	if (recvfrom(fd, &ctl, sizeof(ctl), 0, (struct sockaddr *)&from,
+		     &addrlen) != sizeof(struct sim_ctl))
+		return -1;
+
+	DEBUG("perform ctl type %d for client %s (%d)",
+	      ctl.type, get_name(&from), ctl.clientid);
+
+	if (ctl.magic != SIM_MAGIC) {
+		IBWARN("bad control pkt: magic %x (%x)", ctl.magic, SIM_MAGIC);
+		return -1;
+	}
+
+	if (ctl.clientid >= IBSIM_MAX_CLIENTS && ctl.type != SIM_CTL_CONNECT) {
+		IBWARN("bad client id %d", ctl.clientid);
+		ctl.type = SIM_CTL_ERROR;
+		return -1;
+	}
+
+	cl = clients + ctl.clientid;
+
+	switch (ctl.type) {
+	case SIM_CTL_CONNECT:
+		sim_ctl_new_client(cl, &ctl, &from);
+		break;
+
+	case SIM_CTL_DISCONNECT:
+		sim_ctl_disconnect_client(cl, &ctl);
+		break;
+
+	case SIM_CTL_GET_PORT:
+		sim_ctl_get_port(cl, &ctl);
+		break;
+
+	case SIM_CTL_GET_VENDOR:
+		sim_ctl_get_vendor(cl, &ctl);
+		break;
+
+	case SIM_CTL_GET_GID:
+		sim_ctl_get_gid(cl, &ctl);
+		break;
+
+	case SIM_CTL_GET_GUID:
+		sim_ctl_get_guid(cl, &ctl);
+		break;
+
+	case SIM_CTL_GET_NODEINFO:
+		sim_ctl_get_nodeinfo(cl, &ctl);
+		break;
+
+	case SIM_CTL_GET_PORTINFO:
+		sim_ctl_get_portinfo(cl, &ctl);
+		break;
+
+	case SIM_CTL_SET_ISSM:
+		sim_ctl_set_issm(cl, &ctl);
+		break;
+
+	case SIM_CTL_GET_PKEYS:
+		sim_ctl_get_pkeys(cl, &ctl);
+		break;
+
+	default:
+	case SIM_CTL_ERROR:
+		IBWARN("bad ctl pkt type %d", ctl.type);
+	}
+
+	if (sendto(fd, &ctl, sizeof ctl, 0, (struct sockaddr *)&from,
+		   addrlen) != sizeof ctl) {
+		IBWARN("cannot response ctl: %m");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int sim_read_pkt(int fd, int client)
+{
+	char buf[512];
+	Client *cl = clients + client, *dcl;
+	int size, ret;
+
+	if (client >= IBSIM_MAX_CLIENTS || !cl->pid) {
+		IBWARN("pkt from unconnected client %d?!", client);
+		return -1;
+	}
+	for (;;) {
+		if ((size = read(fd, buf, sizeof(buf))) <= 0)
+			return size;
+
+		if ((size = process_packet(cl, buf, size, &dcl)) < 0) {
+			IBWARN("process packet error - discarded");
+			continue;	// not a network error
+		}
+
+		if (!dcl)
+			continue;
+
+		VERB("%s %d bytes (%zu) to client %d fd %d",
+		     dcl == cl ? "replying" : "forwarding",
+		     size, sizeof(struct sim_request), dcl->id, dcl->fd);
+
+		// reply
+		do {
+			ret = write(dcl->fd, buf, size);
+		} while ((errno == EAGAIN) && (ret == -1));
+			 
+		if (ret == size)
+			return 0;
+
+		if (ret < 0 && (errno == ECONNREFUSED || errno == ENOTCONN)) {
+			IBWARN("client %u seems to be dead - disconnecting.",
+			       dcl->id);
+			disconnect_client(dcl->id);
+		}
+		IBWARN("write failed: %m - pkt dropped");
+		if (dcl != cl) { /* reply timeout */
+			struct sim_request *r = (struct sim_request *)buf;
+			r->status = htonl(110);
+			ret = write(cl->fd, buf, size);
+		}
+	}
+
+	return -1;		// never reached
+}
+
+int sim_cmd_file(FILE * f, char *s)
+{
+	char line[4096];
+	FILE *cmd_file;
+	char *p;
+
+	s++;
+	while (isspace(*s))
+		s++;
+
+	if (!s || !*s) {
+		fprintf(f, "do_cmd_from_file: no file name - skip\n");
+		return -1;
+	}
+
+	p = s + strlen(s) - 1;
+	while (isspace(*p)) {
+		*p = '\0';
+		p--;
+	}
+
+	cmd_file = fopen(s, "r");
+	if (!cmd_file) {
+		fprintf(f, "do_cmd_from_file: cannot open file \'%s\': %s\n",
+			s, strerror(errno));
+		return -1;
+	}
+
+	while (fgets(line, sizeof(line) - 1, cmd_file) != NULL) {
+		do_cmd(line, f);
+	}
+
+	fclose(cmd_file);
+	return 0;
+}
+
+static int sim_init_net(char *netconf, FILE * out)
+{
+	DEBUG("reading %s", netconf);
+	if (read_netconf(netconf, out) < 0)
+		return -1;
+
+	if (connect_ports() < 0)
+		return -2;
+
+	if (set_default_port(NULL) < 0)
+		return -3;
+
+	return 0;
+}
+
+static int sim_init_console(FILE *out)
+{
+	simout = out;
+
+	fprintf(simout, "########################\n");
+	fprintf(simout, "Network simulator ready.\n");
+	fprintf(simout, "MaxNetNodes    = %d\n", maxnetnodes);
+	fprintf(simout, "MaxNetSwitches = %d\n", maxnetswitches);
+	fprintf(simout, "MaxNetPorts    = %d\n", maxnetports);
+	fprintf(simout, "MaxLinearCap   = %d\n", maxlinearcap);
+	fprintf(simout, "MaxMcastCap    = %d\n", maxmcastcap);
+	fprintf(simout, "sim%s> ", netstarted ? "" : " (inactive)");
+	fflush(simout);
+	return 0;
+}
+
+static int sim_run_console(int fd)
+{
+	char line[128];
+	int ret = 0;
+
+	ret = readline(fd, line, sizeof(line) - 1);
+	if (ret <= 0)
+		return ret;
+
+	do_cmd(line, simout);
+	fprintf(simout, "sim%s> ", netstarted ? "" : " (inactive)");
+	fflush(simout);
+
+	return 0;
+}
+
+static int sim_run(int con_fd)
+{
+	fd_set rfds;
+	int i;
+
+	if (sim_init_conn(SIM_BASENAME) < 0)
+		return -1;
+
+	while (!netstarted)
+		sim_run_console(con_fd);
+
+	for (;;) {
+		FD_ZERO(&rfds);
+		FD_SET(simctl, &rfds);
+		FD_SET(con_fd, &rfds);
+		for (i = 0; i < IBSIM_MAX_CLIENTS; i++)
+			if (clients[i].pid)
+				FD_SET(clients[i].fd, &rfds);
+
+		if (select(maxfd + 1, &rfds, NULL, NULL, 0) < 0)
+			break;	// timeout or error
+
+		if (FD_ISSET(simctl, &rfds))
+			sim_ctl(simctl);
+
+		for (i = 0; i < IBSIM_MAX_CLIENTS; i++)
+			if (clients[i].pid && FD_ISSET(clients[i].fd, &rfds))
+				sim_read_pkt(clients[i].fd, i);
+
+		if (FD_ISSET(con_fd, &rfds))
+			sim_run_console(con_fd);
+	}
+
+	return 0;
+}
+
+int list_connections(FILE * out)
+{
+	int i;
+
+	for (i = 0; i < IBSIM_MAX_CLIENTS; i++) {
+		if (!clients[i].pid)
+			continue;
+		fprintf(out,
+			"Client %d: pid %d connected at \"%s\" port 0x%" PRIx64
+			", lid %d, 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" : "");
+	}
+	return 0;
+}
+
+int disconnect_client(int id)
+{
+	if (id < 0 || id >= IBSIM_MAX_CLIENTS || !clients[id].pid)
+		return -1;
+	clients[id].pid = 0;
+	if (clients[id].issm)
+		set_issm(clients[id].port, 0);
+	return 0;
+}
+
+static Client *client_by_trid(Port *port, uint64_t trid)
+{
+	unsigned i = (unsigned)(trid >> 48);
+	if (i < IBSIM_MAX_CLIENTS && clients[i].pid &&
+	    clients[i].port->portguid == port->portguid)
+		return &clients[i];
+	return NULL;
+}
+
+Client *find_client(Port * port, int response, int qp, uint64_t trid)
+{
+	Client *cl, *e;
+
+	DEBUG("port %" PRIx64 " res %d qp %d trid %" PRIx64,
+	      port->portguid, response, qp, trid);
+	// response - match trids
+	if (response && (cl = client_by_trid(port, trid)))
+		return cl;
+	for (cl = clients, e = cl + IBSIM_MAX_CLIENTS; cl < e; cl++) {
+		if (!cl->pid || cl->port->portguid != port->portguid)
+			continue;
+		// if there is a non zero/1 qp (sma/sa) - match qps
+		if (qp > 1) {
+			if (qp == cl->qp)
+				return cl;
+		// zero qp - only issm clients may get requests
+		} else if (!response && cl->issm)
+			return cl;
+	}
+	DEBUG("no client found");
+	return 0;
+}
+
+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"
+		" -M mcastcap -r(emote_mode) -l(isten_to_port) <port>] <netfile>\n",
+		prog_name);
+	fprintf(stderr, "%s %s\n", prog_name, IBSIM_VERSION);
+
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	extern int alloc_core(void);
+	extern void free_core(void);
+	char *outfname = 0, *netfile;
+	FILE *infile, *outfile;
+
+	static char const str_opts[] = "rf:dpvIsN:S:P:L:M:l:Vhu";
+	static const struct option long_opts[] = {
+		{"remote", 0, 0, 'r'},
+		{"file", 1, 0, 'f'},
+		{"Nodes", 1, 0, 'N'},
+		{"Switches", 1, 0, 'S'},
+		{"Ports", 1, 0, 'P'},
+		{"Linearcap", 1, 0, 'L'},
+		{"Mcastcap", 1, 0, 'M'},
+	        {"listen", 1, 0, 'l'},
+		{"Ignoredups", 0, 0, 'I'},
+		{"start", 0, 0, 's'},
+		{"debug", 0, 0, 'd'},
+		{"parsedebug", 0, 0, 'p'},
+		{"verbose", 0, 0, 'v'},
+		{"Version", 0, 0, 'V'},
+		{"help", 0, 0, 'h'},
+		{"usage", 0, 0, 'u'},
+		{}
+	};
+
+	while (1) {
+		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
+		if (ch == -1)
+			break;
+		switch (ch) {
+		case 'r':
+			remote_mode = 1;
+			break;
+		case 'f':
+			outfname = optarg;
+			break;
+		case 'd':
+			ibdebug++;
+			break;
+		case 'p':
+			parsedebug++;
+			break;
+		case 'v':
+			simverb++;
+			break;
+		case 's':
+			netstarted = 1;
+			break;
+		case 'I':
+			ignoreduplicate = 1;
+			break;
+		case 'N':
+			maxnetnodes = strtoul(optarg, 0, 0);
+			break;
+		case 'S':
+			maxnetswitches = strtoul(optarg, 0, 0);
+			break;
+		case 'P':
+			maxnetports = strtoul(optarg, 0, 0);
+			break;
+		case 'L':
+			maxlinearcap = strtoul(optarg, 0, 0);
+			break;
+		case 'M':
+			maxmcastcap = strtoul(optarg, 0, 0);
+			break;
+	        case 'l':
+			listen_to_port = strtoul(optarg, 0, 0);
+			break;
+		case 'V':
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	maxnetaliases = maxnetports;
+
+	infile = stdin;
+	outfile = stdout;
+	if (outfname && (outfile = fopen(outfname, "w")) == 0)
+		IBPANIC("can't open out file %s for write", outfname);
+
+	if (optind >= argc)
+		usage(argv[0]);
+
+	netfile = argv[optind];
+
+	if (alloc_core() < 0)
+		IBPANIC("not enough memory for core structure");
+
+	DEBUG("initializing net \"%s\"", netfile);
+	if (sim_init_net(netfile, outfile) < 0)
+		IBPANIC("sim_init failed");
+
+	sim_init_console(outfile);
+
+	sim_run(fileno(infile));
+
+	free_core();
+
+	exit(0);
+}
diff --git a/ibsim/sim.h b/ibsim/sim.h
new file mode 100644
index 0000000..b268250
--- /dev/null
+++ b/ibsim/sim.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __SIM_H__
+#define __SIM_H__
+
+#include <infiniband/common.h>
+#include <infiniband/mad.h>
+
+#define MAXNETNODES	2048
+#define MAXNETSWITCHS	256
+#define MAXNETPORTS	(MAXNETSWITCHS*36+MAXNETNODES*2)
+#define MAXNETALIASES	MAXNETPORTS
+
+#define MAXLINEARCAP	(30*1024)
+#define MAXMCASTCAP	1024
+#define LASTBLOCK32	(MAXMCASTCAP/32-1)
+// NUMBEROFPORTMASK means that 32port switches could only be build
+#define	NUMBEROFPORTMASK 2
+#define LASTPORTMASK	(NUMBEROFPORTMASK-1)
+// linkwidth == 4X - must be one width only 1,2 or 8
+#define LINKWIDTH_1x        1
+#define LINKWIDTH_4x        2
+#define LINKWIDTH_8x        4
+#define LINKWIDTH_12x       8
+#define LINKWIDTH_1x_4x     3
+#define LINKWIDTH_1x_4x_12x 11
+
+#define LINKSPEED_SDR       1
+#define LINKSPEED_DDR       2
+#define LINKSPEED_QDR       4
+#define LINKSPEED_SDR_DDR   3
+
+#define	DEFAULT_LINKWIDTH	LINKWIDTH_4x
+#define DEFAULT_LINKSPEED	LINKSPEED_SDR
+
+#define NODEPREFIX	20
+#define NODEIDLEN	65
+#define ALIASLEN 	40
+
+#define MAXHOPS 16
+
+enum NODE_TYPES {
+	NO_NODE = 0,
+	HCA_NODE,
+	SWITCH_NODE,
+	ROUTER_NODE,
+
+	NODE_TYPES
+};
+
+enum TRAP_TYPE_ID {
+	TRAP_128,
+	TRAP_144,
+
+	TRAP_NUM_LAST
+};
+
+/* some PortInfo capmask fields */
+enum PORTINFO_CAPMASK {
+	CAPMASK_ISSM = (1<<1),
+	CAPMASK_ISNOTICE = (1<<2),
+	CAPMASK_ISTRAP = (1<<3),
+	CAPMASK_ISCAPMASKTRAP = (1<<22),
+};
+
+enum GS_PERF_COUNTER_SELECT_MASK {
+	GS_PERF_ERR_SYM_MASK = (1UL << 0),	// SYMBOL_ERROR_COUNTER
+	GS_PERF_LINK_RECOVERS_MASK = (1UL << 1),	// LINK_ERROR_RECOVERY_COUNTER
+	GS_PERF_LINK_DOWNED_MASK = (1UL << 2),	// LINK_DOWNED_COUNTER
+	GS_PERF_ERR_RCV_MASK = (1UL << 3),	// PORT_RCV_ERRORS
+	GS_PERF_ERR_PHYSRCV_MASK = (1UL << 4),	// PORT_RCV_REMOTE_PHYSICAL_ERRORS
+	GS_PERF_ERR_SWITCH_REL_MASK = (1UL << 5),	// PORT_RCV_SWITCH_RELAY_ERRORS
+	GS_PERF_XMT_DISCARDS_MASK = (1UL << 6),	// PORT_XMIT_DISCARDS
+	GS_PERF_ERR_XMTCONSTR_MASK = (1UL << 7),	// PORT_XMIT_CONSTRAINT_ERRORS
+	GS_PERF_ERR_RCVCONSTR_MASK = (1UL << 8),	// PORT_RCV_CONSTRAINT_ERRORS
+	GS_PERF_ERR_LOCALINTEG_MASK = (1UL << 9),	// LOCAL_LINK_INTEGRITY_ERRORS
+	GS_PERF_ERR_EXCESS_OVR_MASK = (1UL << 10),	// EXCESSIVE_BUFFER_OVERRUN_ERRORS
+	GS_PERF_VL15_DROPPED_MASK = (1UL << 11),
+	GS_PERF_XMT_BYTES_MASK = (1UL << 12),	// PORT_XMIT_DATA
+	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
+};
+
+enum GS_PC_EXT_SELECT_MASK {
+	GS_PC_EXT_XMIT_DATA = 1 << 0,
+	GS_PC_EXT_RECV_DATA = 1 << 1,
+	GS_PC_EXT_XMIT_PKTS = 1 << 2,
+	GS_PC_EXT_RECV_PKTS = 1 << 3,
+	GS_PC_EXT_UCAST_XMIT = 1 << 4,
+	GS_PC_EXT_UCAST_RECV = 1 << 5,
+	GS_PC_EXT_MCAST_XMIT = 1 << 6,
+	GS_PC_EXT_MCAST_RECV = 1 << 7,
+};
+
+enum GS_PERF_COUNTER_SELECT_LIMIT {
+	GS_PERF_ERR_SYM_LIMIT = 0xffff,
+	GS_PERF_LINK_RECOVERS_LIMIT = 0xff,
+	GS_PERF_LINK_DOWNED_LIMIT = 0xff,
+	GS_PERF_ERR_RCV_LIMIT = 0xffff,
+	GS_PERF_ERR_PHYSRCV_LIMIT = 0xffff,
+	GS_PERF_ERR_SWITCH_REL_LIMIT = 0xffff,
+	GS_PERF_XMT_DISCARDS_LIMIT = 0xffff,
+	GS_PERF_ERR_XMTCONSTR_LIMIT = 0xff,
+	GS_PERF_ERR_RCVCONSTR_LIMIT = 0xff,
+	GS_PERF_ERR_LOCALINTEG_LIMIT = 0xf,
+	GS_PERF_ERR_EXCESS_OVR_LIMIT = 0xf,
+	GS_PERF_VL15_DROPPED_LIMIT = 0xffff,
+	GS_PERF_XMT_BYTES_LIMIT = 0xffffffff,
+	GS_PERF_RCV_BYTES_LIMIT = 0xffffffff,
+	GS_PERF_XMT_PKTS_LIMIT = 0xffffffff,
+	GS_PERF_RCV_PKTS_LIMIT = 0xffffffff,
+};
+
+typedef struct Port Port;
+typedef struct Portinfo Portinfo;
+typedef struct Switch Switch;
+typedef struct Nodeinfo Nodeinfo;
+typedef struct Node Node;
+typedef struct Client Client;
+typedef struct Portcounters Portcounters;
+
+struct Portinfo {
+	int localport;
+	int linkwidthen;
+	int linkspeeden;
+};
+
+struct Portcounters {
+	uint64_t ext_xmit_data;
+	uint64_t ext_recv_data;
+	uint64_t ext_xmit_pkts;
+	uint64_t ext_recv_pkts;
+	uint64_t ext_ucast_xmit;
+	uint64_t ext_ucast_recv;
+	uint64_t ext_mcast_xmit;
+	uint64_t ext_mcast_recv;
+	uint32_t flow_xmt_pkts;
+	uint32_t flow_xmt_bytes;
+	uint32_t flow_rcv_pkts;
+	uint32_t flow_rcv_bytes;
+	uint16_t xmitdiscards;
+	uint16_t vl15dropped;
+	uint16_t linkrecovers;
+	uint8_t linkdowned;
+	uint16_t errs_rcv;
+	uint16_t errs_sym;
+	uint8_t errs_localinteg;
+	uint16_t errs_remphysrcv;
+	uint8_t errs_xmtconstraint;
+	uint8_t errs_rcvconstraint;
+	uint16_t errs_rcvswitchrelay;
+	uint8_t errs_excessbufovrrun;
+};
+
+struct Port {
+	uint64_t portguid;
+	int portnum;
+	int lid;
+	int smlid;
+	int linkwidth;
+	int linkwidthena;
+	int linkspeed;
+	int linkspeedena;
+	int state;
+	int physstate;
+	int lmc;
+	int hoqlife;
+	uint8_t op_vls;
+	uint8_t portinfo[64];
+
+	char remotenodeid[NODEIDLEN];
+	char remotealias[ALIASLEN + 1];
+	char alias[ALIASLEN + 1];
+	Node *remotenode;
+	int remoteport;
+	Node *previous_remotenode;
+	int previous_remoteport;
+	int errrate;
+	uint16_t errattr;
+	Node *node;
+	Portcounters portcounters;
+	uint16_t *pkey_tbl;
+	uint8_t *sl2vl;
+	struct vlarb {
+		uint8_t vl;
+		uint8_t weight;
+	} vlarb_high[64], vlarb_low[64];
+};
+
+struct Switch {
+	int linearcap;
+//      int randomcap;
+	int multicastcap;
+	int linearFDBtop;
+	int portchange;
+	int lifetime;
+	uint8_t switchinfo[64];
+	Node *node;
+	uint8_t *fdb;
+	uint8_t *mfdb;
+};
+
+struct Node {
+	int type;
+	int numports;
+	uint64_t sysguid;
+	uint64_t nodeguid;	// also portguid
+	int portsbase;		// in port table
+	char nodeid[NODEIDLEN];	// contain nodeid[NODEIDLEN]
+	uint8_t nodeinfo[64];
+	char nodedesc[64];
+	Switch *sw;
+	Client *clist;		// client list
+};
+
+struct Nodeinfo {
+	int localport;
+};
+
+struct Client {
+	int id;
+	int pid;
+	Port *port;
+	int qp;
+	int issm;
+	int fd;
+};
+
+// ibsim.c
+int list_connections(FILE * out);
+Client *find_client(Port * port, int response, int qp, uint64_t trid);
+int disconnect_client(int id);
+
+// sim_net.c
+Node *find_node(char *desc);
+Node *find_node_by_desc(char *desc);
+Node *find_node_by_guid(uint64_t guid);
+const char *node_type_name(unsigned type);
+Port *node_get_port(Node * node, int portnum);
+void reset_port(Port * port);
+int link_ports(Port * lport, Port * rport);
+void update_portinfo(Port * p);
+int build_net(char *netconf);
+int connect_ports(void);
+char *expand_name(char *base, char *name, char **portstr);
+int read_netconf(char *name, FILE * out);
+int set_default_port(char *nodeid);
+int readline(int fd, char *buf, int sz);
+
+// sim_cmd.c
+int do_cmd(char *buf, FILE *f);
+int sim_cmd_file(FILE * file, char *line);
+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);
+
+extern Port *default_port;
+extern int simverb, modified;
+extern int netstarted;
+
+#endif				/* __SIM_H__ */
diff --git a/ibsim/sim_cmd.c b/ibsim/sim_cmd.c
new file mode 100644
index 0000000..dd9384e
--- /dev/null
+++ b/ibsim/sim_cmd.c
@@ -0,0 +1,913 @@
+/*
+ * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include <ibsim.h>
+#include "sim.h"
+
+#undef DEBUG
+#define PDEBUG	if (parsedebug) IBWARN
+#define DEBUG	if (simverb > 1 || ibdebug) IBWARN
+
+extern void free_core(void);
+
+extern Node *nodes;
+extern Switch *switches;
+extern Port *ports;
+extern Port **lids;
+extern int netnodes, netports, netswitches;
+
+#define NAMELEN	NODEIDLEN
+
+static const char *portstates[] = {
+	"-", "Down", "Init", "Armed", "Active",
+};
+
+static const char *physstates[] = {
+	"-", "Sleep", "Polling", "Disabled", "Training", "LinkUp",
+	    "ErrorRecovery",
+};
+
+static const char *portlinkwidth[] = {
+	"-", " 1x", " 4x", "-", " 8x", "-", "-", "-", "12x",
+};
+
+static const char *portlinkspeed[] = {
+	"-", " 2.5G", " 5.0G", "-", "10.0G",
+};
+
+#define PORTSTATE(i) (((i) < 1 || (i) > 4) ? "?" : portstates[(i)])
+#define PHYSSTATE(i) (((i) < 1 || (i) > 6) ? "?" : physstates[(i)])
+#define PORTLINKWIDTH(i) (((i) < 1 || (i) > 8) ? "?" : portlinkwidth[(i)])
+#define PORTLINKSPEED(i) (((i) < 1 || (i) > 4) ? "?" : portlinkspeed[(i)])
+
+static int do_link(FILE * f, char *line)
+{
+	Port *lport, *rport;
+	Node *lnode, *rnode;
+	char *orig = 0;
+	char *lnodeid = 0;
+	char *rnodeid = 0;
+	char *s = line, name[NAMELEN], *sp;
+	int lportnum = -1, rportnum = -1;
+
+	// parse local
+	if (strsep(&s, "\""))
+		orig = strsep(&s, "\"");
+
+	lnodeid = expand_name(orig, name, &sp);
+	if (!sp && s && *s == '[')
+		sp = s + 1;
+
+	DEBUG("lnodeid %s port [%s", lnodeid, sp);
+	if (!(lnode = find_node(lnodeid))) {
+		fprintf(f, "# nodeid \"%s\" (%s) not found\n", orig, lnodeid);
+		return -1;
+	}
+
+	if (sp) {
+		lportnum = strtoul(sp, &sp, 0);
+		if (lportnum < 1 || lportnum > lnode->numports) {
+			fprintf(f, "# nodeid \"%s\": bad port %d\n",
+				lnodeid, lportnum);
+			return -1;
+		}
+	} else {
+		fprintf(f, "# no local port\n");
+		return -1;
+	}
+
+	lport = node_get_port(lnode, lportnum);
+
+	// parse remote
+	if (strsep(&s, "\""))
+		orig = strsep(&s, "\"");
+
+	rnodeid = expand_name(orig, name, &sp);
+	if (!sp && s && *s == '[')
+		sp = s + 1;
+
+	DEBUG("rnodeid %s port [%s", rnodeid, sp);
+	if (!(rnode = find_node(rnodeid))) {
+		fprintf(f, "# nodeid \"%s\" (%s) not found\n", orig, rnodeid);
+		return -1;
+	}
+
+	if (sp) {
+		rportnum = strtoul(sp, &sp, 0);
+		if (rportnum < 1 || rportnum > rnode->numports) {
+			fprintf(f, "# nodeid \"%s\": bad port %d\n",
+				rnodeid, rportnum);
+			return -1;
+		}
+	} else {
+		fprintf(f, "# no remote port\n");
+		return -1;
+	}
+
+	rport = node_get_port(rnode, rportnum);
+
+	if (link_ports(lport, rport) < 0)
+		return -fprintf(f,
+				"# can't link: local/remote port are already connected\n");
+
+	lport->previous_remotenode = NULL;
+	rport->previous_remotenode = NULL;
+
+	return 0;
+}
+
+static int do_relink(FILE * f, char *line)
+{
+	Port *lport, *rport, *e;
+	Node *lnode;
+	char *orig = 0;
+	char *lnodeid = 0;
+	char *s = line, name[NAMELEN], *sp;
+	int lportnum = -1;
+	int numports, relinked = 0;
+
+	// parse local
+	if (strsep(&s, "\""))
+		orig = strsep(&s, "\"");
+
+	lnodeid = expand_name(orig, name, &sp);
+	if (!sp && s && *s == '[')
+		sp = s + 1;
+
+	DEBUG("lnodeid %s port [%s", lnodeid, sp);
+	if (!(lnode = find_node(lnodeid))) {
+		fprintf(f, "# nodeid \"%s\" (%s) not found\n", orig, lnodeid);
+		return -1;
+	}
+
+	if (sp) {
+		lportnum = strtoul(sp, &sp, 0);
+		if (lportnum < 1 || lportnum > lnode->numports) {
+			fprintf(f, "# nodeid \"%s\": bad port %d\n",
+				lnodeid, lportnum);
+			return -1;
+		}
+	}
+	numports = lnode->numports;
+
+	if (lnode->type == SWITCH_NODE)
+		numports++;	// To make the for-loop below run up to last port
+	else
+		lportnum--;
+	
+	if (lportnum >= 0) {
+		lport = ports + lnode->portsbase + lportnum;
+
+		if (!lport->previous_remotenode) {
+			fprintf(f, "# no previous link stored\n");
+			return -1;
+		}
+
+		rport = node_get_port(lport->previous_remotenode, lport->previous_remoteport);
+
+		if (link_ports(lport, rport) < 0)
+			return -fprintf(f,
+					"# can't link: local/remote port are already connected\n");
+
+		lport->previous_remotenode = NULL;
+		rport->previous_remotenode = NULL;
+
+		return 1;
+	}
+
+	for (lport = ports + lnode->portsbase, e = lport + numports; lport < e;
+	     lport++) {
+		if (!lport->previous_remotenode)
+			continue; 
+
+		rport = node_get_port(lport->previous_remotenode, lport->previous_remoteport);
+
+		if (link_ports(lport, rport) < 0)
+			continue;
+
+		lport->previous_remotenode = NULL;
+		rport->previous_remotenode = NULL;
+
+		relinked++;
+	}
+
+	return relinked;
+}
+
+static void unlink_port(Node * lnode, Port * lport, Node * rnode, int rportnum)
+{
+	Port *rport = node_get_port(rnode, rportnum);
+	Port *endport;
+
+	/* save current connection for potential relink later */
+	lport->previous_remotenode = lport->remotenode;
+	lport->previous_remoteport = lport->remoteport;
+	rport->previous_remotenode = rport->remotenode;
+	rport->previous_remoteport = rport->remoteport;
+
+	lport->remotenode = rport->remotenode = 0;
+	lport->remoteport = rport->remoteport = 0;
+	lport->remotenodeid[0] = rport->remotenodeid[0] = 0;
+	lport->state = rport->state = 1;	// Down
+	lport->physstate = rport->physstate = 2;	// Polling
+	if (lnode->sw)
+		lnode->sw->portchange = 1;
+	if (rnode->sw)
+		rnode->sw->portchange = 1;
+
+	if (lnode->type == SWITCH_NODE) {
+		endport = node_get_port(lnode, 0);
+		send_trap(endport, TRAP_128);
+	}
+
+	if (rnode->type == SWITCH_NODE) {
+		endport = node_get_port(rnode, 0);
+		send_trap(endport, TRAP_128);
+	}
+}
+
+static void port_change_lid(Port * port, int lid, int lmc)
+{
+	port->lid = lid;
+	if (lmc > 0)
+		port->lmc = lmc;
+
+	if (port->node->type == SWITCH_NODE) {
+		if (port->node->sw)
+			port->node->sw->portchange = 1;
+	} else if (port->remotenode && port->remotenode->sw)
+		port->remotenode->sw->portchange = 1;
+}
+
+static int do_seterror(FILE * f, char *line)
+{
+	Port *port, *e;
+	Node *node;
+	char *s = line;
+	char *nodeid = 0, name[NAMELEN], *sp, *orig = 0;
+	int portnum = -1;	// def - all ports
+	int 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);
+		return -1;
+	}
+
+	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;
+		}
+	}
+	strsep(&s, " \t");
+	if (!s) {
+		fprintf(f, "# error rate is missing\n");
+		return -1;
+	}
+
+	rate = strtoul(s, 0, 0);
+
+	if (rate > 100) {
+		fprintf(f, "# error rate must be in [0..100] range (%d)\n",
+			rate);
+		return -1;
+	}
+
+	DEBUG("error rate is %d", rate);
+
+	strsep(&s, " \t");
+	if (s) {
+		attr = strtoul(s, 0, 0);
+		DEBUG("error attr is %u", attr);
+	}
+
+	numports = node->numports;
+
+	if (node->type == SWITCH_NODE)
+		numports++;	// To make the for-loop below run up to last port
+	else
+		portnum--;
+
+	if (portnum >= 0) {
+		port = ports + node->portsbase + portnum;
+		port->errrate = rate;
+		port->errattr = attr;
+		return 1;
+	}
+
+	for (port = ports + node->portsbase, e = port + numports; port < e;
+	     port++) {
+		port->errrate = rate;
+		port->errattr = attr;
+		set++;
+	}
+
+	return set;
+}
+
+static int do_unlink(FILE * f, char *line, int clear)
+{
+	Port *port, *e;
+	Node *node;
+	char *s = line;
+	char *nodeid = 0, name[NAMELEN], *sp, *orig = 0;
+	int portnum = -1;	// def - all ports
+	int numports, unlinked = 0;
+
+	if (strsep(&s, "\""))
+		orig = strsep(&s, "\"");
+
+	if (!s) {
+		fprintf(f, "# unlink: bad parameter in \"%s\"\n", line);
+		return -1;
+	}
+
+	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, "# can't unlink port %d at nodeid \"%s\"\n",
+				portnum, nodeid);
+			return -1;
+		}
+	}
+	numports = node->numports;
+
+	if (node->type == SWITCH_NODE)
+		numports++;	// To make the for-loop below run up to last port
+	else
+		portnum--;
+
+	if (portnum >= 0) {
+		port = ports + node->portsbase + portnum;
+		if (!clear && !port->remotenode) {
+			fprintf(f, "# port %d at nodeid \"%s\" is not linked\n",
+				portnum, nodeid);
+			return -1;
+		}
+		if (port->remotenode)
+			unlink_port(node, port, port->remotenode,
+				    port->remoteport);
+		if (clear)
+			reset_port(port);
+		return 1;
+	}
+
+	for (port = ports + node->portsbase, e = port + numports; port < e;
+	     port++) {
+		if (!clear && !port->remotenode)
+			continue;
+		if (port->remotenode)
+			unlink_port(node, port, port->remotenode,
+				    port->remoteport);
+		if (clear)
+			reset_port(port);
+		unlinked++;
+	}
+
+	return unlinked;
+}
+
+static int do_set_guid(FILE * f, char *line)
+{
+	char name[NAMELEN];
+	uint64_t new_guid;
+	Node *node;
+	Port *port = NULL;
+	char *s = line, *end;
+	char *nodeid = 0, *sp, *orig = 0;
+	int portnum = -1;
+
+	if (strsep(&s, "\""))
+		orig = strsep(&s, "\"");
+
+	if (!s) {
+		fprintf(f, "# set_guid: bad parameter in \"%s\"\n", line);
+		return -1;
+	}
+
+	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 ((node->type != SWITCH_NODE && portnum < 1)
+		    || portnum > node->numports) {
+			fprintf(f, "# can't parse port %d at nodeid \"%s\"\n",
+				portnum, nodeid);
+			return -1;
+		}
+		if (node->type != SWITCH_NODE)
+			port = ports + node->portsbase + portnum - 1;
+	}
+
+	while (isspace(*s))
+		s++;
+
+	if (!s)
+		return 0;
+
+	new_guid = strtoull(s, &end, 0);
+	if (*end && !isspace(*end))
+		return 0;
+
+	if (port)
+		port->portguid = new_guid;
+	else {
+		node->nodeguid = new_guid;
+		mad_encode_field(node->nodeinfo, IB_NODE_GUID_F,
+				 &node->nodeguid);
+	}
+
+	return 1;
+}
+
+static void dump_switch(FILE * f, Switch * sw)
+{
+	int i, j, top;
+
+	fprintf(f, "#\tlinearcap %d FDBtop %d portchange %d\n",
+		sw->linearcap, sw->linearFDBtop, sw->portchange);
+
+	for (i = 0; i < sw->linearFDBtop; i += 16) {
+		top = i + 16;
+		if (top >= sw->linearFDBtop)
+			top = sw->linearFDBtop + 1;
+
+		fprintf(f, "#\tForwarding table %d-%d:", i, top - 1);
+		for (j = i; j < top; j++)
+			fprintf(f, " [%d]%X", j, (unsigned char)sw->fdb[j]);
+		fprintf(f, "\n");
+	}
+}
+
+static void dump_comment(Port * port, char *comment)
+{
+	int n = 0;
+	if (port->errrate)
+		n += sprintf(comment, "\t# err_rate %d", port->errrate);
+	if (port->errattr)
+		n += sprintf(comment+n, "\t# err_attr %d", port->errattr);
+}
+
+static void dump_port(FILE * f, Port * port, int type)
+{
+	char comment[100] = "";
+
+	dump_comment(port, comment);
+
+	if (port->state == 1)
+		fprintf(f, "%" PRIx64 "\t[%d]\t\t", port->portguid,
+			port->portnum);
+	else
+		fprintf(f, "%" PRIx64 "\t[%d]\t\"%s\"[%d]",
+			port->portguid, port->portnum,
+			port->remotenode ? port->remotenode->
+			nodeid : "Sma Port", port->remoteport);
+	if (type == SWITCH_NODE && port->portnum)
+		fprintf(f, "\t %s %s %s/%s%s\n",
+			PORTLINKWIDTH(port->linkwidth),
+			PORTLINKSPEED(port->linkspeed),
+			PORTSTATE(port->state), PHYSSTATE(port->physstate),
+			comment);
+	else
+		fprintf(f, "\t lid %d lmc %d smlid %d %s %s %s/%s%s\n",
+			port->lid, port->lmc, port->smlid,
+			PORTLINKWIDTH(port->linkwidth),
+			PORTLINKSPEED(port->linkspeed),
+			PORTSTATE(port->state), PHYSSTATE(port->physstate),
+			comment);
+}
+
+static int dump_net(FILE * f, char *line)
+{
+	Node *node, *e;
+	int nports, i;
+	char *s = line;
+	char name[NAMELEN], *sp;
+	char *nodeid = 0;
+	int nnodes = 0;
+
+	time_t t = time(0);
+
+	if (strsep(&s, "\""))
+		nodeid = expand_name(strsep(&s, "\""), name, &sp);
+
+	fprintf(f, "# Net status - %s", ctime(&t));
+	for (node = nodes, e = node + netnodes; node < e; node++) {
+		if (nodeid && strcmp(nodeid, node->nodeid))
+			continue;
+
+		fprintf(f, "\n%s %d \"%s\"",
+			node_type_name(node->type),
+			node->numports, node->nodeid);
+		fprintf(f, "\tnodeguid %" PRIx64 "\tsysimgguid %" PRIx64 "\n",
+			node->nodeguid, node->sysguid);
+		nports = node->numports;
+		if (node->type == SWITCH_NODE) {
+			nports++;
+			dump_switch(f, node->sw);
+		}
+		for (i = 0; i < nports; i++) {
+			dump_port(f, ports + node->portsbase + i, node->type);
+		}
+		nnodes++;
+	}
+
+	if (nodeid && !nnodes)
+		return -fprintf(f, "# nodeid \"%s\" not found\n", nodeid);
+	else
+		fprintf(f, "#  dumped %d nodes\n", nnodes);
+
+	fflush(f);
+
+	return 0;
+}
+
+static Port *find_port(int lid)
+{
+	Port *port = 0;
+	int i, l;
+
+	for (l = lid, i = 256; i-- && l > 0; l--) {
+		if ((port = lids[l]))
+			break;
+	}
+	if (port && (port->lid + (1 << port->lmc)) > lid)
+		return port;
+	return 0;
+}
+
+static int do_change_baselid(FILE * f, char *line)
+{
+	Port *port;
+	Node *node;
+	char *s = line;
+	char *nodeid = 0, name[NAMELEN], *sp, *orig = 0;
+	int portnum = -1;	// def - all ports
+	int lid = 0, lmc = -1;
+
+	if (strsep(&s, "\""))
+		orig = strsep(&s, "\"");
+
+	if (!s) {
+		fprintf(f, "# change baselid: bad parameter in \"%s\"\n", line);
+		return -1;
+	}
+
+	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) {
+		fprintf(f, "# change baselid: missing portnum");
+		return -1;
+	}
+
+	portnum = strtoul(sp, &sp, 0);
+	if ((portnum < 1 && node->type != SWITCH_NODE)
+	    || portnum > node->numports) {
+		fprintf(f,
+			"# can't change baselid for port %d at nodeid \"%s\"\n",
+			portnum, nodeid);
+		return -1;
+	}
+
+	if (node->type != SWITCH_NODE)
+		portnum--;
+
+	port = ports + node->portsbase + portnum;
+
+	if (!sp || *sp != ']') {
+		fprintf(f, "# change baselid: missing ']'\n");
+		return -1;
+	}
+
+	sp++;
+
+	if (sp && *sp)
+		while (isspace(*sp))
+			sp++;
+	lid = strtoul(sp, &sp, 0);
+
+	if (!lid) {
+		fprintf(f, "# change baselid: bad lid\n");
+		return -1;
+	}
+
+	if (sp && *sp)
+		while (isspace(*sp))
+			sp++;
+
+	if (sp && *sp)
+		lmc = strtoul(sp, 0, 0);
+
+	port_change_lid(port, lid, lmc);
+	return 1;
+}
+
+static int dump_route(FILE * f, char *line)
+{
+	char *s = line, *p1, *p2;
+	int from, to;
+	int maxhops = MAXHOPS;
+	Node *node;
+	Port *port, *fromport, *toport;
+	int portnum, outport;
+
+	if (!strsep(&s, "\t ") || !(p1 = strsep(&s, "\t "))
+	    || !(p2 = strsep(&s, "\t "))) {
+		fprintf(f, "bad params. Usage: route from-lid lid\n");
+		return -1;
+	}
+	from = strtoul(p1, 0, 0);
+	to = strtoul(p2, 0, 0);
+
+	if (!from || !to) {
+		fprintf(f, "bad lid value. Usage: route from-lid to-lid\n");
+		return -1;
+	}
+	fromport = find_port(from);
+	toport = find_port(to);
+
+	if (!fromport || !toport) {
+		fprintf(f,
+			"to/from lid unconfigured. Usage: route from-lid to-lid\n");
+		return -1;
+	}
+
+	node = fromport->node;
+	port = fromport;
+	portnum = port->portnum;
+	fprintf(f, "From node \"%s\" port %d lid %d\n", node->nodeid, portnum,
+		from);
+	while (maxhops--) {
+		if (port->state != 4)
+			goto badport;
+		if (port == toport)
+			break;	// found
+		outport = portnum;
+		if (node->type == SWITCH_NODE) {
+			if ((outport = node->sw->fdb[to]) < 0
+			    || to > node->sw->linearFDBtop)
+				goto badtbl;
+			port = ports + node->portsbase + outport;
+			if (outport == 0) {
+				if (port != toport)
+					goto badtbl;
+				else
+					break;	// found SMA port
+			}
+			if (port->state != 4)
+				goto badoutport;
+		}
+		node = port->remotenode;
+		port = ports + node->portsbase + port->remoteport;
+		if (node->type != SWITCH_NODE)
+			port--;
+		portnum = port->portnum;
+		fprintf(f, "[%d] -> \"%s\"[%d]\n", outport, node->nodeid,
+			portnum);
+	}
+
+	if (maxhops <= 0) {
+		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,
+		to);
+	return 0;
+
+      badport:
+	fprintf(f, "Bad port state found: node \"%s\" port %d state %d\n",
+		node->nodeid, portnum, port->state);
+	return -1;
+      badoutport:
+	fprintf(f,
+		"Bad out port state found: node \"%s\" outport %d state %d\n",
+		node->nodeid, outport, port->state);
+	return -1;
+      badtbl:
+	fprintf(f,
+		"Bad forwarding table entry found at: node \"%s\" lid entry %d is %d (top %d)\n",
+		node->nodeid, to, outport, node->sw->linearFDBtop);
+	return -1;
+}
+
+static int change_verbose(FILE * f, char *line)
+{
+	char *s = line;
+
+	if (strsep(&s, "\t ") && s)
+		simverb = strtoul(s, 0, 0);
+	fprintf(f, "simulator verbose level is %d\n", simverb);
+	return 0;
+}
+
+static int do_wait(FILE * f, char *line)
+{
+	char *s = line;
+	long sec = 0;
+
+	if (strsep(&s, "\t ") && s)
+		sec = strtoul(s, 0, 0);
+	if (sec <= 0)
+		return -fprintf(f, "wait: bad param %ld\n", sec);
+	else
+		sleep(sec);
+	return 0;
+}
+
+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, "\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");
+	fprintf(f, "\tReLink \"nodeid\"[port] : restore previously unconnected link\n");
+	fprintf(f, "\tUnlink \"nodeid\" : remove all links of the node\n");
+	fprintf(f, "\tUnlink \"nodeid\"[port]\n");
+	fprintf(f,
+		"\tClear \"nodeid\" : unlink & reset all links of the node\n");
+	fprintf(f, "\tClear \"nodeid\"[port] : unlink & reset port\n");
+	fprintf(f, "\tGuid \"nodeid\" : set GUID value for this node\n");
+	fprintf(f, "\tGuid \"nodeid\"[port] : set GUID value for this port\n");
+	fprintf(f,
+		"\tError \"nodeid\"[port] <error-rate> [attribute]: set error rate for\n"
+		"\t\t\tport/node, optionally for specified attribute ID\n"
+		"\t\t\tSome common attribute IDs:\n"
+		"\t\t\t\tNodeDescription : 16\n"
+		"\t\t\t\tNodeInfo        : 17\n"
+		"\t\t\t\tSwitchInfo      : 18\n"
+		"\t\t\t\tPortInfo        : 19\n"
+		);
+	fprintf(f,
+		"\tBaselid \"nodeid\"[port] <lid> [lmc] : change port's lid (lmc)\n");
+	fprintf(f, "\tVerbose [newlevel] - show/set simulator verbosity\n");
+	fprintf(f, "\t\t\t0 - silent\n");
+	fprintf(f, "\t\t\t1 - debug verbose\n");
+	fprintf(f, "\tWait <sec> : suspend simulator prompt\n");
+	fprintf(f, "\tAttached : list attached clients\n");
+	fprintf(f, "\tX <client num> : (force) disconnect client\n");
+	fprintf(f, "\t#... : comment line (for scripts) - ignored\n");
+	fprintf(f, "\tHelp/?\n");
+	fprintf(f, "\tQuit\n");
+	return 0;
+}
+
+static int do_disconnect_client(FILE * out, int id)
+{
+	if (disconnect_client(id)) {
+		fprintf(out, "disconnect client: bad clientid %d\n", id);
+		return -1;
+	}
+	return 0;
+}
+
+int netstarted;
+
+int do_cmd(char *buf, FILE *f)
+{
+	unsigned int cmd_len = 0;
+	char *line;
+	int r = 0;
+
+	for (line = buf; *line && isspace(*line); line++) ;
+
+	while (!isspace(line[cmd_len]))
+		cmd_len++;
+
+	if (*line == '#')
+		fprintf(f, line);
+	else if (*line == '!')
+		r = sim_cmd_file(f, line);
+	else if (!strncasecmp(line, "Dump", cmd_len))
+		r = dump_net(f, line);
+	else if (!strncasecmp(line, "Route", cmd_len))
+		r = dump_route(f, line);
+	else if (!strncasecmp(line, "Link", cmd_len))
+		r = do_link(f, line);
+	else if (!strncasecmp(line, "Unlink", cmd_len))
+		r = do_unlink(f, line, 0);
+	else if (!strncasecmp(line, "Clear", cmd_len))
+		r = do_unlink(f, line, 1);
+	else if (!strncasecmp(line, "Guid", cmd_len))
+		r = do_set_guid(f, line);
+	else if (!strncasecmp(line, "Error", cmd_len))
+		r = do_seterror(f, line);
+	else if (!strncasecmp(line, "Baselid", cmd_len))
+		r = do_change_baselid(f, line);
+	else if (!strncasecmp(line, "Start", cmd_len)) {
+		if (!netstarted) {
+			DEBUG("starting...");
+			netstarted = 1;
+			return 0;
+		}
+	}
+	else if (!strncasecmp(line, "Verbose", cmd_len))
+		r = change_verbose(f, line);
+	else if (!strncasecmp(line, "Wait", cmd_len))
+		r = do_wait(f, line);
+	else if (!strncasecmp(line, "Attached", cmd_len))
+		r = list_connections(f);
+	else if (!strncasecmp(line, "X", cmd_len))
+		r = do_disconnect_client(f, strtol(line + 2, 0, 0));
+	else if (!strncasecmp(line, "Help", cmd_len)
+		 || !strncasecmp(line, "?", cmd_len))
+		r = dump_help(f);
+	else if (!strncasecmp(line, "Quit", cmd_len)) {
+		fprintf(f, "Exiting network simulator.\n");
+		free_core();
+		exit(0);
+	}
+	/* commands specified above support legacy single
+	 * character options.  For example, 'g' or 'G' for "Guid"
+	 * and 'l' or 'L' for "Link".
+	 *
+	 * please specify new command support below this comment.
+	 */
+	else if (!strncasecmp(line, "ReLink", cmd_len))
+		r = do_relink(f, line);
+	else if (*line != '\n' && *line != '\0')
+		fprintf(f, "command \'%s\' unknown - skipped\n", line);
+
+	return r;
+}
diff --git a/ibsim/sim_mad.c b/ibsim/sim_mad.c
new file mode 100644
index 0000000..f530a7a
--- /dev/null
+++ b/ibsim/sim_mad.c
@@ -0,0 +1,1343 @@
+/*
+ * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include <ibsim.h>
+#include "sim.h"
+
+#undef DEBUG
+#define DEBUG	if (simverb > 1 || ibdebug) IBWARN
+#define VERB	if (simverb || ibdebug) IBWARN
+
+#define ERR_METHOD_UNSUPPORTED	(2 << 2)
+#define ERR_ATTR_UNSUPPORTED	(3 << 2)
+#define ERR_BAD_PARAM		(7 << 2)
+
+typedef int (Smpfn) (Port * port, unsigned op, uint32_t mod, uint8_t * data);
+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;
+
+static EncodeTrapfn encode_trap128;
+static EncodeTrapfn encode_trap144;
+
+static Smpfn *attrs[IB_PERFORMANCE_CLASS + 1][0xff] = {
+	[IB_SMI_CLASS] {[IB_ATTR_NODE_DESC] do_nodedesc,
+			[IB_ATTR_NODE_INFO] do_nodeinfo,
+			[IB_ATTR_SWITCH_INFO] do_switchinfo,
+			[IB_ATTR_PORT_INFO] do_portinfo,
+			[IB_ATTR_LINEARFORWTBL] do_linearforwtbl,
+			[IB_ATTR_MULTICASTFORWTBL] do_multicastforwtbl,
+			[IB_ATTR_PKEY_TBL] do_pkeytbl,
+			[IB_ATTR_SLVL_TABLE] do_sl2vl,
+			[IB_ATTR_VL_ARBITRATION] do_vlarb,
+			[IB_ATTR_GUID_INFO] do_guidinfo,
+			[IB_ATTR_SMINFO] NULL,
+
+			[IB_ATTR_LAST] 0,
+			},
+	[IB_PERFORMANCE_CLASS] {[CLASS_PORT_INFO] = do_nothing,
+				[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_ATTR_LAST] 0,
+
+				},
+};
+
+static EncodeTrapfn *encodetrap[] = {
+	[TRAP_128] encode_trap128,
+	[TRAP_144] encode_trap144,
+
+	[TRAP_NUM_LAST] 0,
+
+};
+
+extern Node *nodes;
+extern Switch *switchs;
+extern Port *ports;
+extern Port **lids;
+extern int netnodes, netports, netswitches;
+extern int maxlinearcap;
+
+static uint64_t update_trid(uint8_t *mad, unsigned response, Client *cl)
+{
+	uint64_t trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
+	if (!response) {
+		trid = (trid&0xffffffffffffULL)|(((uint64_t)cl->id)<<48);
+		mad_set_field64(mad, 0, IB_MAD_TRID_F, trid);
+	}
+	return trid;
+}
+
+static int decode_sim_MAD(Client * cl, struct sim_request * r, ib_rpc_t * rpc,
+			  ib_dr_path_t * path, void *data)
+{
+	void *buf = r->mad;
+	int response;
+
+	// first word
+	response = mad_get_field(buf, 0, IB_MAD_RESPONSE_F);
+	if (mad_get_field(buf, 0, IB_MAD_CLASSVER_F) > 2 ||	// sma ver is 1, sa is 2
+	    mad_get_field(buf, 0, IB_MAD_BASEVER_F) != 1) {
+		IBWARN("bad smp headers (1st word)");
+		return -1;
+	}
+	rpc->method = mad_get_field(buf, 0, IB_MAD_METHOD_F);
+	rpc->mgtclass = mad_get_field(buf, 0, IB_MAD_MGMTCLASS_F);
+
+	// second word:
+	if (rpc->mgtclass == 0x81) {	// direct route
+		if (mad_get_field(buf, 0, IB_DRSMP_HOPPTR_F) != 0x0 ||
+		    mad_get_field(buf, 0, IB_DRSMP_DIRECTION_F) != response) {
+			IBWARN("bad direct smp headers (2nd word)");
+			return -1;
+		}
+		path->cnt = mad_get_field(buf, 0, IB_DRSMP_HOPCNT_F);
+	} else if (r->slid == 0)
+		r->slid = htons(cl->port->lid);
+
+	// words 3,4,5,6
+	rpc->trid = update_trid(buf, response, cl);
+
+	rpc->attr.id = mad_get_field(buf, 0, IB_MAD_ATTRID_F);
+	rpc->attr.mod = mad_get_field(buf, 0, IB_MAD_ATTRMOD_F);
+
+	// words 7,8
+//      mad_get_field(buf, 0, SMP_MKEY, rpc->mkey >> 32);
+//      mad_get_field(buf, 4, SMP_MKEY, rpc->mkey & 0xffffffff);
+
+	if (rpc->mgtclass == 0x81) {	// direct route
+		// word 9
+		if (mad_get_field(buf, 0, IB_DRSMP_DRDLID_F) != 0xffff ||
+		    mad_get_field(buf, 0, IB_DRSMP_DRSLID_F) != 0xffff) {
+			IBWARN("dr[ds]lids are used (not supported)");
+			return -1;
+		}
+		// bytes 128 - 256
+		if (!response)
+			mad_get_array(buf, 0, IB_DRSMP_PATH_F, path->p);
+		else
+			mad_get_array(buf, 0, IB_DRSMP_RPATH_F, path->p);
+	}
+
+	if (rpc->mgtclass == 0x4 || rpc->mgtclass == 0x1
+	    || rpc->mgtclass == 0x81) {
+		rpc->dataoffs = 64;
+		rpc->datasz = 64;
+	}
+	if (data)
+		memcpy(data, (char *)buf + rpc->dataoffs, rpc->datasz);
+
+	return response;
+}
+
+static int forward_MAD(void *buf, ib_rpc_t * rpc, ib_dr_path_t * path)
+{
+	if (rpc->mgtclass == 0x81) {	// direct route
+		// word 9
+
+		// bytes 128 - 256
+		mad_set_array(buf, 0, IB_DRSMP_RPATH_F, path->p);
+	}
+	return 0;
+}
+
+static int reply_MAD(void *buf, ib_rpc_t * rpc, ib_dr_path_t * path,
+		     int status, void *data)
+{
+	// first word
+	mad_set_field(buf, 0, IB_MAD_RESPONSE_F, 1);
+	mad_set_field(buf, 0, IB_MAD_METHOD_F, 0x81);	// SUBN_GETRESP
+
+	// second word:
+	if (rpc->mgtclass == 0x81) {	// direct route
+		mad_set_field(buf, 0, IB_DRSMP_STATUS_F, status);
+		mad_set_field(buf, 0, IB_DRSMP_DIRECTION_F, 1);
+	} else
+		mad_set_field(buf, 0, IB_MAD_STATUS_F, status);
+
+	// words 3,4,5,6
+
+	// words 7,8
+
+	if (rpc->mgtclass == 0x81) {	// direct route
+		// word 9
+
+		// bytes 128 - 256
+		mad_set_array(buf, 0, IB_DRSMP_RPATH_F, path->p);
+//              memcpy(buf+128+64, buf+128, 64);        // copy dest path -> return path
+	}
+
+	if (data)
+		memcpy((char *)buf + rpc->dataoffs, data, rpc->datasz);
+
+	return 0;
+}
+
+static int do_nothing(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+{
+	return 0;
+}
+
+static int do_nodedesc(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+{
+	int status = 0;
+
+	if (op != 1)		// get
+		status = ERR_METHOD_UNSUPPORTED;
+	memcpy(data, port->node->nodedesc, IB_SMP_DATA_SIZE);
+
+	return status;
+}
+
+static int do_nodeinfo(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+{
+	Node *node = port->node;
+	int status = 0;
+	uint64_t portguid = node->nodeguid + port->portnum;
+
+	if (op != IB_MAD_METHOD_GET)	// get
+		status = ERR_METHOD_UNSUPPORTED;
+	memcpy(data, node->nodeinfo, IB_SMP_DATA_SIZE);
+
+	mad_set_field(data, 0, IB_NODE_LOCAL_PORT_F, port->portnum);
+	if (node->type == SWITCH_NODE)
+		mad_encode_field(data, IB_NODE_PORT_GUID_F, &node->nodeguid);
+	else
+		mad_encode_field(data, IB_NODE_PORT_GUID_F, &portguid);
+
+	return status;
+}
+
+static int do_switchinfo(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+{
+	Switch *sw = port->node->sw;
+
+	if (!sw)		// not a Switch?
+		return ERR_ATTR_UNSUPPORTED;
+
+	if (op == 2) {		// Set
+		if (mad_get_field(data, 0, IB_SW_STATE_CHANGE_F))
+			sw->portchange = 0;
+		sw->linearFDBtop =
+		    mad_get_field(data, 0, IB_SW_LINEAR_FDB_TOP_F);
+		sw->lifetime = mad_get_field(data, 0, IB_SW_LIFE_TIME_F);
+	}
+
+	memcpy(data, sw->switchinfo, IB_SMP_DATA_SIZE);
+
+	mad_set_field(data, 0, IB_SW_STATE_CHANGE_F, sw->portchange);
+	mad_set_field(data, 0, IB_SW_LINEAR_FDB_TOP_F, sw->linearFDBtop);
+	mad_set_field(data, 0, IB_SW_LIFE_TIME_F, sw->lifetime);
+
+	return 0;
+}
+
+static int do_pkeytbl(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+{
+	unsigned block = mod & 0xffff;
+	unsigned port_num = mod >> 16;
+	unsigned pkey_size, size;
+	uint16_t *pkeys;
+
+	if (port->node->sw && !(port = node_get_port(port->node, port_num)))
+		return ERR_BAD_PARAM;
+
+	pkey_size = (port->node->sw && port_num) ?
+	    mad_get_field(port->node->sw->switchinfo, 0,
+			  IB_SW_PARTITION_ENFORCE_CAP_F) :
+	    mad_get_field(port->node->nodeinfo, 0, IB_NODE_PARTITION_CAP_F);
+
+	if (block * 32 >= pkey_size)
+		return ERR_BAD_PARAM;
+
+	pkeys = port->pkey_tbl + block * 32;
+	size = pkey_size - block * 32;
+	if (size > 32)
+		size = 32;
+
+	if (op == IB_MAD_METHOD_SET) {
+		memcpy(pkeys, data, size * sizeof(uint16_t));
+	} else {
+		memset(data, 0, 32 * sizeof(uint16_t));
+		memcpy(data, pkeys, size * sizeof(uint16_t));
+	}
+
+	return 0;
+}
+
+static int do_sl2vl(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+{
+	uint8_t *sl2vl;
+	unsigned n;
+
+	if (port->node->sw) {
+		n = (mod >> 8) & 0xff;
+		port = node_get_port(port->node, n);
+		n = mod & 0xff;
+		if (!port && !node_get_port(port->node, n))
+			return ERR_BAD_PARAM;
+	} else
+		n = 0;
+
+	sl2vl = port->sl2vl + 8 * n;
+
+	if (op == IB_MAD_METHOD_SET) {
+		memcpy(sl2vl, data, 8);
+	} else {
+		memcpy(data, sl2vl, 8);
+	}
+
+	return 0;
+}
+
+static int do_vlarb(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+{
+	struct vlarb *vlarb;
+	unsigned size, n;
+
+	if (port->node->sw) {
+		n = mod & 0xffff;
+		port = node_get_port(port->node, n);
+		if (!port)
+			return ERR_BAD_PARAM;
+	}
+
+	n = (mod >> 16) - 1;
+	if (n > 3)
+		return ERR_BAD_PARAM;
+
+	size = mad_get_field(port->portinfo, 0,
+			     (n / 2) ? IB_PORT_VL_ARBITRATION_HIGH_CAP_F :
+			     IB_PORT_VL_ARBITRATION_LOW_CAP_F);
+	if (!size || n % 2 > size / 32)
+		return ERR_BAD_PARAM;
+
+	vlarb = (n / 2) ? port->vlarb_high : port->vlarb_low;
+	vlarb += (n % 2) * 32;
+
+	if (size > 32 && n % 2)
+		size %= 32;
+
+	size *= sizeof(*vlarb);
+
+	if (op == IB_MAD_METHOD_SET) {
+		memcpy(vlarb, data, size);
+	} else {
+		memset(data, 0, 64);
+		memcpy(data, vlarb, size);
+	}
+
+	return 0;
+}
+
+static int do_guidinfo(Port * port, unsigned op, uint32_t mod, uint8_t * data)
+{
+	Node *node = port->node;
+	int status = 0;
+	uint64_t portguid = node->nodeguid + port->portnum;
+
+	if (op != IB_MAD_METHOD_GET)    // only get currently supported (non compliant)
+		status = ERR_METHOD_UNSUPPORTED;
+
+	memset(data, 0, 64);
+	if (mod == 0) {
+		if (node->type == SWITCH_NODE)
+			mad_encode_field(data, IB_GUID_GUID0_F, &node->nodeguid);
+		else
+			mad_encode_field(data, IB_GUID_GUID0_F, &portguid);
+	}
+
+	return status;
+}
+
+static int
+do_portinfo(Port * port, unsigned op, uint32_t portnum, uint8_t * data)
+{
+	Node *node = port->node;
+	Port *p, *rp;
+	int r, newlid, newstate = 0;
+
+	if (portnum > node->numports)
+		return ERR_BAD_PARAM;
+
+	if (portnum == 0 && node->type != SWITCH_NODE)	//according to ibspec 14.2.5.6
+		portnum = port->portnum;
+
+	p = node_get_port(node, portnum);
+	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
+		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
+		newlid = mad_get_field(data, 0, IB_PORT_LID_F);
+		if (newlid != p->lid) {
+			if (p->lid > 0 && p->lid < maxlinearcap
+			    && lids[p->lid] == p)
+				lids[p->lid] = 0;
+		}
+		p->lid = newlid;
+		p->smlid = mad_get_field(data, 0, IB_PORT_SMLID_F);
+//              p->linkwidth = mad_get_field(data, 0, IB_PORT_LINK_WIDTH_ENABLED_F); // ignored
+		p->lmc = mad_get_field(data, 0, IB_PORT_LMC_F);
+		p->hoqlife = mad_get_field(data, 0, IB_PORT_HOQ_LIFE_F);
+		if ((r = mad_get_field(data, 0, IB_PORT_PHYS_STATE_F)))
+			p->physstate = r;
+		r = mad_get_field(data, 0, IB_PORT_STATE_F);
+		if (r > 0 && p->remotenode &&
+		    (rp = node_get_port(p->remotenode, p->remoteport))) {
+			if (r == 1) {	/* DOWN */
+				newstate = p->state = 2;	/* set to INIT */
+				/*
+				 * If the state is changed to initialize (from down or not)
+				 * we should force remote state to same state.
+				 * We also should set portchange on remote node.
+				 * Note that the local portchange (if switch) is not changed
+				 * according to the spec (p. 731) - no portchange on subnset.
+				 */
+				rp->state = 2;
+				if (p->remotenode->type == SWITCH_NODE)
+					p->remotenode->sw->portchange = 1;
+			} else if (r > 2) {
+				if (abs(rp->state - r) <= 1
+				    && abs(p->state - r) == 1)
+					newstate = p->state = r;	/* set to new state */
+				else
+					return ERR_BAD_PARAM;
+			}
+		} else if (r > 1)
+			return ERR_BAD_PARAM;	/* trying to change the state of DOWN port */
+
+		if (p->state == 4) {
+			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)",
+				     node->nodeid, p->portnum, p->lid,
+				     lids[p->lid]->node->nodeid,
+				     lids[p->lid]->portnum);
+			lids[p->lid] = p;
+		}
+		val = mad_get_field(data, 0, IB_PORT_OPER_VLS_F);
+		if (val > mad_get_field(data, 0, IB_PORT_VL_CAP_F))
+			return ERR_BAD_PARAM;
+		p->op_vls = val;
+	}
+
+	update_portinfo(p);
+	memcpy(data, p->portinfo, IB_SMP_DATA_SIZE);
+
+	return 0;
+}
+
+static int do_linearforwtbl(Port * port, unsigned op, uint32_t mod,
+			    uint8_t * data)
+{
+	Switch *sw = port->node->sw;
+
+	if (!sw)		// not a Switch?
+		return ERR_ATTR_UNSUPPORTED;
+
+	if (mod < 0 || mod > 767)
+		return ERR_BAD_PARAM;
+
+	if (op == IB_MAD_METHOD_SET) {	// 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);
+
+	return 0;
+}
+
+static int do_multicastforwtbl(Port * port, unsigned op, uint32_t mod,
+			       uint8_t * data)
+{
+	int numPortMsk = mod >> 28;	// high order 4 bits
+	int numBlock32 = mod & 0x1ff;	// low order 9 bits
+	int blockposition;
+
+	Switch *sw = port->node->sw;
+
+	if (!sw)		// not a Switch?
+		return ERR_ATTR_UNSUPPORTED;
+
+	VERB("requested : Block32 %d PortMask %d", numBlock32, numPortMsk);
+	if (numBlock32 > LASTBLOCK32 || numPortMsk > LASTPORTMASK) {
+		int8_t zeroblock[64] = { 0 };
+		mad_set_array(data, 0, IB_MULTICAST_FORW_TBL_F, zeroblock);
+		return 0;
+	}
+
+	blockposition = (numBlock32 * NUMBEROFPORTMASK + numPortMsk) * 64;
+	if (op == IB_MAD_METHOD_SET) {	// 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)
+{
+	if (mask & GS_PERF_ERR_SYM_MASK)
+		pc->errs_sym = 0;
+	if (mask & GS_PERF_LINK_RECOVERS_MASK)
+		pc->linkrecovers = 0;
+	if (mask & GS_PERF_LINK_DOWNED_MASK)
+		pc->linkdowned = 0;
+	if (mask & GS_PERF_ERR_RCV_MASK)
+		pc->errs_rcv = 0;
+	if (mask & GS_PERF_ERR_PHYSRCV_MASK)
+		pc->errs_remphysrcv = 0;
+	if (mask & GS_PERF_ERR_SWITCH_REL_MASK)
+		pc->errs_rcvswitchrelay = 0;
+	if (mask & GS_PERF_XMT_DISCARDS_MASK)
+		pc->xmitdiscards = 0;
+	if (mask & GS_PERF_ERR_XMTCONSTR_MASK)
+		pc->errs_xmtconstraint = 0;
+	if (mask & GS_PERF_ERR_RCVCONSTR_MASK)
+		pc->errs_rcvconstraint = 0;
+	if (mask & GS_PERF_ERR_LOCALINTEG_MASK)
+		pc->errs_localinteg = 0;
+	if (mask & GS_PERF_ERR_EXCESS_OVR_MASK)
+		pc->errs_excessbufovrrun = 0;
+	if (mask & GS_PERF_VL15_DROPPED_MASK)
+		pc->vl15dropped = 0;
+	if (mask & GS_PERF_XMT_BYTES_MASK)
+		pc->flow_xmt_bytes = 0;
+	if (mask & GS_PERF_RCV_BYTES_MASK)
+		pc->flow_rcv_bytes = 0;
+	if (mask & GS_PERF_XMT_PKTS_MASK)
+		pc->flow_xmt_pkts = 0;
+	if (mask & GS_PERF_RCV_PKTS_MASK)
+		pc->flow_rcv_pkts = 0;
+}
+
+static inline uint32_t addval(uint32_t val, uint32_t delta, uint32_t max)
+{
+	uint32_t newval = val + delta;
+
+	return (newval > max || newval < val) ? max : newval;
+}
+
+#define ADDVAL64(val, add) { uint64_t new = val + add; \
+		val = new < val ? 0xffffffffffffffffULL : new ; }
+
+void pc_add_error_xmitdiscards(Port * port)
+{
+	Portcounters *pc = &(port->portcounters);
+
+	pc->xmitdiscards =
+	    addval(pc->xmitdiscards, 1, GS_PERF_XMT_DISCARDS_LIMIT);
+}
+
+void pc_add_error_rcvswitchrelay(Port * port)
+{
+	Portcounters *pc = &(port->portcounters);
+
+	pc->errs_rcvswitchrelay =
+	    addval(pc->errs_rcvswitchrelay, 1, GS_PERF_ERR_SWITCH_REL_LIMIT);
+}
+
+void pc_add_error_errs_rcv(Port * port)
+{
+	Portcounters *pc = &(port->portcounters);
+
+	pc->errs_rcv = addval(pc->errs_rcv, 1, GS_PERF_ERR_RCV_LIMIT);
+}
+
+static int pc_updated(Port ** srcport, Port * destport)
+{
+	Portcounters *srcpc = &((*srcport)->portcounters);
+	Portcounters *destpc = &(destport->portcounters);
+	uint32_t madsize_div_4 = 72;	//real data divided by 4
+
+	if (*srcport != destport) {
+		//PKT get out of port ..
+		srcpc->flow_xmt_pkts =
+		    addval(srcpc->flow_xmt_pkts, 1, GS_PERF_XMT_PKTS_LIMIT);
+		srcpc->flow_xmt_bytes =
+		    addval(srcpc->flow_xmt_bytes, madsize_div_4,
+			   GS_PERF_XMT_BYTES_LIMIT);
+		ADDVAL64(destpc->ext_xmit_data, madsize_div_4);
+		ADDVAL64(destpc->ext_xmit_pkts, 1);
+
+		if (destport->errrate &&
+		    !destport->errattr &&
+		    (random() % 100) < destport->errrate) {
+			pc_add_error_errs_rcv(destport);
+			VERB("drop pkt due error rate %d", destport->errrate);
+			return 0;
+		}
+		//PKT get in to the port ..
+		destpc->flow_rcv_pkts =
+		    addval(destpc->flow_rcv_pkts, 1, GS_PERF_RCV_PKTS_LIMIT);
+		destpc->flow_rcv_bytes =
+		    addval(destpc->flow_rcv_bytes, madsize_div_4,
+			   GS_PERF_RCV_BYTES_LIMIT);
+		ADDVAL64(destpc->ext_recv_data, madsize_div_4);
+		ADDVAL64(destpc->ext_recv_pkts, 1);
+
+		*srcport = destport;
+	}
+	return 1;
+}
+
+static void pc_sum(Portcounters * totals, Portcounters * pc)
+{
+	totals->flow_xmt_pkts =
+	    addval(totals->flow_xmt_pkts, pc->flow_xmt_pkts,
+		   GS_PERF_XMT_PKTS_LIMIT);
+	totals->flow_xmt_bytes =
+	    addval(totals->flow_xmt_bytes, pc->flow_xmt_bytes,
+		   GS_PERF_XMT_BYTES_LIMIT);
+	totals->flow_rcv_pkts =
+	    addval(totals->flow_rcv_pkts, pc->flow_rcv_pkts,
+		   GS_PERF_RCV_PKTS_LIMIT);
+	totals->flow_rcv_bytes =
+	    addval(totals->flow_rcv_bytes, pc->flow_rcv_bytes,
+		   GS_PERF_RCV_BYTES_LIMIT);
+	totals->xmitdiscards =
+	    addval(totals->xmitdiscards, pc->xmitdiscards,
+		   GS_PERF_ERR_XMTCONSTR_LIMIT);
+	totals->vl15dropped =
+	    addval(totals->vl15dropped, pc->vl15dropped,
+		   GS_PERF_VL15_DROPPED_LIMIT);
+	totals->linkrecovers =
+	    addval(totals->linkrecovers, pc->linkrecovers,
+		   GS_PERF_LINK_RECOVERS_LIMIT);
+	totals->linkdowned =
+	    addval(totals->linkdowned, pc->linkdowned,
+		   GS_PERF_LINK_DOWNED_LIMIT);
+	totals->errs_rcv =
+	    addval(totals->errs_rcv, pc->errs_rcv, GS_PERF_ERR_RCV_LIMIT);
+	totals->errs_sym =
+	    addval(totals->errs_sym, pc->errs_sym, GS_PERF_ERR_SYM_LIMIT);
+	totals->errs_localinteg =
+	    addval(totals->errs_localinteg, pc->errs_localinteg,
+		   GS_PERF_ERR_LOCALINTEG_LIMIT);
+	totals->errs_remphysrcv =
+	    addval(totals->errs_remphysrcv, pc->errs_remphysrcv,
+		   GS_PERF_ERR_PHYSRCV_LIMIT);
+	totals->errs_xmtconstraint =
+	    addval(totals->errs_xmtconstraint, pc->errs_xmtconstraint,
+		   GS_PERF_ERR_XMTCONSTR_LIMIT);
+	totals->errs_rcvconstraint =
+	    addval(totals->errs_rcvconstraint, pc->errs_rcvconstraint,
+		   GS_PERF_ERR_RCVCONSTR_LIMIT);
+	totals->errs_rcvswitchrelay =
+	    addval(totals->errs_rcvswitchrelay, pc->errs_rcvswitchrelay,
+		   GS_PERF_ERR_SWITCH_REL_LIMIT);
+	totals->errs_excessbufovrrun =
+	    addval(totals->errs_excessbufovrrun, pc->errs_excessbufovrrun,
+		   GS_PERF_ERR_EXCESS_OVR_LIMIT);
+}
+
+static void pc_get(Portcounters * pc, uint8_t * data)
+{
+	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);
+	mad_set_field(data, 0, IB_PC_RCV_BYTES_F, pc->flow_rcv_bytes);
+	mad_set_field(data, 0, IB_PC_XMT_DISCARDS_F, pc->xmitdiscards);
+	mad_set_field(data, 0, IB_PC_VL15_DROPPED_F, pc->vl15dropped);
+	mad_set_field(data, 0, IB_PC_LINK_RECOVERS_F, pc->linkrecovers);
+	mad_set_field(data, 0, IB_PC_LINK_DOWNED_F, pc->linkdowned);
+	mad_set_field(data, 0, IB_PC_ERR_RCV_F, pc->errs_rcv);
+	mad_set_field(data, 0, IB_PC_ERR_SYM_F, pc->errs_sym);
+	mad_set_field(data, 0, IB_PC_ERR_LOCALINTEG_F, pc->errs_localinteg);
+	mad_set_field(data, 0, IB_PC_ERR_PHYSRCV_F, pc->errs_remphysrcv);
+	mad_set_field(data, 0, IB_PC_ERR_XMTCONSTR_F, pc->errs_xmtconstraint);
+	mad_set_field(data, 0, IB_PC_ERR_RCVCONSTR_F, pc->errs_rcvconstraint);
+	mad_set_field(data, 0, IB_PC_ERR_SWITCH_REL_F, pc->errs_rcvswitchrelay);
+	mad_set_field(data, 0, IB_PC_ERR_EXCESS_OVR_F,
+		      pc->errs_excessbufovrrun);
+}
+
+static int do_portcounters(Port * port, unsigned op, uint32_t unused,
+			   uint8_t * data)
+{
+	Node *node = port->node;
+	int portnum = mad_get_field(data, 0, IB_PC_PORT_SELECT_F);
+	Portcounters totals;
+	uint mask;
+	Port *p;
+	int i;
+
+	if (node->type != SWITCH_NODE && portnum != port->portnum)
+		return ERR_BAD_PARAM;	//undef_behav.
+
+	if (node->type == SWITCH_NODE && portnum > node->numports
+	    && portnum != 0xff)
+		return ERR_BAD_PARAM;
+
+	DEBUG("in node %" PRIx64 " port %" PRIx64 " portnum %d",
+	      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(&p->portcounters, mask);
+
+		pc_get(&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(&p->portcounters, mask);
+
+		pc_sum(&totals, &p->portcounters);
+	}
+
+	pc_get(&totals, data);
+	return 0;
+}
+
+static void pc_ext_sum(Portcounters * total, Portcounters * pc)
+{
+	ADDVAL64(total->ext_xmit_data, pc->ext_xmit_data);
+	ADDVAL64(total->ext_recv_data, pc->ext_recv_data);
+	ADDVAL64(total->ext_xmit_pkts, pc->ext_xmit_pkts);
+	ADDVAL64(total->ext_recv_pkts, pc->ext_recv_pkts);
+	ADDVAL64(total->ext_ucast_xmit, pc->ext_ucast_xmit);
+	ADDVAL64(total->ext_ucast_recv, pc->ext_ucast_recv);
+	ADDVAL64(total->ext_mcast_xmit, pc->ext_mcast_xmit);
+	ADDVAL64(total->ext_mcast_recv, pc->ext_mcast_recv);
+}
+
+static void pc_ext_reset(Portcounters * pc, uint mask)
+{
+	if (mask & GS_PC_EXT_XMIT_DATA)
+		pc->ext_xmit_data = 0;
+	if (mask & GS_PC_EXT_RECV_DATA)
+		pc->ext_recv_data = 0;
+	if (mask & GS_PC_EXT_XMIT_PKTS)
+		pc->ext_xmit_pkts = 0;
+	if (mask & GS_PC_EXT_RECV_PKTS)
+		pc->ext_xmit_pkts = 0;
+	if (mask & GS_PC_EXT_UCAST_XMIT)
+		pc->ext_ucast_xmit = 0;
+	if (mask & GS_PC_EXT_UCAST_RECV)
+		pc->ext_ucast_recv = 0;
+	if (mask & GS_PC_EXT_MCAST_XMIT)
+		pc->ext_mcast_xmit = 0;
+	if (mask & GS_PC_EXT_MCAST_RECV)
+		pc->ext_mcast_recv = 0;
+}
+
+static void pc_ext_get(Portcounters * pc, uint8_t * data)
+{
+	mad_set_field64(data, 0, IB_PC_EXT_XMT_BYTES_F, pc->ext_xmit_data);
+	mad_set_field64(data, 0, IB_PC_EXT_RCV_BYTES_F, pc->ext_recv_data);
+	mad_set_field64(data, 0, IB_PC_EXT_XMT_PKTS_F, pc->ext_xmit_pkts);
+	mad_set_field64(data, 0, IB_PC_EXT_RCV_PKTS_F, pc->ext_recv_pkts);
+	mad_set_field64(data, 0, IB_PC_EXT_XMT_UPKTS_F, pc->ext_ucast_xmit);
+	mad_set_field64(data, 0, IB_PC_EXT_RCV_UPKTS_F, pc->ext_ucast_recv);
+	mad_set_field64(data, 0, IB_PC_EXT_XMT_MPKTS_F, pc->ext_mcast_xmit);
+	mad_set_field64(data, 0, IB_PC_EXT_RCV_MPKTS_F, pc->ext_mcast_recv);
+}
+
+static int
+do_extcounters(Port * port, unsigned op, uint32_t unused, uint8_t * data)
+{
+	Node *node = port->node;
+	unsigned portnum;
+	Portcounters totals;
+	unsigned mask;
+	Port *p;
+	int i;
+
+	portnum = mad_get_field(data, 0, IB_PC_EXT_PORT_SELECT_F);
+	if (node->type != SWITCH_NODE && portnum != port->portnum)
+		return ERR_BAD_PARAM;	//undef_behav.
+
+	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_EXT_COUNTER_SELECT_F);
+
+	if (portnum != 0xff) {
+		if (!(p = node_get_port(node, portnum)))
+			return ERR_BAD_PARAM;
+		if (op == IB_MAD_METHOD_SET)
+			pc_ext_reset(&p->portcounters, mask);
+		pc_ext_get(&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_ext_reset(&p->portcounters, mask);
+		pc_ext_sum(&totals, &p->portcounters);
+	}
+
+	pc_ext_get(&totals, data);
+	return 0;
+}
+
+static char *pathstr(int lid, ib_dr_path_t * path)
+{
+	static char buf[1024] = "local";
+	unsigned n = 0;
+	int i;
+
+	if (0 && lid != -1) {
+		sprintf(buf, "lid 0x%x", lid);
+		return buf;
+	}
+	for (i = 0; i < path->cnt + 1; i++) {
+		if (i == 0)
+			n += snprintf(buf + n, sizeof(buf) - n, "%d", path->p[i]);
+		else
+			n += snprintf(buf + n, sizeof(buf) - n, ",%d", path->p[i]);
+		if (n >= sizeof(buf))
+			break;
+	}
+
+	return buf;
+}
+
+static int switch_lookup(Node * node, int lid)
+{
+	int outport;
+
+	DEBUG("node 0x%" PRIx64 " lid %d", 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);
+		return -1;
+	}
+
+	return outport;
+}
+
+static int port_get_remote(Port * port, Node ** remotenode, Port ** remoteport)
+{
+	if (!port->remotenode)
+		return -1;
+	*remotenode = port->remotenode;
+	if (!(*remoteport = node_get_port(*remotenode, port->remoteport)))
+		return -1;
+
+	return 0;
+}
+
+static int is_port_lid(Port * port, int lid)
+{
+	DEBUG("port 0x%" PRIx64 " lid %d lmc %d target lid %d",
+	      port->portguid, port->lid, port->lmc, lid);
+	if (lid < port->lid || lid > port->lid + (1 << port->lmc) - 1)
+		return 0;
+	return 1;
+}
+
+static int link_valid(Port * port)
+{
+	Node *node = port->node;
+
+	if (port->physstate != 5) {	// LinkUP ?
+		DEBUG("port %d (link) in not UP (%d)(node %s ports %d)",
+		      port->portnum, port->physstate,
+		      node->nodeid, node->numports);
+		return 0;
+	}
+	if (port->state != 4) {	// Active ?
+		DEBUG("port 0x%" PRIx64
+		      " %d in not Active (%d)(node %s ports %d)",
+		      port->portguid, port->portnum, port->state, node->nodeid,
+		      node->numports);
+		return 0;
+	}
+
+	return 1;
+}
+
+static Port *lid_route_MAD(Port * port, int lid)
+{
+	int hop, portnum;
+	Node *node = port->node;
+	Port *tport = port;
+
+	DEBUG("Node %" PRIx64 " port %" PRIx64 " (%d) lid %d",
+	      node->nodeguid, port->portguid, port->portnum, lid);
+
+	if (lid == 0) {
+		IBWARN("invalid lid 0");
+		return 0;
+	}
+
+	if (is_port_lid(port, lid))
+		return port;
+
+	if (node->type != SWITCH_NODE && port_get_remote(port, &node, &port) < 0) {
+		pc_add_error_xmitdiscards(port);
+		IBWARN("failed: disconnected node 0x%" PRIx64 " or port 0x%"
+		       PRIx64 "?", node->nodeguid, port->portguid);
+		return 0;
+	}
+
+	if (!pc_updated(&tport, port))	// if Client connected via HCA ...
+		return 0;
+
+	for (hop = 0; !is_port_lid(port, lid) && hop < MAXHOPS; hop++) {
+		portnum = switch_lookup(node, lid);
+
+		if (portnum < 0 || portnum > node->numports) {
+			pc_add_error_rcvswitchrelay(port);
+			DEBUG("illegal lid %d (outport %d node %s ports %d)",
+			      lid, portnum, node->nodeid, node->numports);
+			return 0;
+		}
+
+		DEBUG("node %" PRIx64 " outport %d", node->nodeguid, portnum);
+		port = node_get_port(node, portnum);	// out port
+
+		if (!port)
+			IBPANIC("no out port");
+
+		DEBUG("outport 0x%" PRIx64 " (%d)", port->portguid,
+		      port->portnum);
+
+		if (!link_valid(port)) {
+			pc_add_error_xmitdiscards(port);
+			return 0;
+		}
+
+		tport = port;	// prepare to pass PKT to next port
+
+		if (is_port_lid(port, lid))
+			break;	// must be SMA port
+
+		if (port_get_remote(port, &node, &port) < 0) {
+			pc_add_error_xmitdiscards(tport);
+			IBWARN("no remote");
+			return 0;
+		}
+
+		if (!node || !port)	// double check ?...
+			IBPANIC("bad node %p or port %p", node, port);
+
+		if (!link_valid(port)) {
+			pc_add_error_xmitdiscards(tport);
+			return 0;
+		}
+
+		if (!pc_updated(&tport, port))	//try to transmit PKT
+			return 0;
+	}
+
+	DEBUG("routed to node %s port 0x%" PRIx64 " portnum %d (%p)",
+	      node->nodeid, port->portguid, port->portnum, port);
+	return port;
+}
+
+static Port *next_port(Node * node, Port * port, unsigned portnum)
+{
+	Port *tport;
+	if (node->type != SWITCH_NODE && portnum)
+		portnum--;
+	if (portnum > node->numports) {
+		pc_add_error_rcvswitchrelay(port);
+		DEBUG("illegal port %d (node %s ports %d)",
+		      portnum, node->nodeid, node->numports);
+		return NULL;
+	}
+	port = ports + node->portsbase + portnum;
+	tport = port;		// prepare to pass PKT to next port
+
+	if (port->physstate != 5) {	// LinkUP ?
+		pc_add_error_xmitdiscards(port);
+		DEBUG("port %d (link) in not UP (%d)(node %s ports %d)",
+		      port->portnum, port->physstate,
+		      node->nodeid, node->numports);
+		return NULL;
+	}
+
+	node = port->remotenode;
+	portnum = port->remoteport;
+
+	if (!node)
+		return port;	/* SMA port */
+
+	if (portnum > node->numports) {
+		IBPANIC("bad remote port %d in node \"%s\" connected "
+			"to node \"%s\" port %d",
+			portnum, node->nodeid,
+			port->node->nodeid, port->portnum);
+		return NULL;
+	}
+	if (node->type != SWITCH_NODE)
+		portnum--;	// hca or rtr first port is 1
+
+	port = ports + node->portsbase + portnum;
+
+	if (port->physstate != 5) {	// LinkUP ?
+		pc_add_error_xmitdiscards(tport);
+		pc_add_error_errs_rcv(port);
+		DEBUG("remote port %d (link) in not UP (%d)(node %s ports %d)",
+		      port->portnum, port->physstate,
+		      node->nodeid, node->numports);
+		return NULL;
+	}
+
+	if (!pc_updated(&tport, port))	//try to transmit PKT
+		return NULL;
+
+	return port;
+}
+
+static Port *direct_route_in_MAD(Port * port, ib_dr_path_t * path)
+{
+	unsigned ptr;
+
+	DEBUG("route_in: path %s hops %d", pathstr(0, path), path->cnt);
+
+	for (ptr = path->cnt; ptr; ptr--) {
+		if (ptr < path->cnt && port->node->type != SWITCH_NODE)
+			return NULL;
+		port = next_port(port->node, port, path->p[ptr]);
+		if (!port)
+			return NULL;
+	}
+
+	DEBUG("routed in to node %s port %d (%p)",
+	      port->node->nodeid, port->portnum, port);
+
+	return port;
+}
+
+static Port *direct_route_out_MAD(Port * port, ib_dr_path_t * path)
+{
+	unsigned ptr = 0;
+
+	DEBUG("route_out: path %s hops %d", pathstr(0, path), path->cnt);
+
+	while (ptr < path->cnt) {
+		if (ptr && port->node->type != SWITCH_NODE)
+			return NULL;
+		path->p[ptr++] = port->portnum;
+		port = next_port(port->node, port, path->p[ptr]);
+		if (!port)
+			return NULL;
+	}
+	path->p[ptr++] = port->portnum;
+
+	DEBUG("routed out to node %s port %d (%p) return path %s",
+	      port->node->nodeid, port->portnum, port, pathstr(0, path));
+
+	return port;
+}
+
+static Port *route_MAD(Port * port, int response, int lid, ib_dr_path_t * path)
+{
+	if (lid >= 0 && lid < 0xffff)
+		return lid_route_MAD(port, lid);
+
+	return response ? direct_route_in_MAD(port, path) :
+	    direct_route_out_MAD(port, path);
+}
+
+int modified;
+
+Smpfn *get_handle_fn(ib_rpc_t rpc, int response)
+{
+	Smpfn *fn;
+
+	if (response)
+		return 0;
+
+	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 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 fn;
+	}
+
+	return 0;		// No MGTCLASS matched.
+}
+
+int process_packet(Client * cl, void *p, int size, Client ** dcl)
+{
+	struct sim_request *r = p;
+	Port *port;
+	uint8_t data[256];
+	int status, tlid, tqp;
+	int response;
+	Smpfn *fn;
+	ib_rpc_t rpc = { 0 };
+	ib_dr_path_t path = { 0 };
+
+	*dcl = cl;
+
+	DEBUG("client %d, size %d", cl->id, size);
+	if (size != sizeof(*r)) {
+		IBWARN("bad packet size %d (!= %zu)", size, sizeof(*r));
+		return -1;
+	}
+
+	if (simverb > 2) {
+		xdump(stdout, "--- packet ---\n", r->mad, 256);
+		fflush(stdout);
+	}
+	if ((response = decode_sim_MAD(cl, r, &rpc, &path, data)) < 0)
+		return -1;
+
+	if (rpc.method == 0x7) {
+		IBWARN("got trap repress - drop");
+		*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",
+		       ntohs(r->dlid), pathstr(0, &path));
+		goto _dropped;
+	}
+
+	VERB("packet (attr 0x%x mod 0x%x) reached host %s port %d",
+	     rpc.attr.id, rpc.attr.mod, port->node->nodeid, port->portnum);
+
+	if (!(fn = get_handle_fn(rpc, response))) {
+		if (!
+		    (*dcl =
+		     find_client(port, response, ntohl(r->dqp), rpc.trid))) {
+			IBWARN("no one to handle pkt: class 0x%x, attr 0x%x",
+			       rpc.mgtclass, rpc.attr.id);
+			goto _dropped;
+		}
+		VERB("forward pkt to client %d pid %d attr 0x%x",
+		     (*dcl)->id, (*dcl)->pid, rpc.attr.id);
+		forward_MAD(r->mad, &rpc, &path);
+		return sizeof(*r);	// forward only
+	}
+
+	if (port->errrate && (!port->errattr || port->errattr == rpc.attr.id) &&
+	    (random() % 100) < port->errrate) {
+		VERB("drop pkt due error rate %d", port->errrate);
+		goto _dropped;
+	}
+
+	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;
+	r->dlid = r->slid;
+	r->slid = tlid;
+
+	tqp = r->dqp;
+	r->dqp = r->sqp;
+	r->sqp = tqp;
+
+	r->status = 0;
+
+	port = route_MAD(port, 1, ntohs(r->dlid), &path);
+	if (!port || cl->port->node != port->node) {
+		VERB("PKT roll back did not succeed");
+		goto _dropped;
+	}
+	return sizeof(*r);
+
+  _dropped:
+	r->status = htonl(110);
+	*dcl = cl;
+	return sizeof(*r);
+}
+
+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",
+		     port->lid, port->smlid);
+		return -1;
+	}
+
+	mad_set_field(data, 0, IB_NOTICE_IS_GENERIC_F, 1);	// Generic
+	mad_set_field(data, 0, IB_NOTICE_TYPE_F, 1);	// Urgent
+	mad_set_field(data, 0, IB_NOTICE_PRODUCER_F, 2);	// Switch
+	mad_set_field(data, 0, IB_NOTICE_TRAP_NUMBER_F, 128);	// PortStateChange
+	mad_set_field(data, 0, IB_NOTICE_ISSUER_LID_F, port->lid);
+	mad_set_field(data, 0, IB_NOTICE_TOGGLE_F, 0);
+	mad_set_field(data, 0, IB_NOTICE_COUNT_F, 0);
+	mad_set_field(data, 0, IB_NOTICE_DATA_LID_F, port->lid);
+
+	return 0;
+}
+
+static int encode_trap144(Port * port, char *data)
+{
+	if (!port->lid || !port->smlid) {
+		VERB("switch trap 144 for lid %d with smlid %d",
+		     port->lid, port->smlid);
+		return -1;
+	}
+
+	mad_set_field(data, 0, IB_NOTICE_IS_GENERIC_F, 1);
+	mad_set_field(data, 0, IB_NOTICE_TYPE_F, 4);	// Informational
+	mad_set_field(data, 0, IB_NOTICE_PRODUCER_F, port->node->type);
+	mad_set_field(data, 0, IB_NOTICE_TRAP_NUMBER_F, 144);
+	mad_set_field(data, 0, IB_NOTICE_ISSUER_LID_F, port->lid);
+	mad_set_field(data, 0, IB_NOTICE_TOGGLE_F, 0);
+	mad_set_field(data, 0, IB_NOTICE_COUNT_F, 0);
+	mad_set_field(data, 0, IB_NOTICE_DATA_144_LID_F, port->lid);
+	mad_set_field(data, 0, IB_NOTICE_DATA_144_CAPMASK_F,
+		      mad_get_field(port->portinfo, 0, IB_PORT_CAPMASK_F));
+
+	return 0;
+}
+
+static int encode_trap_header(char *buf)
+{
+	mad_set_field(buf, 0, IB_MAD_CLASSVER_F, 0x1);	// Class
+	mad_set_field(buf, 0, IB_MAD_MGMTCLASS_F, 0x1);	// MgmtClass
+	mad_set_field(buf, 0, IB_MAD_BASEVER_F, 0x1);	// BaseVersion
+	mad_set_field(buf, 0, IB_MAD_METHOD_F, 0x5);	// SubnTrap
+	mad_set_field(buf, 0, IB_MAD_ATTRID_F, 0x2);	// Notice
+
+	return 0;
+}
+
+int send_trap(Port * port, int trapnum)
+{
+	struct sim_request req;
+	Client *cl;
+	int ret, lid = port->lid;
+	char *data = req.mad + 64;	/* data offset */
+	EncodeTrapfn *encode_trapfn = encodetrap[trapnum];
+	Port *destport;
+
+	if (!encode_trapfn) {
+		IBWARN("trap number %d not supported", trapnum);
+		return -1;
+	}
+
+	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);
+		return -1;
+	}
+
+	req.dlid = htons(port->smlid);
+	req.slid = htons(lid);
+	req.sqp = 0;
+	req.dqp = 0;
+	req.status = 0;
+	req.length = htonll(sizeof(req.mad));
+
+	// find SM client
+	cl = find_client(destport, 0, 1, 0);
+
+	if (!cl)
+		return 0;
+
+	if (simverb > 2) {
+		xdump(stdout, "--- packet ---\n", &req, 256);
+		fflush(stdout);
+	}
+
+	do {
+		ret = write(cl->fd, &req, sizeof(req));
+	} while ((errno == EAGAIN) && (ret == -1));
+
+	if (ret == sizeof(req))
+		return 0;
+
+	if (ret < 0 && (errno == ECONNREFUSED || errno == ENOTCONN)) {
+		IBWARN("write: client %u seems to be dead"
+		       " - disconnecting.", cl->id);
+		disconnect_client(cl->id);
+		return -1;
+	}
+
+	IBWARN("write failed: %m - pkt dropped");
+
+	return -1;
+}
diff --git a/ibsim/sim_net.c b/ibsim/sim_net.c
new file mode 100644
index 0000000..ee268e0
--- /dev/null
+++ b/ibsim/sim_net.c
@@ -0,0 +1,1362 @@
+/*
+ * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include <ibsim.h>
+#include "sim.h"
+
+#undef DEBUG
+#define PDEBUG	if (parsedebug) IBWARN
+#define DEBUG	if (simverb || ibdebug) IBWARN
+
+#define MAX_INCLUDE 9
+int inclines[MAX_INCLUDE];
+char *incfiles[MAX_INCLUDE];
+int inclevel;
+
+int parsedebug;
+int simverb;
+
+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, 0x00, 0x0F, 0xF9, 0x00, 0x03, 0x03, 0x01,
+	0x14, 0x52, 0x00, 0x11, 0x10, 0x40, 0x00, 0x08,
+	0x08, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x01, 0x1F, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+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, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x02,
+	0x14, 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,
+};
+
+static const uint8_t swport_down[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x01,
+	0x11, 0x22, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08,
+	0x08, 0x04, 0xE9, 0x40, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+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, 0x00, 0x0F, 0xF9, 0x01, 0x03, 0x03, 0x02,
+	0x14, 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,
+};
+
+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, 0x00, 0x0F, 0xF9, 0x01, 0x03, 0x03, 0x01,
+	0x11, 0x22, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08,
+	0x08, 0x04, 0xE9, 0x10, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x20, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t switchinfo[] = {
+	0xC0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+	0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t swnodeinfo[] = {
+	0x01, 0x01, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0xF1, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08,
+	0xF1, 0x04, 0x00, 0x0D, 0x00, 0x08, 0xA8, 0x7C,
+	0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x08, 0xF1,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t hcanodeinfo[] = {
+	0x01, 0x01, 0x01, 0x02, 0x00, 0x02, 0xC9, 0x00,
+	0x01, 0x13, 0x6E, 0x40, 0x00, 0x02, 0xC9, 0x00,
+	0x01, 0x13, 0x6E, 0x40, 0x00, 0x02, 0xC9, 0x00,
+	0x01, 0x13, 0x6E, 0x41, 0x00, 0x40, 0x5A, 0x44,
+	0x00, 0x00, 0x00, 0xA1, 0x01, 0x00, 0x02, 0xC9,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t default_sl2vl[] = {
+	0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7,
+};
+
+static const struct vlarb default_vlarb_high[] = {
+	{0, 4}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0},
+	{8, 0}, {9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0}, {14, 0},
+};
+
+static const struct vlarb default_vlarb_low[] = {
+	{0, 0}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {5, 4}, {6, 4}, {7, 4},
+	{8, 4}, {9, 4}, {10, 4}, {11, 4}, {12, 4}, {13, 4}, {14, 4},
+};
+
+#define MAXLINE	256
+
+// map is in format "alias at nodeid[portnum]"
+#define ALIASMAPLEN (ALIASLEN+NODEIDLEN+6)
+
+int maxnetnodes = MAXNETNODES;
+int maxnetswitches = MAXNETSWITCHS;
+int maxnetports = MAXNETPORTS;
+int maxlinearcap = MAXLINEARCAP;
+int maxmcastcap = MAXMCASTCAP;
+int maxnetaliases = MAXNETALIASES;
+int ignoreduplicate = 0;
+
+Node *nodes;
+Switch *switches;
+Port *ports;
+Port **lids;
+char (*aliases)[NODEIDLEN + NODEPREFIX + 1];	// aliases map format: "%s@%s"
+
+int netnodes, netswitches, netports, netaliases;
+
+static uint64_t absguids[NODE_TYPES] = { ~0, 0x100000, 0x200000 };
+static uint64_t guids[NODE_TYPES] = { ~0, 0x100000, 0x200000 };
+static char netprefix[NODEPREFIX + 1];
+static int netvendid;
+static int netdevid;
+static uint64_t netsysimgguid;
+static int netwidth = DEFAULT_LINKWIDTH;
+static int netspeed = DEFAULT_LINKSPEED;
+
+const char *node_type_name(unsigned type)
+{
+	switch(type) {
+	case SWITCH_NODE:
+		return "Switch";
+	case HCA_NODE:
+		return "Ca";
+	case ROUTER_NODE:
+		return "Router";
+	default:
+		return "Unknown";
+	}
+}
+
+static int new_ports(Node * node, int portnum, int firstport)
+{
+	int first, i;
+
+	if (netports + portnum > maxnetports) {
+		IBPANIC("no more ports (max %d)", maxnetports);
+		return 0;
+	}
+
+	first = netports;
+
+	netports += portnum;
+
+	for (i = first; i < netports; i++) {
+		ports[i].node = node;
+		ports[i].portnum = firstport++;
+	}
+
+	return first;
+}
+
+static Switch *new_switch(Node * nd, int set_esp0)
+{
+	Switch *sw;
+
+	if (netswitches >= maxnetswitches) {
+		IBPANIC("no more switches (max %d)", maxnetswitches);
+		return 0;
+	}
+
+	sw = switches + netswitches++;
+
+	sw->node = nd;
+	sw->linearcap = maxlinearcap;	// assume identical val for all switches
+	sw->multicastcap = maxmcastcap;	// assume identical val for all switches
+	memcpy(sw->switchinfo, switchinfo, sizeof(sw->switchinfo));
+	mad_set_field(sw->switchinfo, 0, IB_SW_LINEAR_FDB_CAP_F, sw->linearcap);
+	mad_set_field(sw->switchinfo, 0, IB_SW_MCAST_FDB_CAP_F,
+		      sw->multicastcap);
+	if (set_esp0)
+		mad_set_field(sw->switchinfo, 0, IB_SW_ENHANCED_PORT0_F,
+			      set_esp0 > 0);
+	sw->fdb = malloc(maxlinearcap*sizeof(sw->fdb[0]));
+	sw->mfdb = malloc(maxmcastcap*NUMBEROFPORTMASK*sizeof(uint16_t));
+	if (!sw->fdb || !sw->mfdb) {
+		IBPANIC("new_switch: no mem: %m");
+		return NULL;
+	}
+	memset(sw->fdb, 0xff, maxlinearcap*sizeof(sw->fdb[0]));
+	memset(sw->mfdb, 0, maxmcastcap*NUMBEROFPORTMASK*sizeof(uint16_t));
+
+	return sw;
+}
+
+static int new_hca(Node * nd)
+{
+	return 0;
+}
+
+static int build_nodeid(char *nodeid, size_t len, char *base)
+{
+	if (strchr(base, '#') || strchr(base, '@')) {
+		IBWARN("bad nodeid \"%s\": '#' & '@' characters are reserved",
+		       base);
+		return -1;
+	}
+
+	snprintf(nodeid, len, "%s%s%s", netprefix, *netprefix ? "#" : "", base);
+
+	return 0;
+}
+
+static Node *new_node(int type, char *nodename, char *nodedesc, int nodeports)
+{
+	int firstport = 1;
+	char nodeid[NODEIDLEN];
+	Node *nd;
+
+	if (build_nodeid(nodeid, sizeof(nodeid), nodename) < 0)
+		return 0;
+
+	if (find_node(nodeid)) {
+		IBWARN("node id %s already exists", nodeid);
+		return 0;
+	}
+
+	if (netnodes >= maxnetnodes) {
+		IBPANIC("no more nodes (max %d)", maxnetnodes);
+		return 0;
+	}
+
+	if (find_node_by_guid(guids[type])) {
+		IBWARN("node %s guid %" PRIx64 " already exists",
+		       node_type_name(type), guids[type]);
+		return 0;
+	}
+
+	nd = nodes + netnodes++;
+
+	nd->type = type;
+	nd->numports = nodeports;
+	strncpy(nd->nodeid, nodeid, sizeof(nd->nodeid) - 1);
+	strncpy(nd->nodedesc, nodedesc && *nodedesc ? nodedesc : nodeid,
+		sizeof(nd->nodedesc) - 1);
+	nd->sysguid = nd->nodeguid = guids[type];
+	if (type == SWITCH_NODE) {
+		nodeports++;	// port 0 is SMA
+		firstport = 0;
+		memcpy(nd->nodeinfo, swnodeinfo, sizeof(nd->nodeinfo));
+		guids[type]++;	// reserve single guid;
+	} else {
+		memcpy(nd->nodeinfo, hcanodeinfo, sizeof(nd->nodeinfo));
+		guids[type] += nodeports + 1;	// reserve guids;
+	}
+
+	mad_set_field(nd->nodeinfo, 0, IB_NODE_NPORTS_F, nd->numports);
+	mad_set_field(nd->nodeinfo, 0, IB_NODE_VENDORID_F, netvendid);
+	mad_set_field(nd->nodeinfo, 0, IB_NODE_DEVID_F, netdevid);
+
+	mad_encode_field(nd->nodeinfo, IB_NODE_GUID_F, &nd->nodeguid);
+	mad_encode_field(nd->nodeinfo, IB_NODE_PORT_GUID_F, &nd->nodeguid);
+	mad_encode_field(nd->nodeinfo, IB_NODE_SYSTEM_GUID_F,
+			 netsysimgguid ? &netsysimgguid : &nd->nodeguid);
+
+	if ((nd->portsbase = new_ports(nd, nodeports, firstport)) < 0) {
+		IBWARN("can't alloc %d ports for node %s", nodeports,
+		       nd->nodeid);
+		return 0;
+	}
+
+	netvendid = 0;
+	netsysimgguid = 0;
+
+	return nd;
+}
+
+static int parse_node_ports(char *buf)
+{
+	while (*buf && !isdigit(*buf))
+		buf++;
+	return strtoul(buf, 0, 0);
+}
+
+static char *parse_node_id(char *buf, char **rest_buf)
+{
+	char *s, *e = 0;
+
+	if (!(s = strchr(buf, '"')) || !(e = strchr(s + 1, '"'))) {
+		IBWARN("can't find valid id in <%s>", buf);
+		return 0;
+	}
+	*e = 0;
+	if (rest_buf)
+		*rest_buf = e + 1;
+	return s + 1;
+}
+
+static char *parse_node_desc(char *s, char **rest_buf)
+{
+	char *e = NULL;
+
+	*rest_buf = s;
+	s = strchr(s, '#');
+	if (!s)
+		return NULL;
+	while (isspace(*++s))
+		;
+	if (*s == '\"') {
+		s++;
+		if ((e = strchr(s, '\"')))
+			*e++ = '\0';
+	} else if ((e = strstr(s, " enhanced port ")) ||
+	    (e = strstr(s, " base port ")) ||
+	    (e = strstr(s, " lid ")) ||
+	    (e = strstr(s, " lmc ")))
+		*e++ = '\0';
+	*rest_buf = e;
+	return s;
+}
+
+static int is_linkwidth_valid(int width)
+{
+	/* width is 1x 4x 8x 12x */
+	if (width < 1 || width > 15) {
+		IBWARN("bad enabled width %d - should be between 1 to 15",
+		       width);
+		return 0;
+	}
+	return 1;
+}
+
+static int is_linkspeed_valid(int speed)
+{
+	/* speed is 2.5G, 5.0G, or 10.0 G */
+	if (speed < 1 || speed > 7) {
+		IBWARN("bad speed %d - should be between 1 to 7", speed);
+		return 0;
+	}
+	return 1;
+}
+
+static int parse_switch_esp0(char *line)
+{
+	if (strstr(line, "enhanced port 0"))
+		return 1;
+	else if (strstr(line, "base port 0"))
+		return -1;
+	else
+		return 0;
+}
+
+static int parse_port_lid_and_lmc(Port * port, char *line)
+{
+	char *s;
+
+	if ((s = strstr(line, "lid "))) {
+		s += 4;
+		port->lid = strtoul(s, NULL, 0);
+	}
+	if ((s = strstr(line, "lmc "))) {
+		s += 4;
+		port->lmc = strtoul(s, NULL, 0);
+	}
+
+	return 0;
+}
+
+static int parse_port_opt(Port * port, char *opt, char *val)
+{
+	int v;
+
+	switch (*opt) {
+	case 'w':
+		v = strtoul(val, 0, 0);
+		if (!is_linkwidth_valid(v))
+			return -1;
+
+		port->linkwidthena = v;
+		DEBUG("port %p linkwidth enabled set to %d", port,
+		      port->linkwidthena);
+		break;
+	case 's':
+		v = strtoul(val, 0, 0);
+		if (!is_linkspeed_valid(v))
+			return -1;
+
+		port->linkspeedena = v;
+		DEBUG("port %p linkspeed enabled set to %d", port,
+		      port->linkspeedena);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static void init_ports(Node * node, int type, int maxports)
+{
+	Port *port;
+	unsigned ca_pkey_size, sw_pkey_size, size;
+	unsigned i, j;
+
+	ca_pkey_size = mad_get_field(node->nodeinfo, 0,
+				     IB_NODE_PARTITION_CAP_F);
+	if (type == SWITCH_NODE)
+		sw_pkey_size = mad_get_field(node->sw->switchinfo, 0,
+					     IB_SW_PARTITION_ENFORCE_CAP_F);
+
+	for (i = (type == SWITCH_NODE ? 0 : 1); i <= maxports; i++) {
+		port = node_get_port(node, i);
+
+		if (type == SWITCH_NODE)
+			port->portguid = node->nodeguid;
+		else
+			port->portguid = node->nodeguid + i;
+		port->portnum = i;
+		port->linkwidthena = netwidth;
+		port->linkwidth = LINKWIDTH_4x;
+		port->linkspeedena = netspeed;
+		port->linkspeed = LINKSPEED_SDR;
+
+		size = (type == SWITCH_NODE && i) ? sw_pkey_size : ca_pkey_size;
+		if (size) {
+			port->pkey_tbl = calloc(size, sizeof(uint16_t));
+			if (!port->pkey_tbl)
+				IBPANIC("cannot alloc port's pkey table\n");
+			port->pkey_tbl[0] = 0xffff;
+		}
+
+		size = node->sw ? maxports + 1 : 1;
+		port->sl2vl = calloc(size, 8 * sizeof(uint8_t));
+		if (!port->sl2vl) {
+			IBPANIC("cannot alloc port's sl2vl table\n");
+		}
+		for (j = 0; j < size; j++)
+			memcpy(port->sl2vl + 8 * j, default_sl2vl, 8);
+
+		memcpy(port->vlarb_high, default_vlarb_high,
+		       sizeof(port->vlarb_high));
+		memcpy(port->vlarb_low, default_vlarb_low,
+		       sizeof(port->vlarb_low));
+	}
+}
+
+static int build_alias(char *alias, char *base, int check)
+{
+	if (strchr(base, '#') || strchr(base, '@')) {
+		if (!check) {
+			strncpy(alias, base, ALIASLEN);
+			return 0;
+		}
+		IBWARN("bad alias \"%s\": '#' & '@' characters are resereved",
+		       base);
+		return -1;
+	}
+	snprintf(alias, ALIASLEN, "%s@%s", netprefix, base);
+	return 0;
+}
+
+char *map_alias(char *alias)
+{
+	int i;
+	int len = strlen(alias);
+
+	for (i = 0; i < netaliases; i++) {
+		if (strncmp(alias, aliases[i], len))
+			continue;
+		if (aliases[i][len] == '#')
+			return aliases[i] + len + 1;
+	}
+	return 0;
+}
+
+char *expand_name(char *base, char *name, char **portstr)
+{
+	char *s;
+
+	if (!base)
+		return 0;
+
+	if (!strchr(base, '@')) {
+		if (netprefix[0] != 0 && !strchr(base, '#'))
+			snprintf(name, NODEIDLEN, "%s#%s", netprefix, base);
+		else
+			strncpy(name, base, NODEIDLEN - 1);
+		if (portstr)
+			*portstr = NULL;
+		PDEBUG("name %s port %s", name, portstr ? *portstr : 0);
+		return name;
+	}
+
+	snprintf(name, NODEIDLEN, "%s%s", base[0] == '@' ? netprefix : "", base);
+	PDEBUG("alias %s", name);
+
+	if (!(s = map_alias(name)))
+		return 0;
+
+	strncpy(name, s, NODEIDLEN - 1);
+
+	if (portstr) {
+		*portstr = name;
+		strsep(portstr, "[");
+	}
+	PDEBUG("name %s port %s", name, portstr ? *portstr : 0);
+	return name;
+}
+
+static int new_alias(char *alias, Node * node, int portnum)
+{
+	char aliasname[ALIASLEN];
+	char *s;
+
+	PDEBUG("new alias: a %s n %s pn %d", alias, node->nodeid, portnum);
+	if (netaliases >= maxnetaliases) {
+		IBPANIC("max net aliases %d limit exceeded", maxnetaliases);
+		return -1;
+	}
+
+	if (build_alias(aliasname, alias, 1) < 0)
+		return -1;
+
+	if ((s = map_alias(aliasname))) {
+		IBWARN("alias %s is already mapped to %s", aliasname, s);
+		return -1;
+	}
+
+	snprintf(aliases[netaliases], ALIASMAPLEN,
+		 "%s#%s[%d]", aliasname, node->nodeid, portnum);
+	PDEBUG("new alias: %s", aliases[netaliases]);
+	netaliases++;
+	return 0;
+}
+
+static int parse_port(char *line, Node * node, int type, int maxports)
+{
+	char remotenodeid[NODEIDLEN], *sp;
+	int portnum, isalias = 0;
+	Port *port;
+	char *s;
+
+	if (line[0] == '@') {
+		isalias = 1;
+		line++;
+	}
+
+	portnum = atoi(line + 1);
+
+	if (portnum < 0 || portnum > maxports) {
+		IBWARN("bad port num %d: <%s>", portnum, line);
+		return -1;
+	}
+	if (!portnum && line[1] != 0) {
+		IBWARN("bad port: <%s>", line);
+		return -1;
+	}
+
+	port = node_get_port(node, portnum);
+
+	if (type != SWITCH_NODE && !portnum) {
+		IBWARN("Port0 in non switch node <%s>", line);
+		return -1;
+	}
+
+	if (!(s = parse_node_id(line, NULL))) {
+		IBWARN("invalid remote nodeid: <%s>", line);
+		return -1;
+	}
+
+	if (isalias) {
+		if (new_alias(s, node, portnum) < 0)
+			return -1;
+		build_alias(port->alias, s, 1);
+		s += strlen(s) + 1;
+		goto parse_opt;
+	}
+
+	if (strchr(s, '@'))
+		build_alias(port->remotealias, s, 0);
+
+	expand_name(s, remotenodeid, &sp);
+	PDEBUG("remotenodeid %s s %s sp %s", remotenodeid, s, sp);
+
+	s += strlen(s) + 1;
+	if (!sp && *s == '[')
+		sp = s + 1;
+
+	strncpy(port->remotenodeid, remotenodeid,
+		sizeof(port->remotenodeid) - 1);
+	if (!sp) {
+		port->remoteport = 1;	// default
+		goto parse_opt;
+	}
+	if ((port->remoteport = atoi(sp)) <= 0) {
+		IBWARN("invalid remote portnum %d: <%s>", port->remoteport, sp);
+		port->remoteport = 0;	// no remote
+		return -1;
+	}
+      parse_opt:
+	line = s;
+	while (s && (s = strchr(s + 1, '='))) {
+		char *opt = s;
+		while (opt && !isalpha(*opt))
+			opt--;
+		if (!opt || parse_port_opt(port, opt, s + 1) < 0) {
+			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");
+		return -1;
+	}
+	return 1;
+}
+
+static int parse_ports(int fd, Node * node, int type, int maxports)
+{
+	char line[MAXLINE], *s;
+	int lines = 0, portnum, r;
+
+	init_ports(node, type, maxports);
+
+	for (lines = 0, portnum = maxports; portnum; lines++) {
+		if (!readline(fd, line, sizeof(line) - 1))
+			return lines;	// EOF - check errno?
+
+		if ((s = strchr(line, '\n')))
+			*s = 0;
+
+		if (line[0] == '#')	// comment line
+			continue;
+
+		if (line[0] != '[' && line[0] != '@')	// end of record
+			return lines;
+
+		if ((r = parse_port(line, node, type, maxports)) > 0) {
+			portnum--;
+			continue;
+		}
+		return -(lines - r);
+	}
+
+	return lines;
+}
+
+static int parse_endnode(int fd, char *line, int type)
+{
+	Node *nd;
+	char *nodeid;
+	char *nodedesc;
+	int ports, r;
+
+	if (!(ports = parse_node_ports(line + 3)) ||
+	    !(nodeid = parse_node_id(line, &line)))
+		return 0;
+
+	nodedesc = parse_node_desc(line, &line);
+
+	if (!(nd = new_node(type, nodeid, nodedesc, ports)))
+		return 0;
+
+	if (new_hca(nd) < 0)
+		return 0;
+
+	r = parse_ports(fd, nd, type, ports);
+
+	PDEBUG("%d ports found", r);
+
+	// return number of lines + 1 for the header line
+	if (r >= 0)
+		return r + 1;
+	return r - 1;
+}
+
+static int parse_switch(int fd, char *line)
+{
+	Node *nd;
+	Switch *sw;
+	Port *port;
+	char *nodeid;
+	char *nodedesc;
+	int nports, r, esp0 = 0;
+
+	if (!(nports = parse_node_ports(line + 6)) ||
+	    !(nodeid = parse_node_id(line, &line)))
+		return 0;
+
+	nodedesc = parse_node_desc(line, &line);
+
+	if (!(nd = new_node(SWITCH_NODE, nodeid, nodedesc, nports)))
+		return 0;
+
+	if (line)
+		esp0 = parse_switch_esp0(line);
+
+	if (!(sw = new_switch(nd, esp0)))
+		return 0;
+
+	nd->sw = sw;
+
+	r = parse_ports(fd, nd, SWITCH_NODE, nports);
+
+	port = node_get_port(nd, 0);
+	if (line && parse_port_lid_and_lmc(port, line) < 0) {
+		IBWARN("cannot parse switch lid, lmc");
+		return -1;
+	}
+	// return number of lines + 1 for the header line
+	PDEBUG("%d ports found", r);
+	if (r >= 0)
+		return r + 1;
+	return r - 1;
+}
+
+static int parse_guidbase(int fd, char *line, int type)
+{
+	uint64_t guidbase;
+	int relative = 0;
+	char *s;
+
+	if (!(s = strchr(line, '=')) && !(s = strchr(line, '+'))) {
+		IBWARN("bad assignment: missing '=|+' sign");
+		return -1;
+	}
+
+	if (*s == '+')
+		relative = 1;
+
+	guidbase = strtoull(s + 1, 0, 0);
+
+	if (!relative) {
+		absguids[type] = guidbase;
+		guidbase = 0;
+	}
+	guids[type] = absguids[type] + guidbase;
+	PDEBUG("new guidbase for %s: base 0x%" PRIx64 " current 0x%" PRIx64,
+	       node_type_name(type), absguids[type],
+	       guids[type]);
+	return 1;
+}
+
+static int parse_vendid(int fd, char *line)
+{
+	char *s;
+
+	if (!(s = strchr(line, '='))) {
+		IBWARN("bad assignment: missing '=' sign");
+		return -1;
+	}
+
+	netvendid = strtol(s + 1, 0, 0);
+
+	return 1;
+}
+
+static int parse_devid(int fd, char *line)
+{
+	char *s;
+
+	if (!(s = strchr(line, '='))) {
+		IBWARN("bad assignment: missing '=' sign");
+		return -1;
+	}
+
+	netdevid = strtol(s + 1, 0, 0);
+
+	return 1;
+}
+
+static uint64_t parse_sysimgguid(int fd, char *line)
+{
+	char *s;
+
+	if (!(s = strchr(line, '='))) {
+		IBWARN("bad assignment: missing '=' sign");
+		return -1;
+	}
+
+	netsysimgguid = strtoull(s + 1, 0, 0);
+
+	return 1;
+}
+
+static int parse_width(int fd, char *line)
+{
+	char *s;
+	int width;
+
+	if (!(s = strchr(line, '='))) {
+		IBWARN("bad assignment: missing '=' sign");
+		return -1;
+	}
+
+	width = strtol(s + 1, 0, 0);
+	if (!is_linkwidth_valid(width)) {
+		IBPANIC("invalid enabled link width %d", width);
+		return -1;
+	}
+
+	netwidth = width;
+	return 1;
+}
+
+static int parse_speed(int fd, char *line)
+{
+	char *s;
+	int speed;
+
+	if (!(s = strchr(line, '='))) {
+		IBWARN("bad assignment: missing '=' sign");
+		return -1;
+	}
+
+	speed = strtol(s + 1, 0, 0);
+	if (!is_linkspeed_valid(speed)) {
+		IBPANIC("invalid enabled link speed %d", speed);
+		return -1;
+	}
+
+	netspeed = speed;
+	return 1;
+}
+
+static int parse_netprefix(int fd, char *line)
+{
+	char *s;
+
+	if (!(s = strchr(line, '='))) {
+		IBWARN("bad assignment: missing '=' sign");
+		return -1;
+	}
+
+	if (!(s = parse_node_id(s + 1, NULL)))
+		return -1;
+
+	if (strlen(s) > NODEPREFIX) {
+		IBWARN("prefix %s too long!", s);
+		return -1;
+	}
+
+	strncpy(netprefix, s, NODEPREFIX);
+	return 1;
+}
+
+static int parse_include(char *line, FILE * out)
+{
+	char *s = line, *fname;
+
+	strsep(&s, "\"");
+	if (s)
+		fname = strsep(&s, "\"");
+	if (!s) {
+		IBWARN("bad include file name");
+		return -1;
+	}
+	if (read_netconf(fname, out) < 0)
+		return -1;
+	return 1;		// only one line is consumed from parent file
+}
+
+static int set_var(char *line, int *var)
+{
+	char *s;
+
+	if (!(s = strchr(line, '='))) {
+		IBWARN("bad assignment: missing '=' sign");
+		return -1;
+	}
+
+	*var = strtol(s + 1, 0, 0);
+	return 1;
+}
+
+static int parse_netconf(int fd, FILE * out)
+{
+	char line[MAXLINE], *s;
+	int r = 1;
+	int lineno = 0;
+
+	do {
+		lineno += r;
+		if (!readline(fd, line, sizeof(line) - 1))
+			return lineno;	// EOF - check errno?
+		if ((s = strchr(line, '\n')))
+			*s = 0;
+		PDEBUG("> parse line: <%s>", line);
+		if (!strncmp(line, "Switch", 6))
+			r = parse_switch(fd, line);
+		else if (!strncmp(line, "Hca", 3) || !strncmp(line, "Ca", 2))
+			r = parse_endnode(fd, line, HCA_NODE);
+		else if (!strncmp(line, "Rt", 2))
+			r = parse_endnode(fd, line, ROUTER_NODE);
+		else if (!strncmp(line, "switchguid", 10))
+			r = parse_guidbase(fd, line, SWITCH_NODE);
+		else if (!strncmp(line, "hcaguids", 8) ||
+			 !strncmp(line, "caguid", 6))
+			r = parse_guidbase(fd, line, HCA_NODE);
+		else if (!strncmp(line, "rtguid", 6))
+			r = parse_guidbase(fd, line, ROUTER_NODE);
+		else if (!strncmp(line, "vendid", 6))
+			r = parse_vendid(fd, line);
+		else if (!strncmp(line, "devid", 5))
+			r = parse_devid(fd, line);
+		else if (!strncmp(line, "sysimgguid", 10))
+			r = parse_sysimgguid(fd, line);
+		else if (!strncmp(line, "width", 5))
+			r = parse_width(fd, line);
+		else if (!strncmp(line, "speed", 5))
+			r = parse_speed(fd, line);
+		else if (!strncmp(line, "module", 6))
+			r = parse_netprefix(fd, line);
+		else if (!strncmp(line, "include", 7))
+			r = parse_include(line, out);
+		else if (!strncmp(line, "pdebug", 6))
+			r = set_var(line, &parsedebug);
+		else if (!strncmp(line, "do", 2))
+			r = do_cmd(line + 2, out) < 0 ? -1 : 1;
+		// else line is ignored
+		else
+			r = 1;
+		PDEBUG("> lines consumed = %d", r);
+	} while (r > 0);
+
+	return -lineno + r;
+}
+
+int read_netconf(char *name, FILE * out)
+{
+	int r, fd;
+
+	incfiles[inclevel] = name;
+	inclines[inclevel] = 0;
+
+	fprintf(out, "parsing: %s\n", name);
+	if ((fd = open(name, O_RDONLY)) < 0) {
+		IBWARN("can't open net configuration file \"%s\": %m", name);
+		return -1;
+	}
+	inclevel++;
+
+	r = parse_netconf(fd, out);
+
+	close(fd);
+	inclevel--;
+
+	if (r < 0) {
+		int i;
+		fprintf(out, "fatal: error at %s: line %d \n",
+			name, inclines[inclevel]);
+		for (i = inclevel - 1; i >= 0; i--)
+			fprintf(out, "\tcalled from %s: line %d \n",
+				incfiles[i], inclines[i]);
+		IBPANIC("parsing failed");
+	}
+	fprintf(out, "%s: parsed %d lines\n", name, inclines[inclevel]);
+	return r;
+}
+
+static int get_active_linkwidth(Port * lport, Port * rport)
+{
+	int width = lport->linkwidthena & rport->linkwidthena;
+
+	if (width & LINKWIDTH_12x)
+		return LINKWIDTH_12x;
+	if (width & LINKWIDTH_8x)
+		return LINKWIDTH_8x;
+	if (width & LINKWIDTH_4x)
+		return LINKWIDTH_4x;
+	if (width & LINKWIDTH_1x)
+		return LINKWIDTH_1x;
+
+	IBPANIC("mismatched enabled width between %" PRIx64 " P#%d W=%d and %"
+		PRIx64 " P#%d W=%d", lport->portguid, lport->portnum,
+		lport->linkwidthena, rport->portguid, rport->portnum,
+		rport->linkwidthena);
+	return 0;
+}
+
+static int get_active_linkspeed(Port * lport, Port * rport)
+{
+	int speed = lport->linkspeedena & rport->linkspeedena;
+
+	if (speed & LINKSPEED_QDR)
+		return LINKSPEED_QDR;
+	if (speed & LINKSPEED_DDR)
+		return LINKSPEED_DDR;
+	if (speed & LINKSPEED_SDR)
+		return LINKSPEED_SDR;
+
+	IBPANIC("mismatched enabled speed between %" PRIx64 " P#%d S=%d and %"
+		PRIx64 " P#%d S=%d", lport->portguid, lport->portnum,
+		lport->linkspeedena, rport->portguid, rport->portnum,
+		rport->linkspeedena);
+	return 0;
+}
+
+void update_portinfo(Port * p)
+{
+	uint8_t *pi = p->portinfo;
+
+	mad_set_field(pi, 0, IB_PORT_LOCAL_PORT_F,
+		      p->node->type == SWITCH_NODE ? 0 : p->portnum);
+	mad_set_field(pi, 0, IB_PORT_LID_F, p->lid);
+	mad_set_field(pi, 0, IB_PORT_SMLID_F, p->smlid);
+	mad_set_field(pi, 0, IB_PORT_OPER_VLS_F, p->op_vls);
+	mad_set_field(pi, 0, IB_PORT_LINK_WIDTH_ENABLED_F, p->linkwidthena);
+	mad_set_field(pi, 0, IB_PORT_LINK_WIDTH_SUPPORTED_F,
+		      LINKWIDTH_1x_4x_12x);
+	mad_set_field(pi, 0, IB_PORT_LINK_WIDTH_ACTIVE_F, p->linkwidth);
+	mad_set_field(pi, 0, IB_PORT_LINK_SPEED_ENABLED_F, p->linkspeedena);
+	mad_set_field(pi, 0, IB_PORT_LINK_SPEED_SUPPORTED_F, LINKSPEED_SDR_DDR);
+	mad_set_field(pi, 0, IB_PORT_LINK_SPEED_ACTIVE_F, p->linkspeed);
+	mad_set_field(pi, 0, IB_PORT_LMC_F, p->lmc);
+	mad_set_field(pi, 0, IB_PORT_HOQ_LIFE_F, p->hoqlife);
+	mad_set_field(pi, 0, IB_PORT_PHYS_STATE_F, p->physstate);
+	mad_set_field(pi, 0, IB_PORT_STATE_F, p->state);
+}
+
+static void set_portinfo(Port * p, const uint8_t portinfo[])
+{
+	memcpy(p->portinfo, portinfo, sizeof(p->portinfo));
+	if (!p->op_vls)
+		p->op_vls = mad_get_field(p->portinfo, 0, IB_PORT_VL_CAP_F);
+}
+
+int link_ports(Port * lport, Port * rport)
+{
+	Node *lnode = lport->node;
+	Node *rnode = rport->node;
+	Port *endport;
+
+	if (lport->remotenode || rport->remotenode)
+		return -1;
+
+	lport->remotenode = rnode;
+	lport->remoteport = rport->portnum;
+	set_portinfo(lport, lnode->type == SWITCH_NODE ? swport : hcaport);
+	memcpy(lport->remotenodeid, rnode->nodeid, sizeof(lport->remotenodeid));
+
+	rport->remotenode = lnode;
+	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->physstate = rport->physstate = 5;	// LinkUP
+	if (lnode->sw)
+		lnode->sw->portchange = 1;
+	if (rnode->sw)
+		rnode->sw->portchange = 1;
+
+	lport->linkwidth = rport->linkwidth =
+	    get_active_linkwidth(lport, rport);
+	lport->linkspeed = rport->linkspeed =
+	    get_active_linkspeed(lport, rport);
+
+	if (lnode->type == SWITCH_NODE) {
+		endport = node_get_port(lnode, 0);
+		send_trap(endport, TRAP_128);
+	}
+
+	if (rnode->type == SWITCH_NODE) {
+		endport = node_get_port(rnode, 0);
+		send_trap(endport, TRAP_128);
+	}
+
+	return 0;
+}
+
+int connect_ports(void)
+{
+	Port *port, *e, *remoteport;
+	Node *remote;
+	int pconnected = 0;
+	int type;
+
+	for (port = ports, e = port + netports; port < e; port++) {
+		PDEBUG
+		    ("process port idx %zu: nodeid \"%s\" remotenodeid \"%s\" remoteport %d",
+		     port - ports, port->node ? port->node->nodeid : "",
+		     port->remotenodeid, port->remoteport);
+		PDEBUG("from node 0x%016" PRIx64 " port 0x%016" PRIx64 " .",
+		       port->node->nodeguid, port->portguid);
+		if (port->remotenode)
+			continue;
+
+		type = port->node->type;
+		if (port->node->type == SWITCH_NODE && port->portnum == 0) {	// SMA
+			set_portinfo(port, smaport);
+			port->state = 4;	// Active
+			port->physstate = 5;	// LinkUP
+			continue;
+		}
+		if (!port->remoteport) {	// unconnected port -> down
+			set_portinfo(port, type == SWITCH_NODE ?
+				     swport_down : hcaport_down);
+			port->state = 1;	// Down
+			port->physstate = 2;	// Polling
+			continue;
+		}
+
+		if (!(remote = find_node(port->remotenodeid))) {
+			IBWARN
+			    ("can't find remote node \"%s\" connected to node \"%s\" port %d",
+			     port->remotenodeid, port->node->nodeid,
+			     port->portnum);
+			return -1;
+		}
+
+		if (port->remoteport > remote->numports) {
+			IBWARN("bad remote port %d in node \"%s\" connected to "
+			       "node \"%s\" port %d",
+			       port->remoteport, port->remotenodeid,
+			       port->node->nodeid, port->portnum);
+			return -1;
+		}
+		remoteport = ports + remote->portsbase + port->remoteport;
+		if (remote->type != SWITCH_NODE)
+			remoteport--;	// hca first port is 1
+
+		if (port->remotealias[0]) {
+			if (strcmp(port->remotealias, remoteport->alias) ||
+			    remoteport->remoteport) {
+				IBWARN("remote alias %s is not %s",
+				       port->remotealias, remoteport->alias);
+				return -1;
+			}
+		} else if (remoteport->remoteport != port->portnum ||
+			   strncmp(remoteport->remotenodeid, port->node->nodeid,
+				   sizeof(remoteport->remotenodeid))) {
+			IBWARN
+			    ("remote port %d in node \"%s\" is not connected to "
+			     "node \"%s\" port %d (\"%s\" %d)",
+			     port->remoteport, port->remotenodeid,
+			     port->node->nodeid, port->portnum,
+			     remoteport->remotenodeid, remoteport->remoteport);
+			return -1;
+		}
+
+		link_ports(port, remoteport);
+		pconnected += 2;
+	}
+
+	DEBUG("%d ports connected", pconnected);
+	return 0;
+}
+
+void reset_port(Port * port)
+{
+	int type = port->node->type;
+
+	if (type == SWITCH_NODE && port->portnum == 0) {	// SMA
+		set_portinfo(port, smaport);
+		port->state = 4;	// Active
+		port->physstate = 5;	// LinkUP
+	} else {
+		set_portinfo(port, type == SWITCH_NODE ?
+			     swport_down : hcaport_down);
+		port->state = 1;	// Down
+		port->physstate = 2;	// Polling
+	}
+
+	port->lid = 0;
+	port->lmc = 0;
+	port->smlid = 0;
+}
+
+int readline(int fd, char *buf, int sz)
+{
+	int i;
+
+	buf[0] = 0;
+
+	for (i = 0; i < sz; i++, buf++)
+		if (read(fd, buf, 1) != 1 || *buf == '\n')
+			break;
+
+	if (*buf == '\n' && sz - i > 0) {
+		buf[1] = 0;
+		i++;
+	} else
+		*buf = 0;
+	if (i)
+		inclines[inclevel > 0 ? inclevel - 1 : 0]++;
+	return i;
+}
+
+Node *find_node(char *desc)
+{
+	Node *nd, *e;
+
+	if (!desc)
+		return 0;
+
+	for (nd = nodes, e = nodes + netnodes; nd < e; nd++)
+		if (!strcmp(desc, nd->nodeid))
+			return nd;
+
+	return 0;
+}
+
+Node *find_node_by_desc(char *desc)
+{
+	Node *nd, *e;
+
+	if (!desc)
+		return 0;
+
+	for (nd = nodes, e = nodes + netnodes; nd < e; nd++)
+		if (!strcmp(desc, nd->nodedesc))
+			return nd;
+
+	return 0;
+}
+
+Node *find_node_by_guid(uint64_t guid)
+{
+	Node *nd, *e;
+
+	if (ignoreduplicate)
+		return 0;
+
+	for (nd = nodes, e = nodes + netnodes; nd < e; nd++)
+		if (nd->nodeguid == guid)
+			return nd;
+
+	return 0;
+}
+
+Port *node_get_port(Node * node, int portnum)
+{
+	Port *port = ports + node->portsbase + portnum;
+
+	if (node->type != SWITCH_NODE && portnum > 0)
+		port--;
+
+	return port;
+}
+
+int set_default_port(char *nodeid)
+{
+	Node *node = NULL;
+
+	if (!netports)
+		return -1;	// no ports are defined in net
+
+	if (nodeid && !(node = find_node(nodeid)))
+		IBWARN("node %s not found - use default port!", nodeid);
+
+	default_port = node ? node_get_port(node, 0) : ports;
+
+	return 0;
+}
+
+int alloc_core(void)
+{
+	if (!(nodes = calloc(maxnetnodes, sizeof(*nodes))))
+		return -1;
+	if (!(switches = calloc(maxnetswitches, sizeof(*switches))))
+		return -1;
+	if (!(ports = calloc(maxnetports, sizeof(*ports))))
+		return -1;
+	if (!(lids = calloc(maxlinearcap, sizeof(*lids))))
+		return -1;
+	if (!(aliases = calloc(maxnetaliases, sizeof(*aliases))))
+		return -1;
+	return 0;
+}
+
+void free_core(void)
+{
+	unsigned i;
+	free(aliases);
+	free(lids);
+	for (i = 0; i < maxnetports ; i++) {
+		if (ports[i].pkey_tbl)
+			free(ports[i].pkey_tbl);
+		if (ports[i].sl2vl)
+			free(ports[i].sl2vl);
+	}
+	free(ports);
+	for (i = 0; i < maxnetswitches ; i++) {
+		if (switches[i].fdb)
+			free(switches[i].fdb);
+		if (switches[i].mfdb)
+			free(switches[i].mfdb);
+	}
+	free(switches);
+	free(nodes);
+}
diff --git a/include/ibsim.h b/include/ibsim.h
new file mode 100644
index 0000000..15fc37c
--- /dev/null
+++ b/include/ibsim.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _IBSIM_H_
+#define _IBSIM_H_
+
+#include <stdint.h>
+
+#include <sys/un.h>
+#include <netinet/in.h>
+
+
+struct sim_vendor {
+	uint32_t vendor_id;	/* Vendor ID */
+	uint32_t vendor_part_id;	/* Vendor Part ID */
+	uint32_t hw_ver;	/* Hardware Version */
+	uint64_t fw_ver;	/* Device's firmware version (device specific) */
+};
+
+struct sim_port {
+	uint16_t lid;		/* Base IB_LID */
+	uint8_t state;		/* Port state */
+};
+
+#define IBSIM_MAX_CLIENTS 10
+
+#define IBSIM_DEFAULT_SERVER_PORT 7070
+#define SIM_BASENAME	"sim"
+
+#define SIM_MAGIC	0xdeadbeef
+#define SIM_CTL_MAX_DATA	64
+
+struct sim_request {
+	uint32_t dlid;
+	uint32_t slid;
+	uint32_t dqp;
+	uint32_t sqp;
+	uint32_t status;
+	uint64_t length;
+	char mad[256];
+};
+
+enum SIM_CTL_TYPES {
+	SIM_CTL_ERROR,		/* reply type */
+	SIM_CTL_CONNECT,
+	SIM_CTL_DISCONNECT,
+	SIM_CTL_GET_PORT,
+	SIM_CTL_GET_VENDOR,
+	SIM_CTL_GET_GID,
+	SIM_CTL_GET_GUID,
+	SIM_CTL_GET_NODEINFO,
+	SIM_CTL_GET_PORTINFO,
+	SIM_CTL_SET_ISSM,
+	SIM_CTL_GET_PKEYS,
+
+	SIM_CTL_LAST
+};
+
+struct sim_ctl {
+	uint32_t magic;
+	uint32_t clientid;
+	uint32_t type;
+	uint32_t len;
+	char data[SIM_CTL_MAX_DATA];
+};
+
+struct sim_client_info {
+	uint32_t id;		/* conn id in call, client id in return */
+	uint32_t qp;
+	uint32_t issm;		/* accept request for qp 0 & 1 */
+	char nodeid[32];
+};
+
+union name_t {
+	struct sockaddr name;
+	struct sockaddr_un name_u;
+	struct sockaddr_in name_i;
+};
+
+#endif				/* _IBSIM_H_ */
diff --git a/net-examples/examples.README b/net-examples/examples.README
new file mode 100644
index 0000000..c559e0b
--- /dev/null
+++ b/net-examples/examples.README
@@ -0,0 +1,10 @@
+As fabric topology description ibsim uses text file in the format
+compatible with ibnetdiscover command output and it can be generated
+using real cluster snapshot. Just like:
+
+  ibnetdiscover > ibnet.out
+
+Some useful extensions (must be at beginning of line) are:
+'include <file-name>' - includes named topology file
+'do <ibsim-command>' - executes ibsim console command during the
+                       topology file parsing
diff --git a/net-examples/net b/net-examples/net
new file mode 100644
index 0000000..60db3b1
--- /dev/null
+++ b/net-examples/net
@@ -0,0 +1,39 @@
+# Net configuation file example
+#
+# The file defines node records as follows:
+# < node header line: >
+# < first connected port >
+# < second connected port >
+# < ... >
+# < last connected port >
+# < newlines (at least one) >
+# < next record ...>
+#
+# The header line format is as follows:
+# type(Switch|Hca)	ports(1-255)	"nodeid"(unique string)
+#
+# The connected port line format is:
+# [localport] "remoteid" [remoteport]
+#
+# Optionally, link width can be supplied by adding 'w=(1|4|12)':
+# [localport] "remoteid" [remoteport]	w=12
+#
+#
+# The first port in the file is used as the SM port.
+#
+
+Switch	8 "Switch1"
+[1]	"Hca1"[1]
+[2]	"Hca2"[2]
+[3]	"Switch2"[3]
+[4]	"Switch2"[4]
+
+Switch 8 "Switch2"
+[3]	"Switch1"[3]
+[4]	"Switch1"[4]
+
+Hca	2 "Hca1"
+[1]	"Switch1"[1]
+
+Hca	2 "Hca2"
+[2]	"Switch1"[2]
diff --git a/net-examples/net.1 b/net-examples/net.1
new file mode 100644
index 0000000..0f16f5e
--- /dev/null
+++ b/net-examples/net.1
@@ -0,0 +1,29 @@
+# Net configuation file example
+#
+# The file defines node records as follows:
+# < node header line: >
+# < first connected port >
+# < second connected port >
+# < ... >
+# < last connected port >
+# < newlines (at least one) >
+# < next record ...>
+#
+# The header line format is as follows:
+# type(Switch|Hca)	ports(1-255)	"nodeid"(unique string)
+#
+# The connected port line format is:
+# [localport] "remoteid" [remoteport]
+#
+# The first port in the file is used as the SM port.
+#
+
+Switch	8 "Switch1"
+[1]	"Hca1"[1]
+[4]	"Hca2"[1]
+
+Hca	2 "Hca1"
+[1]	"Switch1"[1]
+
+Hca	2 "Hca2"
+[1]	"Switch1"[4]
diff --git a/net-examples/net.2sw2path b/net-examples/net.2sw2path
new file mode 100644
index 0000000..1b50973
--- /dev/null
+++ b/net-examples/net.2sw2path
@@ -0,0 +1,35 @@
+# Net configuation file example
+#
+# The file defines node records as follows:
+# < node header line: >
+# < first connected port >
+# < second connected port >
+# < ... >
+# < last connected port >
+# < newlines (at least one) >
+# < next record ...>
+#
+# The header line format is as follows:
+# type(Switch|Hca)	ports(1-255)	"nodeid"(unique string)
+#
+# The connected port line format is:
+# [localport] "remoteid" [remoteport]
+#
+# The first port in the file is used as the SM port.
+#
+
+Switch	8 "Switch1"
+[1]	"Hca1"[1]
+[3]	"Switch2"[3]
+[5]	"Switch2"[5]
+
+Switch 8 "Switch2"
+[1]	"Hca2"[1]
+[3]	"Switch1"[3]
+[5]	"Switch1"[5]
+
+Hca	2 "Hca1"
+[1]	"Switch1"[1]
+
+Hca	2 "Hca2"
+[1]	"Switch2"[1]
diff --git a/net-examples/net.2sw2path4hca b/net-examples/net.2sw2path4hca
new file mode 100644
index 0000000..6aeab73
--- /dev/null
+++ b/net-examples/net.2sw2path4hca
@@ -0,0 +1,43 @@
+# Net configuation file example
+#
+# The file defines node records as follows:
+# < node header line: >
+# < first connected port >
+# < second connected port >
+# < ... >
+# < last connected port >
+# < newlines (at least one) >
+# < next record ...>
+#
+# The header line format is as follows:
+# type(Switch|Hca)	ports(1-255)	"nodeid"(unique string)
+#
+# The connected port line format is:
+# [localport] "remoteid" [remoteport]
+#
+# The first port in the file is used as the SM port.
+#
+
+Switch	8 "Switch1"
+[1]	"Hca1"[1]
+[2]	"Hca3"[1]
+[3]	"Switch2"[3]
+[5]	"Switch2"[5]
+
+Switch 8 "Switch2"
+[1]	"Hca2"[1]
+[2]	"Hca4"[1]
+[3]	"Switch1"[3]
+[5]	"Switch1"[5]
+
+Hca	2 "Hca1"
+[1]	"Switch1"[1]
+
+Hca	2 "Hca2"
+[1]	"Switch2"[1]
+
+Hca	2 "Hca3"
+[1]	"Switch1"[2]
+
+Hca 	2 "Hca4"
+[1]	"Switch2"[2]
diff --git a/net-examples/net.2sw2path4hca2port b/net-examples/net.2sw2path4hca2port
new file mode 100644
index 0000000..b1bc46c
--- /dev/null
+++ b/net-examples/net.2sw2path4hca2port
@@ -0,0 +1,39 @@
+# Net configuation file example
+#
+# The file defines node records as follows:
+# < node header line: >
+# < first connected port >
+# < second connected port >
+# < ... >
+# < last connected port >
+# < newlines (at least one) >
+# < next record ...>
+#
+# The header line format is as follows:
+# type(Switch|Hca)	ports(1-255)	"nodeid"(unique string)
+#
+# The connected port line format is:
+# [localport] "remoteid" [remoteport]
+#
+# The first port in the file is used as the SM port.
+#
+
+Switch	8 "Switch1"
+[1]	"Hca1"[1]
+[2]	"Hca1"[2]
+[3]	"Switch2"[3]
+[5]	"Switch2"[5]
+
+Switch 8 "Switch2"
+[1]	"Hca2"[1]
+[2]	"Hca2"[2]
+[3]	"Switch1"[3]
+[5]	"Switch1"[5]
+
+Hca	2 "Hca1"
+[1]	"Switch1"[1]
+[2]	"Switch1"[2]
+
+Hca	2 "Hca2"
+[1]	"Switch2"[1]
+[2]	"Switch2"[2]
diff --git a/scripts/run_opensm.sh b/scripts/run_opensm.sh
new file mode 100755
index 0000000..a225d81
--- /dev/null
+++ b/scripts/run_opensm.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+if [ "$1" = "-g" ] ; then
+	debug=1
+	shift
+fi
+
+if [ -z "$1" ] ; then
+	cmd=opensm
+	cmd_args="-e -c -V -f ./osm.log -s 0"
+else
+	cmd="$1"
+	shift
+	cmd_args="$*"
+fi
+
+# for example to run OpenSM from Hca1 node of net.2sw2path
+#SIM_HOST="Hca1"
+
+OSM_TMP_DIR=./
+OSM_CACHE_DIR=./
+
+# setup valid libumad2sim.so path here
+# when installed it can be $(libdir)/lib/umad2sim/libumad2sim.so
+umad2sim=`dirname $0`/../umad2sim/libumad2sim.so
+
+
+if [ -z "$debug" ] ; then
+	export SIM_HOST
+	export OSM_TMP_DIR
+	export OSM_CACHE_DIR
+	time LD_PRELOAD=${umad2sim} ${cmd} ${cmd_args}
+	rc=$?
+	exit $rc
+else
+	cmd_file=ibsim-gdb-init
+	test -f ${cmd_file} && mv ${cmd_file} ${cmd_file}-saved
+	echo > ${cmd_file}
+	echo set environment SIM_HOST ${SIM_HOST} >> ${cmd_file}
+	echo set environment OSM_TMP_DIR ${OSM_TMP_DIR} >> ${cmd_file}
+	echo set environment OSM_CACHE_DIR ${OSM_CACHE_DIR} >> ${cmd_file}
+	echo set environment LD_PRELOAD ${umad2sim} >> ${cmd_file}
+	echo handle SIGHUP noprint nostop pass >> ${cmd_file}
+	echo handle SIGUSR1 noprint nostop pass >> ${cmd_file}
+	echo handle SIGTERM print stop pass >> ${cmd_file}
+	#echo break sim_client_init >> ${cmd_file}
+	echo break main >> ${cmd_file}
+	echo run ${cmd_args} >> ${cmd_file}
+	gdb --command=${cmd_file} ${cmd}
+fi
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..dd4cd55
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1,7 @@
+progs:= mcast_storm
+
+-include ../defs.mk
+
+all: $(progs)
+
+$(progs): %: %.o
diff --git a/tests/get_all_ca_port_guids.sh b/tests/get_all_ca_port_guids.sh
new file mode 100755
index 0000000..de1536a
--- /dev/null
+++ b/tests/get_all_ca_port_guids.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+ibnetdiscover \
+| sed -ne 's/^\[[1-9]\](\([a-f|0-9]\+\)).*$/0x\1/p'
diff --git a/tests/mcast_storm.c b/tests/mcast_storm.c
new file mode 100644
index 0000000..b2bf19a
--- /dev/null
+++ b/tests/mcast_storm.c
@@ -0,0 +1,746 @@
+/*
+ * Copyright (c) 2006-2008 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 <ctype.h>
+#include <getopt.h>
+
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#define info(fmt, arg...) fprintf(stderr, "INFO: " fmt, ##arg )
+#define err(fmt, arg...) fprintf(stderr, "ERR: " fmt, ##arg )
+#ifdef NOISY_DEBUG
+#define dbg(fmt, arg...) fprintf(stderr, "DBG: " fmt, ##arg )
+#else
+#define dbg(fmt, arg...)
+#endif
+
+#define TMO 100
+
+#define DEFAULT_PREFIX 0xfe80000000000000ULL
+
+/* Multicast Member Record Component Masks */
+#define IB_MCR_COMPMASK_MGID        (1ULL<<0)
+#define IB_MCR_COMPMASK_PORT_GID    (1ULL<<1)
+#define IB_MCR_COMPMASK_QKEY        (1ULL<<2)
+#define IB_MCR_COMPMASK_MLID        (1ULL<<3)
+#define IB_MCR_COMPMASK_MTU_SEL     (1ULL<<4)
+#define IB_MCR_COMPMASK_MTU         (1ULL<<5)
+#define IB_MCR_COMPMASK_TCLASS      (1ULL<<6)
+#define IB_MCR_COMPMASK_PKEY        (1ULL<<7)
+#define IB_MCR_COMPMASK_RATE_SEL    (1ULL<<8)
+#define IB_MCR_COMPMASK_RATE        (1ULL<<9)
+#define IB_MCR_COMPMASK_LIFE_SEL    (1ULL<<10)
+#define IB_MCR_COMPMASK_LIFE        (1ULL<<11)
+#define IB_MCR_COMPMASK_SL          (1ULL<<12)
+#define IB_MCR_COMPMASK_FLOW        (1ULL<<13)
+#define IB_MCR_COMPMASK_HOP         (1ULL<<14)
+#define IB_MCR_COMPMASK_SCOPE       (1ULL<<15)
+#define IB_MCR_COMPMASK_JOIN_STATE  (1ULL<<16)
+#define IB_MCR_COMPMASK_PROXY       (1ULL<<17)
+
+struct addr_data {
+	int port;
+	int agent;
+	int timeout;
+	ib_portid_t dport;
+};
+
+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)
+{
+	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;
+}
+
+uint64_t build_mcm_create_rec(uint8_t * data, ibmad_gid_t mgid,
+			      ibmad_gid_t port_gid, uint8_t join_state)
+{
+	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;
+}
+
+static void build_mcm_rec_umad(void *umad, ib_portid_t * dport, int method,
+			       uint64_t comp_mask, uint8_t * data)
+{
+	ib_rpc_t rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.mgtclass = IB_SA_CLASS;
+	rpc.method = method;
+	rpc.attr.id = IB_SA_ATTR_MCRECORD;
+	rpc.attr.mod = 0;	// ???
+	rpc.mask = comp_mask;
+	rpc.datasz = IB_SA_DATA_SIZE;
+	rpc.dataoffs = IB_SA_DATA_OFFS;
+
+	mad_build_pkt(umad, &rpc, dport, NULL, data);
+}
+
+static uint64_t get_guid_ho(ibmad_gid_t gid)
+{
+	uint64_t guid;
+	memcpy(&guid, &gid[8], sizeof(guid));
+	return ntohll(guid);
+}
+
+static int send_req(struct addr_data *a, uint8_t * umad, int len,
+		    int method, uint64_t comp_mask, uint8_t data[])
+{
+	build_mcm_rec_umad(umad, &a->dport, method, comp_mask, data);
+	if (umad_send(a->port, a->agent, umad, len, a->timeout, 0) < 0) {
+		err("umad_send method %u, tid 0x%016" PRIx64 "failed: %s\n",
+		    method,
+		    mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F),
+		    strerror(errno));
+		return -1;
+	}
+	dbg("umad_send %d: tid = 0x%016" PRIx64 "\n", method,
+	    mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F));
+
+	return 0;
+}
+
+static int recv_res(struct addr_data *a, uint8_t * umad, int length)
+{
+	int ret, retry = 0;
+	int len = length;
+
+	while ((ret = umad_recv(a->port, umad, &len, a->timeout)) < 0 &&
+	       errno == ETIMEDOUT) {
+		if (retry++ > 3)
+			return 0;
+	}
+	if (ret < 0) {
+		err("umad_recv %d failed: %s\n", ret, strerror(errno));
+		return -1;
+	}
+	dbg("umad_recv (retries %d), tid = 0x%016" PRIx64
+	    ": len = %d, status = %d\n", retry,
+	    mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F), len,
+	    umad_status(umad));
+
+	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)
+{
+	uint8_t data[IB_SA_DATA_SIZE];
+	uint64_t comp_mask;
+
+	comp_mask = build_mcm_rec(data, mgid, port_gid, 1);
+
+	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)
+{
+	uint8_t data[IB_SA_DATA_SIZE];
+	uint64_t comp_mask;
+
+	comp_mask = build_mcm_rec(data, mgid, port_gid, 1);
+
+	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)
+{
+	uint8_t data[IB_SA_DATA_SIZE];
+	uint64_t comp_mask;
+
+	comp_mask = build_mcm_rec(data, mgid, port_gid, 1);
+
+	return send_req(a, umad, len, IB_MAD_METHOD_GET, comp_mask, data);
+}
+
+struct gid_list {
+	ibmad_gid_t gid;
+	uint64_t trid;
+};
+
+static int recv_all(struct addr_data *a, void *umad, int len)
+{
+	uint8_t *mad;
+	uint64_t trid;
+	unsigned n, method, status;
+
+	info("%s...\n", __func__);
+
+	n = 0;
+	while (recv_res(a, umad, len) > 0) {
+		dbg("%s: done %d\n", __func__, n);
+		n++;
+		mad = umad_get_mad(umad);
+
+		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)) {
+			trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
+			info("mad trid 0x%016" PRIx64
+			     ": method = %x status = %x.\n",
+			     trid, method, status);
+		}
+	}
+
+	info("%s: got %u responses\n", __func__, n);
+
+	return 0;
+}
+
+static int rereg_port(struct addr_data *a, uint8_t * umad, int len,
+		      ibmad_gid_t mgid, struct gid_list *list)
+{
+	if (send_leave(a, umad, len, mgid, list->gid))
+		return -1;
+
+	if (send_join(a, umad, len, mgid, list->gid))
+		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);
+
+	return 0;
+}
+
+static int rereg_recv_all(struct addr_data *a, ibmad_gid_t mgid,
+			  struct gid_list *list, unsigned cnt)
+{
+	uint8_t *umad, *mad;
+	int len = 256;
+	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);
+		n++;
+		mad = umad_get_mad(umad);
+
+		method = mad_get_field(mad, 0, IB_MAD_METHOD_F);
+		status = mad_get_field(mad, 0, IB_MAD_STATUS_F);
+
+		if (status)
+			dbg("MAD status %x, method %x\n", status, method);
+
+		if (status &&
+		    (method & 0x7f) == (IB_MAD_METHOD_GET_RESPONSE & 0x7f)) {
+			trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
+			for (i = 0; i < cnt; i++)
+				if (trid == list[i].trid)
+					break;
+			if (i == cnt) {
+				err("cannot find trid 0x%016" PRIx64
+				    ", status %x\n", trid, status);
+				continue;
+			}
+			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]);
+		}
+	}
+
+	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)
+{
+	uint8_t *umad, *mad;
+	int len = 256;
+	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);
+		if (ret < 0) {
+			err("%s: rereg_send failed.\n", __func__);
+			continue;
+		}
+
+		ret = recv_res(a, umad, len);
+		if (ret < 0) {
+			err("%s: recv_res failed.\n", __func__);
+			continue;
+		}
+
+		mad = umad_get_mad(umad);
+
+		method = mad_get_field(mad, 0, IB_MAD_METHOD_F);
+		status = mad_get_field(mad, 0, IB_MAD_STATUS_F);
+
+		if (status)
+			info("guid 0x%016" PRIx64 ": status %x, method %x\n",
+			     get_guid_ho(list[i].gid), status, method);
+	}
+
+	info("%s: %u queried.\n", __func__, cnt);
+
+	free(umad);
+	return 0;
+}
+
+/* tests framework */
+
+struct test_data {
+	unsigned gids_size;
+	struct gid_list *gids;
+	unsigned mgids_size;
+	struct gid_list *mgids;
+};
+
+#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 *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;
+	}
+
+	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 (recv_all(a, umad, len) < 0)
+		return -1;
+
+	free(umad);
+
+	return 0;
+}
+
+static int run_mcast_leave_test(struct addr_data *a, struct test_data *td)
+{
+	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;
+	}
+
+	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))
+				return -1;
+
+	if (recv_all(a, umad, len) < 0)
+		return -1;
+
+	free(umad);
+
+	return 0;
+}
+
+/* main stuff */
+
+struct test {
+	const char *name;
+	int (*func)(struct addr_data *, struct test_data *);
+	const char *description;
+};
+
+static int run_test(const struct test *t, struct test_data *td)
+{
+	struct addr_data addr;
+	int ret;
+
+	info("Running \'%s\'...\n", t->name);
+
+	ib_resolve_smlid(&addr.dport, TMO);
+	if (!addr.dport.lid) {
+		/* dport.lid = 1; */
+		err("No SM. Exit.\n");
+		exit(1);
+	}
+	addr.dport.qp = 1;
+	if (!addr.dport.qkey)
+		addr.dport.qkey = IB_DEFAULT_QP1_QKEY;
+
+	addr.port = madrpc_portid();
+	addr.agent = umad_register(addr.port, IB_SA_CLASS, 2, 0, NULL);
+	addr.timeout = TMO;
+
+	ret = t->func(&addr, td);
+
+	umad_unregister(addr.port, addr.agent);
+	umad_close_port(addr.port);
+	umad_done();
+
+	info("\'%s\' %s.\n", t->name, ret ? "failed" : "is done");
+
+	return ret;
+}
+
+static void make_gid(ibmad_gid_t gid, uint64_t prefix, uint64_t guid)
+{
+	prefix = ntohll(prefix);
+	guid = ntohll(guid);
+	memcpy(&gid[0], &prefix, 8);
+	memcpy(&gid[8], &guid, 8);
+}
+
+static int make_gids_list(ibmad_gid_t gid, unsigned n, struct gid_list **gid_list)
+{
+	struct gid_list *list = NULL;
+	uint64_t guid, prefix;
+	unsigned i;
+
+	list = calloc(1 + n, sizeof(list[0]));
+	if (!list) {
+		err("cannot alloc mem for guid/trid list: %s\n",
+		    strerror(errno));
+		return -1;
+	}
+
+	memcpy(&prefix, &gid[0], 8);
+	prefix = ntohll(prefix);
+	memcpy(&guid, &gid[8], 8);
+	guid = ntohll(guid);
+
+	for (i = 0; i <= n; i++)
+		make_gid(list[i].gid, prefix, guid++);
+
+	*gid_list = list;
+
+	return i;
+}
+
+static int parse_gids_file(const char *guid_file, struct gid_list **gid_list)
+{
+	char line[256];
+	FILE *f;
+	uint64_t guid, prefix;
+	struct gid_list *list = NULL;
+	char *e;
+	unsigned list_size = 0;
+	int i = 0;
+
+	f = fopen(guid_file, "r");
+	if (!f) {
+		fprintf(stderr, "cannot fopen \'%s\' %s\n",
+			guid_file, strerror(errno));
+		return -1;
+	}
+
+	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 (i >= list_size) {
+			list_size += 256;
+			list = realloc(list, list_size * sizeof(list[0]));
+			if (!list) {
+				err("cannot alloc mem for guid/trid list: %s\n",
+				    strerror(errno));
+				return -1;
+			}
+			memset(&list[i], 0, 256 * sizeof(list[0]));
+		}
+
+		make_gid(list[i].gid, prefix, guid);
+		i++;
+	}
+	fclose(f);
+
+	*gid_list = list;
+
+	return i;
+}
+
+static void make_str_opts(char *p, unsigned size, const struct option *o)
+{
+	int i, n = 0;
+
+	for (n = 0; o->name  && n + 2 + o->has_arg < size; o++) {
+		p[n++] = o->val;
+		for (i = 0; i < o->has_arg; i++)
+			p[n++] = ':';
+	}
+	p[n] = '\0';
+}
+
+static const struct test *find_test(const struct test *t, const char *name)
+{
+	int len = strlen(name);
+
+	for (; t->name; t++)
+		if (!strncasecmp(name, t->name, len))
+			return t;
+
+	return NULL;
+}
+
+static void usage(char *prog, const struct option *o, const struct test *t)
+{
+	printf("Usage: %s [options] <test>\n", prog);
+
+	printf("\n, where <test> could be:\n");
+	for (; t->name; t++)
+		printf("\t%s - %s\n", t->name, t->description ? t->description : "");
+	printf("\n, and [options] could be:\n");
+	for (; o->name; o++)
+		printf("\t--%s (-%c)\n", o->name, o->val);
+
+	printf("\n");
+
+	exit(2);
+}
+
+int main(int argc, char **argv)
+{
+	const struct option long_opts [] = {
+		{"guidfile", 1, 0, 'g'},
+		{"mgidfile", 1, 0, 'm'},
+		{"GUID", 1, 0, 'G'},
+		{"MGID", 1, 0, 'M'},
+		{"ipv4", 0, 0, 'i'},
+		{"increment", 1, 0, 'I'},
+		{"version", 0, 0, 'V'},
+		{"verbose", 0, 0, 'v'},
+		{"help", 0, 0, 'h'},
+		{}
+	};
+	const struct test tests[] = {
+		{"rereg", run_port_rereg_test, "simulates port reregistration"},
+		{"joins", run_mcast_joins_test, "run a lot of join requests"},
+		{"leave", run_mcast_leave_test, "run a lot of leave requests"},
+		{0}
+	};
+
+	char opt_str[256];
+	int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS };
+	struct test_data tdata;
+	ibmad_gid_t gid, mgid = {};
+	uint64_t guid = 0;
+	const char *guid_file = NULL, *mgid_file = NULL;
+	const struct test *t;
+	unsigned is_mgid = 0, is_ipv4 = 1, increment = 0;
+	int ret, ch;
+
+	make_str_opts(opt_str, sizeof(opt_str), long_opts);
+
+	while ((ch = getopt_long(argc, argv, opt_str, long_opts, NULL)) != -1) {
+		switch (ch) {
+		case 'G':
+			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;
+			}
+			break;
+		case 'I':
+			increment = strtoul(optarg, NULL, 0);
+			break;
+		case 'g':
+			guid_file = optarg;
+			break;
+		case 'm':
+			mgid_file = optarg;
+			break;
+		case 'v':
+			break;
+		case 'V':
+			printf("%s version %s\n", argv[0], "0.1");
+			exit(0);
+		case 'h':
+		default:
+			usage(argv[0], long_opts, tests);
+			break;
+		}
+	}
+
+	madrpc_init(NULL, 0, mgmt_classes, 2);
+
+	memset(&tdata, 0, sizeof(tdata));
+
+	if (guid) {
+		make_gid(gid, DEFAULT_PREFIX, guid);
+		ret = make_gids_list(gid, increment, &tdata.gids);
+	} else if (guid_file) {
+		ret = parse_gids_file(guid_file, &tdata.gids);
+		guid = get_guid_ho(tdata.gids[0].gid);
+	} else {
+		ib_portid_t portid = {0};
+		if (ib_resolve_self(&portid, NULL, &gid) < 0) {
+			err("Cannot resolve self port...\n");
+			exit(1);
+		}
+		guid = get_guid_ho(gid);
+		ret = make_gids_list(gid, increment, &tdata.gids);
+	}
+
+	if (ret < 0)
+		return ret;
+	tdata.gids_size = ret;
+
+	if (is_mgid)
+		ret = make_gids_list(mgid, increment, &tdata.mgids);
+	else if (mgid_file)
+		ret = parse_gids_file(mgid_file, &tdata.mgids);
+	else if (is_ipv4)
+		ret = make_gids_list(mgid_ipoib, increment, &tdata.mgids);
+	else {
+		make_gid(gid, 0xff00000000000000ULL, guid);
+		ret = make_gids_list(gid, increment, &tdata.mgids);
+	}
+
+	if (ret < 0)
+		return ret;
+	tdata.mgids_size = ret;
+
+	if (argc <= optind)
+		return run_test(&tests[0], &tdata);
+
+	do {
+		t = find_test(tests, argv[optind]);
+		if (!t)
+			usage(argv[0], long_opts, tests);
+		ret = run_test(t, &tdata);
+		if (ret)
+			break;
+	} while (argc > ++optind);
+
+	if (tdata.gids)
+		free(tdata.gids);
+	if (tdata.mgids)
+		free(tdata.mgids);
+
+	return ret;
+}
diff --git a/umad2sim/Makefile b/umad2sim/Makefile
new file mode 100644
index 0000000..6126ead
--- /dev/null
+++ b/umad2sim/Makefile
@@ -0,0 +1,11 @@
+srcs:=umad2sim.c sim_client.c
+objs:=$(srcs:.c=.o)
+libs:=libumad2sim.so
+
+-include ../defs.mk
+
+#CFLAGS+= -DUMAD2SIM_NOISY_DEBUG
+#CFLAGS+= -DSIM_CLIENT_NOISY_DEBUG
+LIBS+= -ldl
+$(libs): $(objs)
+all: $(libs)
diff --git a/umad2sim/sim_client.c b/umad2sim/sim_client.c
new file mode 100644
index 0000000..30430b7
--- /dev/null
+++ b/umad2sim/sim_client.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <infiniband/common.h>
+#include <infiniband/mad.h>
+
+#include <ibsim.h>
+
+#include "sim_client.h"
+
+#ifdef SIM_CLIENT_NOISY_DEBUG
+#undef DEBUG
+#define DEBUG	IBWARN
+#else
+#define DEBUG(fmt...)
+#endif
+
+static unsigned int remote_mode = 0;
+
+static int sim_ctl(struct sim_client *sc, int type, void *data, int len)
+{
+	struct sim_ctl ctl;
+
+	DEBUG("type %d len %d", type, len);
+
+	memset(&ctl, 0, sizeof(ctl));
+
+	if (sc->fd_ctl < 0) {
+		IBWARN("no ctl connection");
+		return -1;
+	}
+
+	ctl.magic = SIM_MAGIC;
+	ctl.type = type;
+	ctl.clientid = sc->clientid;
+	ctl.len = len;
+	if (len)
+		memcpy(ctl.data, data, len);
+
+	if (write(sc->fd_ctl, &ctl, sizeof(ctl)) != sizeof(ctl)) {
+		IBWARN("ctl failed(write)");
+		return -1;
+	}
+
+	ctl.type = SIM_CTL_ERROR;
+
+	if (read(sc->fd_ctl, &ctl, sizeof(ctl)) != sizeof(ctl)) {
+		IBWARN("ctl failed(read)");
+		return -1;
+	}
+
+	if (ctl.type == SIM_CTL_ERROR) {
+		IBWARN("ctl error");
+		return -1;
+	}
+	if (len)
+		memcpy(data, &ctl.data, len);
+
+	return 0;
+}
+
+static size_t make_name(union name_t *name, char *host, unsigned port,
+			const char *fmt, ...)
+{
+	size_t size;
+	memset(name, 0, sizeof(*name));
+	if (remote_mode) {
+		struct sockaddr_in *name_i = &name->name_i;
+	        name_i->sin_family = AF_INET;
+		if (host) {
+			name_i->sin_addr.s_addr = inet_addr(host);
+			if (name_i->sin_addr.s_addr == (unsigned long)INADDR_NONE) {
+				struct hostent *hostp;
+				if(!(hostp = gethostbyname(host)))
+					IBPANIC("cannot resolve ibsim server"
+						" %s: h_errno = %d\n",
+						host, h_errno);
+				memcpy(&name_i->sin_addr, hostp->h_addr,
+				       sizeof(name_i->sin_addr));
+			}
+		} else
+			name_i->sin_addr.s_addr = htonl(INADDR_ANY);
+	        name_i->sin_port = htons(port);
+		size = sizeof(*name_i);
+	} else {
+		va_list args;
+		struct sockaddr_un *name_u = &name->name_u;
+		size = sizeof(*name_u) -
+				((void *)name_u->sun_path + 1 - (void*)name_u);
+		name_u->sun_family = AF_UNIX;
+		name_u->sun_path[0] = 0;	// abstract name space
+		va_start(args, fmt);
+		size = vsnprintf(name_u->sun_path + 1, size, fmt, args);
+		va_end(args);
+		size += 1 + ((void *)name_u->sun_path + 1 - (void*)name_u);
+	}
+	return size;
+}
+
+static char *get_name(union name_t *name)
+{
+	if (remote_mode) {
+		return inet_ntoa(name->name_i.sin_addr);
+	} else {
+		return name->name_u.sun_path + 1;
+	}
+}
+
+static int sim_attach(int fd, union name_t *name, size_t size)
+{
+	int retries;
+	int r;
+
+	for (retries = 0;; retries++) {
+		DEBUG("attempt to connect to %s (attempt %d)",
+		      get_name(name), retries);
+
+		if ((r =
+		     connect(fd, (struct sockaddr *)name, size)) >= 0)
+			break;
+
+		if (r < 0 && errno == ECONNREFUSED) {
+			DEBUG("waiting for %s to start", get_name(name));
+			sleep(2);
+			continue;
+		}
+
+		IBPANIC("can't connect to sim socket %s", get_name(name));
+	}
+
+	return 0;
+}
+
+static int sim_connect(struct sim_client *sc, int id, int qp, char *nodeid)
+{
+	struct sim_client_info info = { 0 };
+
+	info.id = id;
+	info.issm = 0;
+	info.qp = qp;
+
+	if (nodeid)
+		strncpy(info.nodeid, nodeid, sizeof(info.nodeid) - 1);
+
+	if (sim_ctl(sc, SIM_CTL_CONNECT, &info, sizeof(info)) < 0)
+		return -1;
+
+	id = info.id;
+
+	if (!nodeid || strcmp(nodeid, info.nodeid))
+		IBWARN("attached as client %d at node \"%s\"", id,
+		       info.nodeid);
+	return id;
+}
+
+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)
+{
+	union name_t name;
+	socklen_t size;
+	int fd, ctlfd;
+	int pid = getpid();
+	char *connect_port;
+	char *connect_host;
+	unsigned short port;
+
+	connect_port = getenv("IBSIM_SERVER_PORT");
+	connect_host = getenv("IBSIM_SERVER_NAME");
+
+	if (connect_host && *connect_host)
+		remote_mode = 1;
+
+	DEBUG("init client pid=%d, qp=%d nodeid=%s",
+	      pid, qp, nodeid ? nodeid : "none");
+
+	if ((fd = socket(remote_mode ? PF_INET : PF_LOCAL, SOCK_DGRAM, 0)) < 0)
+		IBPANIC("can't get socket (fd)");
+
+	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);
+
+	if (bind(ctlfd, (struct sockaddr *)&name, size) < 0)
+		IBPANIC("can't bind ctl socket");
+
+	DEBUG("init %d: opened ctl fd %d as \'%s\'",
+	      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);
+
+	sim_attach(ctlfd, &name, size);
+
+	sc->fd_ctl = ctlfd;
+
+	size = make_name(&name, NULL, 0, "%s:in%d", SIM_BASENAME, pid);
+
+	if (bind(fd, (struct sockaddr *)&name, size) < 0)
+		IBPANIC("can't bind input socket");
+
+	DEBUG("init client %d: opened input data fd %d as \'%s\'\n",
+	      pid, fd, get_name(&name));
+	if (getsockname(fd, (struct sockaddr *)&name, &size) < 0 )
+		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);
+	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);
+
+	sim_attach(fd, &name, size);
+
+	DEBUG("init client %d: connect data fd %d to \'%s\'\n",
+	      sc->clientid, fd, get_name(&name));
+
+	sc->fd_pktin = fd;
+	sc->fd_pktout = fd;
+
+	return fd;
+}
+
+/*************************/
+
+int sim_client_set_sm(struct sim_client *sc, unsigned issm)
+{
+	DEBUG("sim_client_is_sm: setting to %d", issm);
+	return sim_ctl(sc, SIM_CTL_SET_ISSM, &issm, sizeof(int));
+}
+
+int sim_client_init(struct sim_client *sc, char *nodeid)
+{
+	if (!nodeid)
+		nodeid = getenv("SIM_HOST");
+	if (sim_init(sc, 0, nodeid) < 0)
+		return -1;
+	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;
+	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"))
+		sim_client_set_sm(sc, 1);
+	return 0;
+  _exit:
+	sim_disconnect(sc);
+	sc->fd_ctl = sc->fd_pktin = sc->fd_pktout = -1;
+	return 0;
+}
+
+void sim_client_exit(struct sim_client *sc)
+{
+	sim_disconnect(sc);
+	sc->fd_ctl = sc->fd_pktin = sc->fd_pktout = -1;
+}
diff --git a/umad2sim/sim_client.h b/umad2sim/sim_client.h
new file mode 100644
index 0000000..605b305
--- /dev/null
+++ b/umad2sim/sim_client.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006,2007 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _SIM_CLIENT_H_
+#define _SIM_CLIENT_H_
+
+#include <ibsim.h>
+
+struct sim_client {
+	int clientid;
+	int fd_pktin, fd_pktout, fd_ctl;
+	struct sim_vendor vendor;
+	uint8_t nodeinfo[64];
+	uint8_t portinfo[64];
+	uint16_t pkeys[SIM_CTL_MAX_DATA/sizeof(uint16_t)];
+};
+
+extern int sim_client_set_sm(struct sim_client *sc, unsigned issm);
+extern int sim_client_init(struct sim_client *sc, char *nodeid);
+extern void sim_client_exit(struct sim_client *sc);
+
+#endif				/* _SIM_CLIENT_H_ */
diff --git a/umad2sim/umad2sim.c b/umad2sim/umad2sim.c
new file mode 100644
index 0000000..f896540
--- /dev/null
+++ b/umad2sim/umad2sim.c
@@ -0,0 +1,841 @@
+/*
+ * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved.
+ *
+ * This file is part of ibsim.
+ *
+ * ibsim is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#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
+#undef DEBUG
+#define DEBUG(fmt...) fprintf(stderr, fmt)
+#else
+#define DEBUG(fmt...)
+#endif
+#define ERROR(fmt...) fprintf(stderr, "ERR: " fmt)
+
+#define arrsize(a) (sizeof(a)/sizeof(a[0]))
+
+struct ib_user_mad_reg_req {
+	uint32_t id;
+	uint32_t method_mask[4];
+	uint8_t qpn;
+	uint8_t mgmt_class;
+	uint8_t mgmt_class_version;
+	uint8_t oui[3];
+	uint8_t rmpp_version;
+};
+
+struct umad2sim_dev {
+	int fd;
+	unsigned num;
+	char name[32];
+	uint8_t port;
+	struct sim_client sim_client;
+	unsigned agent_idx[256];
+	struct ib_user_mad_reg_req agents[32];
+	char umad_path[256];
+	char issm_path[256];
+};
+
+static int (*real_open) (const char *path, int flags, ...);
+static int (*real_close) (int fd);
+static ssize_t(*real_read) (int fd, void *buf, size_t count);
+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);
+static int (*real_scandir) (const char *dir, struct dirent *** namelist,
+			    int (*filter) (const struct dirent *),
+			    int (*compar) (const void *, const void *));
+
+static char sysfs_infiniband_dir[] = SYS_INFINIBAND;
+static char sysfs_infiniband_mad_dir[] = IB_UMAD_ABI_DIR;
+static char umad_dev_dir[] = UMAD_DEV_DIR;
+
+static char umad2sim_sysfs_prefix[32];
+
+static unsigned umad2sim_initialized;
+static struct umad2sim_dev *devices[32];
+
+/*
+ *  sysfs stuff
+ *
+ */
+
+static int is_sysfs_file(const char *path)
+{
+	return !strncmp(path, sysfs_infiniband_dir,
+			strlen(sysfs_infiniband_dir)) ||
+	    !strncmp(path, sysfs_infiniband_mad_dir,
+		     strlen(sysfs_infiniband_mad_dir));
+}
+
+static void convert_sysfs_path(char *new_path, unsigned size,
+			       const char *old_path)
+{
+	snprintf(new_path, size, "%s/%s", umad2sim_sysfs_prefix, old_path);
+}
+
+static int make_path(char *path)
+{
+	char dir[1024];
+	char *p;
+
+	convert_sysfs_path(dir, sizeof(dir), path);
+	p = dir;
+	do {
+		p = strchr(p, '/');
+		if (p)
+			*p = '\0';
+		mkdir(dir, 0755);
+		if (p) {
+			*p = '/';
+			p++;
+		}
+	} while (p && p[0]);
+
+	return 0;
+}
+
+static int file_printf(char *path, char *name, const char *fmt, ...)
+{
+	char file_name[1024];
+	va_list args;
+	FILE *f;
+	int ret;
+
+	convert_sysfs_path(file_name, sizeof(file_name), path);
+	strncat(file_name, "/", sizeof(file_name) - 1);
+	strncat(file_name, name, sizeof(file_name) - 1);
+	unlink(file_name);
+	f = fopen(file_name, "w");
+	if (!f) {
+		perror("fopen");
+		return -1;
+	}
+	va_start(args, fmt);
+	ret = vfprintf(f, fmt, args);
+	va_end(args);
+	fclose(f);
+
+	return ret;
+}
+
+static int dev_sysfs_create(struct umad2sim_dev *dev)
+{
+	char path[1024];
+	uint64_t gid, guid;
+	uint32_t val, speed;
+	struct sim_client *sc = &dev->sim_client;
+	char *str;
+	uint8_t *portinfo;
+	int i;
+
+	/* /sys/class/infiniband_mad/abi_version */
+	snprintf(path, sizeof(path), "%s", sysfs_infiniband_mad_dir);
+	make_path(path);
+	file_printf(path, IB_UMAD_ABI_FILE, "%u\n", IB_UMAD_ABI_VERSION);
+
+	/* /sys/class/infiniband/mthca0/ */
+	snprintf(path, sizeof(path), "%s/%s", sysfs_infiniband_dir, dev->name);
+	make_path(path);
+
+	/* /sys/class/infiniband/mthca0/node_type */
+	val = mad_get_field(sc->nodeinfo, 0, IB_NODE_TYPE_F);
+	if (val == 1)
+		str = "CA";
+	else if (val == 2)
+		str = "SWITCH";
+	else if (val == 3)
+		str = "ROUTER";
+	else
+		str = "<unknown>";
+	file_printf(path, SYS_NODE_TYPE, "%x: %s\n", val, str);
+
+	/* /sys/class/infiniband/mthca0/fw_ver */
+	file_printf(path, SYS_CA_FW_VERS, "%llx\n", sc->vendor.fw_ver);
+	//file_printf(path, SYS_CA_FW_VERS, "3.2.2\n");
+
+	/* /sys/class/infiniband/mthca0/hw_rev */
+	file_printf(path, SYS_CA_HW_VERS, "%x\n", sc->vendor.hw_ver);
+
+	/* /sys/class/infiniband/mthca0/hca_type */
+	file_printf(path, SYS_CA_TYPE, "%s\n", "simulator");
+
+	/* /sys/class/infiniband/mthca0/node_guid */
+	guid = mad_get_field64(sc->nodeinfo, 0, IB_NODE_GUID_F);
+	file_printf(path, SYS_CA_NODE_GUID, "%04x:%04x:%04x:%04x\n",
+		    (uint16_t) ((guid >> 48) & 0xffff),
+		    (uint16_t) ((guid >> 32) & 0xffff),
+		    (uint16_t) ((guid >> 16) & 0xffff),
+		    (uint16_t) ((guid >> 0) & 0xffff));
+
+	/* /sys/class/infiniband/mthca0/sys_image_guid */
+	guid = mad_get_field64(sc->nodeinfo, 0, IB_NODE_SYSTEM_GUID_F);
+	file_printf(path, SYS_CA_SYS_GUID, "%04x:%04x:%04x:%04x\n",
+		    (uint16_t) ((guid >> 48) & 0xffff),
+		    (uint16_t) ((guid >> 32) & 0xffff),
+		    (uint16_t) ((guid >> 16) & 0xffff),
+		    (uint16_t) ((guid >> 0) & 0xffff));
+
+	/* /sys/class/infiniband/mthca0/ports/ */
+	strncat(path, "/ports", sizeof(path) - 1);
+	make_path(path);
+
+	portinfo = sc->portinfo;
+
+	/* /sys/class/infiniband/mthca0/ports/1/ */
+	val = mad_get_field(portinfo, 0, IB_PORT_LOCAL_PORT_F);
+	snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%u", val);
+	make_path(path);
+
+	/* /sys/class/infiniband/mthca0/ports/1/lid_mask_count */
+	val = mad_get_field(portinfo, 0, IB_PORT_LMC_F);
+	file_printf(path, SYS_PORT_LMC, "%d", val);
+
+	/* /sys/class/infiniband/mthca0/ports/1/sm_lid */
+	val = mad_get_field(portinfo, 0, IB_PORT_SMLID_F);
+	file_printf(path, SYS_PORT_SMLID, "0x%x", val);
+
+	/* /sys/class/infiniband/mthca0/ports/1/sm_sl */
+	val = mad_get_field(portinfo, 0, IB_PORT_SMSL_F);
+	file_printf(path, SYS_PORT_SMSL, "%d", val);
+
+	/* /sys/class/infiniband/mthca0/ports/1/lid */
+	val = mad_get_field(portinfo, 0, IB_PORT_LID_F);
+	file_printf(path, SYS_PORT_LID, "0x%x", val);
+
+	/* /sys/class/infiniband/mthca0/ports/1/state */
+	val = mad_get_field(portinfo, 0, IB_PORT_STATE_F);
+	if (val == 0)
+		str = "NOP";
+	else if (val == 1)
+		str = "DOWN";
+	else if (val == 2)
+		str = "INIT";
+	else if (val == 3)
+		str = "ARMED";
+	else if (val == 4)
+		str = "ACTIVE";
+	else if (val == 5)
+		str = "ACTIVE_DEFER";
+	else
+		str = "<unknown>";
+	file_printf(path, SYS_PORT_STATE, "%d: %s\n", val, str);
+
+	/* /sys/class/infiniband/mthca0/ports/1/phys_state */
+	val = mad_get_field(portinfo, 0, IB_PORT_PHYS_STATE_F);
+	if (val == 1)
+		str = "Sleep";
+	else if (val == 2)
+		str = "Polling";
+	else if (val == 3)
+		str = "Disabled";
+	else if (val == 4)
+		str = "PortConfigurationTraining";
+	else if (val == 5)
+		str = "LinkUp";
+	else if (val == 6)
+		str = "LinkErrorRecovery";
+	else if (val == 7)
+		str = "Phy Test";
+	else
+		str = "<unknown>";
+	file_printf(path, SYS_PORT_PHY_STATE, "%d: %s\n", val, str);
+
+	/* /sys/class/infiniband/mthca0/ports/1/rate */
+	val = mad_get_field(portinfo, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
+	speed = mad_get_field(portinfo, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
+	if (val == 1)
+		val = 1;
+	else if (val == 2)
+		val = 4;
+	else if (val == 4)
+		val = 8;
+	else if (val == 8)
+		val = 12;
+	else
+		val = 0;
+	if (speed == 2)
+		str = " DDR";
+	else if (speed == 4)
+		str = " QDR";
+	else
+		str = "";
+	file_printf(path, SYS_PORT_RATE, "%d%s Gb/sec (%dX%s)\n",
+		    (val * speed * 25) / 10,
+		    (val * speed * 25) % 10 ? ".5" : "", val, str);
+
+	/* /sys/class/infiniband/mthca0/ports/1/cap_mask */
+	val = mad_get_field(portinfo, 0, IB_PORT_CAPMASK_F);
+	file_printf(path, SYS_PORT_CAPMASK, "0x%08x", val);
+
+	/* /sys/class/infiniband/mthca0/ports/1/gids/0 */
+	str = path + strlen(path);
+	strncat(path, "/gids", sizeof(path) - 1);
+	make_path(path);
+	*str = '\0';
+	gid = mad_get_field64(portinfo, 0, IB_PORT_GID_PREFIX_F);
+	guid = mad_get_field64(sc->nodeinfo, 0, IB_NODE_GUID_F) +
+	    mad_get_field(portinfo, 0, IB_PORT_LOCAL_PORT_F);
+	file_printf(path, SYS_PORT_GID,
+		    "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		    (uint16_t) ((gid >> 48) & 0xffff),
+		    (uint16_t) ((gid >> 32) & 0xffff),
+		    (uint16_t) ((gid >> 16) & 0xffff),
+		    (uint16_t) ((gid >> 0) & 0xffff),
+		    (uint16_t) ((guid >> 48) & 0xffff),
+		    (uint16_t) ((guid >> 32) & 0xffff),
+		    (uint16_t) ((guid >> 16) & 0xffff),
+		    (uint16_t) ((guid >> 0) & 0xffff));
+
+	/* /sys/class/infiniband/mthca0/ports/1/pkeys/0 */
+	str = path + strlen(path);
+	strncat(path, "/pkeys", sizeof(path) - 1);
+	make_path(path);
+	for (i = 0; i < sizeof(sc->pkeys)/sizeof(sc->pkeys[0]); i++) {
+		char name[8];
+		snprintf(name, sizeof(name), "%u", i);
+		file_printf(path, name, "0x%04x\n", ntohs(sc->pkeys[i]));
+	}
+	*str = '\0';
+
+	/* /sys/class/infiniband_mad/umad0/ */
+	snprintf(path, sizeof(path), "%s/umad%u", sysfs_infiniband_mad_dir,
+		 dev->num);
+	make_path(path);
+	file_printf(path, SYS_IB_MAD_DEV, "%s\n", dev->name);
+	file_printf(path, SYS_IB_MAD_PORT, "%d\n", dev->port);
+
+	/* /sys/class/infiniband_mad/issm0/ */
+	snprintf(path, sizeof(path), "%s/issm%u", sysfs_infiniband_mad_dir,
+		 dev->num);
+	make_path(path);
+	file_printf(path, SYS_IB_MAD_DEV, "%s\n", dev->name);
+	file_printf(path, SYS_IB_MAD_PORT, "%d\n", dev->port);
+
+	return 0;
+}
+
+/*
+ * umad2sim device
+ *
+ */
+
+static ssize_t umad2sim_read(struct umad2sim_dev *dev, void *buf, size_t count)
+{
+	struct sim_request req;
+	ib_user_mad_t *umad = (ib_user_mad_t *) buf;
+	unsigned mgmt_class;
+	int cnt;
+
+	DEBUG("umad2sim_read: %zu...\n", count);
+
+	cnt = real_read(dev->sim_client.fd_pktin, &req, sizeof(req));
+	DEBUG("umad2sim_read: got %d...\n", cnt);
+	if (cnt < sizeof(req)) {
+		ERROR("umad2sim_read: partial request - skip.\n");
+		umad->status = EAGAIN;
+		return umad_size();
+	}
+
+	mgmt_class = mad_get_field(req.mad, 0, IB_MAD_MGMTCLASS_F);
+
+	DEBUG("umad2sim_read: mad: method=%x, response=%x, mgmtclass=%x, "
+	      "attrid=%x, attrmod=%x\n",
+	      mad_get_field(req.mad, 0, IB_MAD_METHOD_F),
+	      mad_get_field(req.mad, 0, IB_MAD_RESPONSE_F),
+	      mgmt_class,
+	      mad_get_field(req.mad, 0, IB_MAD_ATTRID_F),
+	      mad_get_field(req.mad, 0, IB_MAD_ATTRMOD_F));
+
+	if (mgmt_class >= arrsize(dev->agent_idx)) {
+		ERROR("bad mgmt_class 0x%x\n", mgmt_class);
+		mgmt_class = 0;
+	}
+
+	if (mad_get_field(req.mad, 0, IB_MAD_RESPONSE_F)) {
+		uint64_t trid = mad_get_field64(req.mad, 0, IB_MAD_TRID_F);
+		umad->agent_id = (trid >> 32) & 0xffff;
+	} else
+		umad->agent_id = dev->agent_idx[mgmt_class];
+
+	umad->status = ntohl(req.status);
+	umad->timeout_ms = 0;
+	umad->retries = 0;
+	umad->length = umad_size() + ntohll(req.length);
+
+	umad->addr.qpn = req.sqp;
+	umad->addr.qkey = 0;	// agent->qkey;
+	umad->addr.lid = req.slid;
+	umad->addr.sl = 0;	// agent->sl;
+	umad->addr.path_bits = 0;
+	umad->addr.grh_present = 0;
+
+	cnt -= sizeof(req) - sizeof(req.mad);
+	if (cnt > count - umad_size())
+		cnt = count - umad_size();
+	memcpy(umad_get_mad(umad), req.mad, cnt);
+
+	return umad->length;
+}
+
+static ssize_t umad2sim_write(struct umad2sim_dev *dev,
+			      const void *buf, size_t count)
+{
+	struct sim_request req;
+	ib_user_mad_t *umad = (ib_user_mad_t *) buf;
+	int cnt;
+
+#ifdef SIMULATE_SEND_ERRORS
+	{ 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");
+		return  -1;
+	}
+	}
+#endif
+
+	DEBUG("umad2sim_write: %zu...\n", count);
+
+	DEBUG("umad2sim_write: umad: agent_id=%u, retries=%u, "
+	      "agent.class=%x, agent.qpn=%u, "
+	      "addr.qpn=%u, addr.lid=%u\n",
+	      umad->agent_id, umad->retries,
+	      dev->agents[umad->agent_id].mgmt_class,
+	      dev->agents[umad->agent_id].qpn,
+	      htonl(umad->addr.qpn), htons(umad->addr.lid));
+	DEBUG("umad2sim_write: mad: method=%x, response=%x, mgmtclass=%x, "
+	      "attrid=%x, attrmod=%x\n",
+	      mad_get_field(umad_get_mad(umad), 0, IB_MAD_METHOD_F),
+	      mad_get_field(umad_get_mad(umad), 0, IB_MAD_RESPONSE_F),
+	      mad_get_field(umad_get_mad(umad), 0, IB_MAD_MGMTCLASS_F),
+	      mad_get_field(umad_get_mad(umad), 0, IB_MAD_ATTRID_F),
+	      mad_get_field(umad_get_mad(umad), 0, IB_MAD_ATTRMOD_F));
+
+	req.dlid = umad->addr.lid;
+	req.slid = req.dlid == 0xffff ? 0xffff : 0;	/* 0 - means auto
+							   (supported by ibsim) */ ;
+	req.dqp = umad->addr.qpn;
+	req.sqp = htonl(dev->agents[umad->agent_id].qpn);
+	req.status = 0;
+
+	cnt = count - umad_size();
+	if (cnt > sizeof(req.mad))
+		cnt = sizeof(req.mad);
+	memcpy(req.mad, umad_get_mad(umad), cnt);
+
+	req.length = htonll(cnt);
+
+	if (!mad_get_field(req.mad, 0, IB_MAD_RESPONSE_F)) {
+		uint64_t trid = mad_get_field64(req.mad, 0, IB_MAD_TRID_F);
+		trid = (trid&0xffff0000ffffffffULL)|(((uint64_t)umad->agent_id)<<32);
+		mad_set_field64(req.mad, 0, IB_MAD_TRID_F, trid);
+	}
+
+	cnt = write(dev->sim_client.fd_pktout, (void *)&req, sizeof(req));
+	if (cnt < 0) {
+		ERROR("umad2sim_write: cannot write\n");
+		return -1;
+	}
+	if (cnt < sizeof(req))
+		ERROR("umad2sim_write: partial write\n");
+
+	return count;
+}
+
+static int register_agent(struct umad2sim_dev *dev,
+			  struct ib_user_mad_reg_req *req)
+{
+	unsigned i;
+	DEBUG("register_agent: id = %u, qpn = %u, mgmt_class = %u,"
+	      " mgmt_class_version = %u, rmpp_version = %u\n",
+	      req->id, req->qpn, req->mgmt_class, req->mgmt_class_version,
+	      req->rmpp_version);
+	for (i = 0; i < arrsize(dev->agents); i++)
+		if (dev->agents[i].id == (uint32_t)(-1)) {
+			req->id = i;
+			dev->agents[i] = *req;
+			dev->agent_idx[req->mgmt_class] = i;
+			DEBUG("agent registered: %d\n", i);
+			return 0;
+		}
+	errno = ENOMEM;
+	return -1;
+}
+
+static int unregister_agent(struct umad2sim_dev *dev, unsigned id)
+{
+	unsigned mgmt_class;
+	if (id >= arrsize(dev->agents)) {
+		errno = EINVAL;
+		return -1;
+	}
+	mgmt_class = dev->agents[id].mgmt_class;
+	dev->agents[id].id = (uint32_t)(-1);
+	dev->agent_idx[mgmt_class] = -1;
+	return 0;
+}
+
+static int umad2sim_ioctl(struct umad2sim_dev *dev, unsigned long request,
+			  void *arg)
+{
+	DEBUG("umad2sim_ioctl: %lu, %p...\n", request, arg);
+	switch (request) {
+	case IB_USER_MAD_REGISTER_AGENT:
+		return register_agent(dev, arg);
+	case IB_USER_MAD_UNREGISTER_AGENT:
+		return unregister_agent(dev, *((unsigned *)arg));
+	case IB_USER_MAD_ENABLE_PKEY:
+		return 0;
+	default:
+		errno = EINVAL;
+	}
+	return -1;
+}
+
+static struct umad2sim_dev *umad2sim_dev_create(unsigned num, const char *name)
+{
+	struct umad2sim_dev *dev;
+	unsigned i;
+
+	DEBUG("umad2sim_dev_create: %s...\n", name);
+
+	dev = malloc(sizeof(*dev));
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
+
+	dev->num = num;
+	strncpy(dev->name, name, sizeof(dev->name) - 1);
+
+	if (sim_client_init(&dev->sim_client, NULL) < 0)
+		goto _error;
+
+	dev->port = mad_get_field(&dev->sim_client.portinfo, 0,
+				  IB_PORT_LOCAL_PORT_F);
+	for (i = 0; i < arrsize(dev->agents); i++)
+		dev->agents[i].id = (uint32_t)(-1);
+	for (i = 0; i < arrsize(dev->agent_idx); i++)
+		dev->agent_idx[i] = (unsigned)(-1);
+
+	dev_sysfs_create(dev);
+
+	snprintf(dev->umad_path, sizeof(dev->umad_path), "%s/%s%u",
+		 umad_dev_dir, "umad", num);
+	snprintf(dev->issm_path, sizeof(dev->issm_path), "%s/%s%u",
+		 umad_dev_dir, "issm", num);
+
+	return dev;
+
+  _error:
+	free(dev);
+	return NULL;
+}
+
+static void umad2sim_dev_delete(struct umad2sim_dev *dev)
+{
+	sim_client_exit(&dev->sim_client);
+	free(dev);
+}
+
+static void unlink_dir(char path[], unsigned size)
+{
+	struct dirent *dent;
+	DIR *dir;
+	int len = strlen(path);
+
+	dir = opendir(path);
+	if (!dir) {
+		fprintf(stderr, "cannot opendir %s: %s\n",
+			path, strerror(errno));
+		return;
+	}
+
+	while ((dent = readdir(dir)) != NULL) {
+		struct stat st;
+		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+			continue;
+		snprintf(path + len, size - len, "/%s", dent->d_name);
+		if (stat(path, &st) < 0)
+			fprintf(stderr, "cannot stat %s: %s\n",
+				path, strerror(errno));
+		else if (S_ISDIR(st.st_mode))
+			unlink_dir(path, size);
+		else if (unlink(path) < 0)
+			fprintf(stderr, "cannot unlink %s: %s\n",
+				path, strerror(errno));
+		path[len] = '\0';
+	}
+
+	closedir(dir);
+	if (rmdir(path) < 0)
+		fprintf(stderr, "cannot rmdir %s: %s\n", path, strerror(errno));
+}
+
+static void umad2sim_cleanup(void)
+{
+	char path[1024];
+	unsigned i;
+	DEBUG("umad2sim_cleanup...\n");
+	for (i = 0; i < arrsize(devices); i++)
+		if (devices[i]) {
+			umad2sim_dev_delete(devices[i]);
+			devices[i] = NULL;
+		}
+	strncpy(path, umad2sim_sysfs_prefix, sizeof(path) - 1);
+	unlink_dir(path, sizeof(path));
+}
+
+static void umad2sim_init(void)
+{
+	if (umad2sim_initialized)
+		return;
+	DEBUG("umad2sim_init...\n");
+	snprintf(umad2sim_sysfs_prefix, sizeof(umad2sim_sysfs_prefix),
+		 "./sys-%d", getpid());
+	devices[0] = umad2sim_dev_create(0, "ibsim0");
+	if (!devices[0]) {
+		ERROR("cannot init umad2sim. Exit.\n");
+		exit(-1);
+	}
+	atexit(umad2sim_cleanup);
+	umad2sim_initialized = 1;
+}
+
+/*
+ *  libc wrappers
+ *
+ */
+
+static unsigned wrapper_initialized;
+
+#define CHECK_INIT() if (!wrapper_initialized) wrapper_init()
+
+static void wrapper_init()
+{
+	if (wrapper_initialized)
+		return;
+	real_open = dlsym(RTLD_NEXT, "open");
+	real_close = dlsym(RTLD_NEXT, "close");
+	real_read = dlsym(RTLD_NEXT, "read");
+	real_write = dlsym(RTLD_NEXT, "write");
+	real_poll = dlsym(RTLD_NEXT, "poll");
+	real_ioctl = dlsym(RTLD_NEXT, "ioctl");
+	real_opendir = dlsym(RTLD_NEXT, "opendir");
+	real_scandir = dlsym(RTLD_NEXT, "scandir");
+	wrapper_initialized = 1;
+}
+
+DIR *opendir(const char *path)
+{
+	char new_path[1024];
+
+	CHECK_INIT();
+	DEBUG("libs_wrap: opendir: %s...\n", path);
+
+	if (is_sysfs_file(path)) {
+		convert_sysfs_path(new_path, sizeof(new_path), path);
+		path = new_path;
+	}
+
+	return real_opendir(path);
+}
+
+int scandir(const char *path, struct dirent ***namelist,
+	    int (*filter) (const struct dirent *),
+	    int (*compar) (const void *, const void *))
+{
+	char new_path[4096];
+
+	CHECK_INIT();
+	DEBUG("libs_wrap: scandir: %s...\n", path);
+
+	if (is_sysfs_file(path)) {
+		convert_sysfs_path(new_path, sizeof(new_path), path);
+		path = new_path;
+	}
+
+	return real_scandir(path, namelist, filter, compar);
+}
+
+int open(const char *path, int flags, ...)
+{
+	struct umad2sim_dev *dev;
+	va_list args;
+	mode_t mode = 0;
+	unsigned i;
+
+	CHECK_INIT();
+
+	if (!umad2sim_initialized && (is_sysfs_file(path) ||
+				      !strncmp(path, umad_dev_dir,
+					       strlen(umad_dev_dir))))
+		umad2sim_init();
+
+	DEBUG("libs_wrap: open: %s...\n", path);
+
+	if (flags & O_CREAT) {
+		va_start(args, flags);
+		mode = va_arg(args, mode_t);
+		va_end(args);
+	}
+
+	if (is_sysfs_file(path)) {
+		char new_path[1024];
+		convert_sysfs_path(new_path, sizeof(new_path), path);
+		return real_open(new_path, flags, mode);
+	}
+
+	for (i = 0; i < arrsize(devices); i++) {
+		if (!(dev = devices[i]))
+			continue;
+		if (!strncmp(path, dev->umad_path, sizeof(dev->umad_path))) {
+			return 1024 + i;
+		}
+		if (!strncmp(path, dev->issm_path, sizeof(dev->issm_path))) {
+			sim_client_set_sm(&dev->sim_client, 1);
+			return 2048 + i;
+		}
+	}
+
+	return real_open(path, flags, mode);
+}
+
+int close(int fd)
+{
+	struct umad2sim_dev *dev;
+
+	DEBUG("libs_wrap: close %d...\n", fd);
+	CHECK_INIT();
+
+	if (fd >= 2048) {
+		dev = devices[fd - 2048];
+		sim_client_set_sm(&dev->sim_client, 0);
+		return 0;
+	} else if (fd >= 1024) {
+		return 0;
+	} else
+		return real_close(fd);
+}
+
+ssize_t read(int fd, void *buf, size_t count)
+{
+	CHECK_INIT();
+
+	if (fd >= 2048)
+		return -1;
+	else if (fd >= 1024)
+		return umad2sim_read(devices[fd - 1024], buf, count);
+	else
+		return real_read(fd, buf, count);
+}
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+	CHECK_INIT();
+
+	if (fd >= 2048)
+		return -1;
+	else if (fd >= 1024)
+		return umad2sim_write(devices[fd - 1024], buf, count);
+	else
+		return real_write(fd, buf, count);
+}
+
+int ioctl(int fd, unsigned long request, ...)
+{
+	va_list args;
+	void *arg;
+
+	CHECK_INIT();
+	va_start(args, request);
+	arg = va_arg(args, void *);
+	va_end(args);
+
+	if (fd >= 2048)
+		return -1;
+	else if (fd >= 1024)
+		return umad2sim_ioctl(devices[fd - 1024], request, arg);
+	else
+		return real_ioctl(fd, request, arg);
+}
+
+int poll(struct pollfd *pfds, unsigned long nfds, int timeout)
+{
+	int saved_fds[nfds];
+	unsigned i;
+	int ret;
+
+	CHECK_INIT();
+
+	for (i = 0; i < nfds; i++) {
+		if (pfds[i].fd >= 1024 && pfds[i].fd < 2048) {
+			struct umad2sim_dev *dev = devices[pfds[i].fd - 1024];
+			saved_fds[i] = pfds[i].fd;
+			pfds[i].fd = dev->sim_client.fd_pktin;
+		}
+	}
+
+	ret = real_poll(pfds, nfds, timeout);
+
+	for (i = 0; i < nfds; i++)
+		if (saved_fds[i])
+			pfds[i].fd = saved_fds[i];
+
+	return ret;
+}

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