[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