pax_global_header00006660000000000000000000000064143277620230014520gustar00rootroot0000000000000052 comment=db9c0e46bf23802e92cea5c72b5eea6d9075169a ibsim-0.12/000077500000000000000000000000001432776202300125455ustar00rootroot00000000000000ibsim-0.12/.gitignore000066400000000000000000000002231432776202300145320ustar00rootroot00000000000000# Backup files *~ # Generated files *.o *.so *.build_profile ibsim/ibsim ibsim/ibsim-run tests/mcast_storm tests/query_many tests/subnet_discover ibsim-0.12/.travis.yml000066400000000000000000000004731432776202300146620ustar00rootroot00000000000000language: c dist: xenial addons: apt: sources: - ubuntu-toolchain-r-test packages: - gcc-8 - git-core - make - sparse - wget - libibumad-dev - libibmad-dev - opensm script: - scripts/travis-checkpatch - scripts/travis-build - scripts/travis-runtest - ./dist.sh ibsim-0.12/COPYING000066400000000000000000000431141432776202300136030ustar00rootroot00000000000000 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. Copyright (C) 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. , 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. ibsim-0.12/Makefile000066400000000000000000000010371432776202300142060ustar00rootroot00000000000000subdirs:= ibsim umad2sim subdirs_with_tests:=$(subdirs) tests all clean dep: $(foreach dir, $(subdirs_with_tests), make -C $(dir) $@ && ) echo "Done." install: $(foreach dir, $(subdirs), make -C $(dir) $@ && ) echo "Done." dist: ./dist.sh RELEASE=$(RELEASE) distcheck: dist @set -e; set -x; \ tarball=`ls -t *.tar.gz | head -n 1`; \ rm -rf checkdir; \ mkdir checkdir; \ cd checkdir; \ tar xzf ../$$tarball; \ cd *; \ make; \ make install DESTDIR=`pwd`/root; \ # rm -rf checkdir .PHONEY: all clean dep dist distcheck install ibsim-0.12/README000066400000000000000000000064711432776202300134350ustar00rootroot00000000000000Infiniband 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 , where 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: Tamir Ronen ibsim-0.12/TODO000066400000000000000000000003131432776202300132320ustar00rootroot00000000000000* transaction management - multiple transactions per client - hops simulation - RMPP * more attributes handled * MKey support * cleaner (less) debug/warning messages * support for combined routing ibsim-0.12/debian/000077500000000000000000000000001432776202300137675ustar00rootroot00000000000000ibsim-0.12/debian/changelog000066400000000000000000000004131432776202300156370ustar00rootroot00000000000000ibsim (0.9) unstable; urgency=low * Switch to Github. -- Tzafrir Cohen Sun, 12 Apr 2020 11:14:12 +0300 ibsim (0.6) unstable; urgency=low * Initial release -- Ilya Nelkenbaum Mon, 11 Mar 2013 11:03:54 +0200 ibsim-0.12/debian/compat000066400000000000000000000000021432776202300151650ustar00rootroot000000000000009 ibsim-0.12/debian/control000066400000000000000000000010701432776202300153700ustar00rootroot00000000000000Source: ibsim Section: net Priority: extra Maintainer: Tzafrir Cohen Build-Depends: debhelper (>= 9), libibumad-dev, libibmad-dev Standards-Version: 4.13 Homepage: https://github.com/linux-rdma/ibsim Package: ibsim Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: InfiniBand fabric simulator for management ibsim provides simulation of infiniband fabric for using with OFA OpenSM, diagnostic and management tools. Package: ibsim-doc Architecture: all Description: documentation for ibsim Documentation for ibsim ibsim-0.12/debian/copyright000066400000000000000000000044671432776202300157350ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: ibsim Source: https://github.com/linux-rdma/ibsim/ Files: * Copyright: 2004-2008, Voltaire, Inc. 2010-2017, Mellanox Technologies LTD. License: BSD-2+GPL-2 Files: ibsim/sim_mad.c Copyright: 2004-2008, Voltaire, Inc. 2009, HNR Consulting. 2011, Mellanox Technologies LTD. License: BSD-2+GPL-2 Files: tests/mcast_storm.c tests/query_many.c tests/subnet_discover.c Copyright: 2006-2008, Voltaire, Inc. 2009, Voltaire, Inc. License: GPL-2+ 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. . on Debian system in the file /usr/share/common-licenses/GPL-2. Comment: Those are tests that are included in the source and built, but are not currently included in any binary package. License: BSD-2+GPL-2 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. . on Debian system in the file /usr/share/common-licenses/GPL-2. ibsim-0.12/debian/docs000066400000000000000000000000411432776202300146350ustar00rootroot00000000000000README TODO net-examples scripts ibsim-0.12/debian/ibsim-doc.docs000066400000000000000000000000071432776202300165040ustar00rootroot00000000000000#DOCS# ibsim-0.12/debian/ibsim-doc.install000066400000000000000000000000071432776202300172220ustar00rootroot00000000000000#DOCS# ibsim-0.12/debian/ibsim.install000066400000000000000000000000201432776202300164520ustar00rootroot00000000000000usr/lib usr/bin ibsim-0.12/debian/rules000077500000000000000000000012241432776202300150460ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # # Modified to make a template file for a multi-binary package with separated # build-arch and build-indep targets by Bill Allombert 2001 # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # This has to be exported to make some magic below work. export DH_OPTIONS %: dh $@ ibsim-0.12/debian/source/000077500000000000000000000000001432776202300152675ustar00rootroot00000000000000ibsim-0.12/debian/source/format000066400000000000000000000000151432776202300164760ustar00rootroot000000000000003.0 (native) ibsim-0.12/defs.mk000066400000000000000000000033411432776202300140200ustar00rootroot00000000000000 old_ofed:=/usr/local/ofed prefix:= $(strip $(if $(prefix),$(prefix),\ $(if $(wildcard $(old_ofed)/lib64/libibumad.so \ $(old_ofed)/lib/libibumad.so),$(old_ofed),\ $(if $(wildcard /usr/local/lib/libibumad.so \ /usr/local/lib64/libibumad.so),/usr/local,\ $(if $(wildcard /usr/lib /usr/lib64),/usr,/tmp/unknown))))) libpath:= $(strip $(if $(libpath),$(libpath),\ $(if $(wildcard $(prefix)/lib64/libibumad.so),\ $(prefix)/lib64,$(prefix)/lib))) binpath:= $(if $(binpath),$(binpath),$(prefix)/bin) libdir:=$(libpath)/umad2sim #IB_DEV_DIR:=$(HOME)/src/m ifdef IB_DEV_DIR INCS:= $(foreach l, mad umad, -I$(IB_DEV_DIR)/libib$(l)/include) \ -I/usr/local/include LIBS:= \ $(foreach l, mad umad, $(IB_DEV_DIR)/libib$(l)/.libs/libib$(l).so) else INCS:= -I$(dir $(libpath))include LIBS:= -L$(libpath) -libmad -libumad -lpthread 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) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< %.so: $(CC) -shared $(LDFLAGS) -o $@ $^ $(LIBS) $(bins): %: $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) dep: $(CC) -M $(CFLAGS) $(srcs) > .depend -include .depend clean: $(RM) $(objs) $(libs) $(bins) $(extra_clean) $(RM) .build_profile $(RM) *.o *.a *.so *~ install: all install -d $(DESTDIR)$(binpath) install -d $(DESTDIR)$(libdir) $(foreach p, $(progs), install $(p) $(DESTDIR)$(binpath);) $(foreach l, $(libs), install $(l) $(DESTDIR)$(libdir);) $(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 ibsim-0.12/dist.sh000077500000000000000000000014361432776202300140530ustar00rootroot00000000000000#!/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 dch_entry() { cat < `date -R` EOF } rm -f $tarball rm -rf $distdir mkdir $distdir files=`find . -name '*.[ch]' -o -name Makefile -o -name '*.in'` cp -a --parents $files debian \ 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 (dch_entry; cat debian/changelog) >$distdir/debian/changelog tar czf $tarball $distdir rm -rf $distdir ibsim-0.12/ibsim.spec.in000066400000000000000000000022451432776202300151340ustar00rootroot00000000000000 %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: https://github.com/linux-rdma/ibsim/releases/download/@VERSION@/@TARBALL@ Url: https://github.com/linux-rdma/ibsim BuildRequires: libibmad-devel, libibumad-devel, gcc %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 %{_bindir}/ibsim-run %doc README COPYING TODO net-examples scripts %changelog ibsim-0.12/ibsim/000077500000000000000000000000001432776202300136505ustar00rootroot00000000000000ibsim-0.12/ibsim/Makefile000066400000000000000000000003441432776202300153110ustar00rootroot00000000000000bins:=ibsim scripts:=ibsim-run progs:=$(bins) $(scripts) extra_clean:=ibsim-run -include ../defs.mk ibsim-run: ibsim-run.in sed -e 's|@sim_so@|$(libdir)/libumad2sim.so|' \ <$< >$@ chmod +x $@ all: $(progs) ibsim: $(objs) ibsim-0.12/ibsim/ibsim-run.1000066400000000000000000000020351432776202300156370ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" (C) Copyright 2020 Tzafrir Cohen .\" .TH ibsim\-run 1 "2020-04-05" .SH NAME ibsim\-run \- run programs in an ibsim-simulated envronment .SH SYNOPSIS .B ibsim\-run .RI [ ] .SH DESCRIPTION The package ibsim simulates calls to the umad library (of the Infiniband user-space stack). In order to use it, you should run ibsim(1), that gets a network diagram. Programs that have libumad2sim.so loaded, override the calls to libumad with calls to the ibsim simulator. This is a script that runs commands with libumad2sim.so already LD_PRELOAD-ed. .SH OPTIONS The script will manipulate the environment and then run the rest of the command line in that environment. If no command was given, it will run bash. However the following options are supported: .TP .B \-h, \-\-help Show summary of options and exit. .SH EXAMPLES ibsim -s path/to/net-examples/net.2sw2path4hca And in a separate shell: ibsim-run ibdiscover .SH SEE ALSO .BR ibsim(1) ibsim-0.12/ibsim/ibsim-run.in000077500000000000000000000011301432776202300161030ustar00rootroot00000000000000#!/bin/sh sim_so=@sim_so@ shell="bash" usage() { me=${0##*/} cat < # Run under ibsim $me # Start a shell similarely $me -h | --help # Print this message Note: You still need to run ibsim separately. EOF } case "$1" in -h | --help) usage; exit 1;; esac if [ "$LD_PRELOAD" = '' ]; then LD_PRELOAD="$sim_so" else LD_PRELOAD="$LD_PRELOAD:sim_so" fi export LD_PRELOAD if [ "$*" = '' ]; then exec $shell else exec "$@" fi ibsim-0.12/ibsim/ibsim.c000066400000000000000000000447101432776202300151250ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sim.h" #define IBSIM_VERSION "0.12" #undef DEBUG #define PDEBUG if (parsedebug) IBWARN #define DEBUG if (simverb > 1 || ibdebug) IBWARN #define VERB if (simverb || ibdebug) IBWARN 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 char* socket_basename; static int console = 1; 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", socket_basename, id); if (connect(cl->fd, (struct sockaddr *)&name, size) < 0) IBPANIC("can't connect to in socket %s - fd %d client pid %d", 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; memcpy(&issm, &ctl->data[0], sizeof(int)); 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 } 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); if (console) fprintf(simout, "sim%s> ", netstarted ? "" : " (inactive)"); fflush(simout); return 0; } static int sim_run_console(int fd) { char line[128]; int ret = 0; char *p = NULL; ret = readline(fd, line, sizeof(line) - 1); if (ret <= 0) return ret; if((p = strchr(line, '\n')) != NULL) *p = '\0'; do_cmd(line, simout); fprintf(simout, "sim%s> ", netstarted ? "" : " (inactive)"); fflush(simout); return 0; } static int sim_run(int con_fd) { fd_set rfds; int i; socket_basename=getenv("IBSIM_SOCKNAME"); if(!socket_basename) socket_basename = SIM_BASENAME; if (sim_init_conn(socket_basename) < 0) return -1; while (!netstarted) sim_run_console(con_fd); for (;;) { FD_ZERO(&rfds); FD_SET(simctl, &rfds); if (console) 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, NULL) < 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 %u, qp %d %s\n", i, clients[i].pid, clients[i].port->node->nodeid, clients[i].port->portguid, clients[i].port->lid, clients[i].qp, clients[i].issm ? "SM" : ""); } 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 NULL; } static 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 switches -P ports -L linearcap" " -M mcastcap -r(emote_mode) -l(isten_to_port) -n(o-console)] \n", prog_name); fprintf(stderr, "%s %s\n", prog_name, IBSIM_VERSION); exit(-1); } int main(int argc, char **argv) { char *outfname = NULL, *netfile; FILE *infile, *outfile; int status; static char const str_opts[] = "rf:dpvIsN:S:P:L:M:l:Vhun"; static const struct option long_opts[] = { {"remote", 0, NULL, 'r'}, {"file", 1, NULL, 'f'}, {"Nodes", 1, NULL, 'N'}, {"Switches", 1, NULL, 'S'}, {"Ports", 1, NULL, 'P'}, {"Linearcap", 1, NULL, 'L'}, {"Mcastcap", 1, NULL, 'M'}, {"listen", 1, NULL, 'l'}, {"Ignoredups", 0, NULL, 'I'}, {"start", 0, NULL, 's'}, {"debug", 0, NULL, 'd'}, {"parsedebug", 0, NULL, 'p'}, {"verbose", 0, NULL, 'v'}, {"Version", 0, NULL, 'V'}, {"no-console", 0, NULL, 'n'}, {"help", 0, NULL, 'h'}, {"usage", 0, NULL, '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, NULL, 0); break; case 'S': maxnetswitches = strtoul(optarg, NULL, 0); break; case 'P': maxnetports = strtoul(optarg, NULL, 0); break; case 'L': maxlinearcap = strtoul(optarg, NULL, 0); break; case 'M': maxmcastcap = strtoul(optarg, NULL, 0); break; case 'l': listen_to_port = strtoul(optarg, NULL, 0); break; case 'n': console = 0; break; case 'V': default: usage(argv[0]); } } maxnetaliases = maxnetports; infile = stdin; outfile = stdout; if (outfname && (outfile = fopen(outfname, "w")) == NULL) IBPANIC("can't open out file %s for write", outfname); if (!console && !netstarted) IBPANIC("Cannot disable console without starting " "the network from the command line"); 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); status = sim_init_net(netfile, outfile); if (status < 0) IBPANIC("sim_init failed, status %d", status); sim_init_console(outfile); sim_run(fileno(infile)); free_core(); exit(0); } ibsim-0.12/ibsim/sim.h000066400000000000000000000342651432776202300146230ustar00rootroot00000000000000/* * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. * Copyright (c) 2011 Mellanox Technologies LTD. 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 #define MAXNETNODES 2048 #define MAXNETSWITCHS 256 #define MAXNETPORTS (MAXNETSWITCHS*36+MAXNETNODES*2) #define MAXNETALIASES MAXNETPORTS #define MAXLINEARCAP (48*1024) #define MAXMCASTCAP 1024 #define LASTBLOCK32 (MAXMCASTCAP/32-1) #define MCASTMASKSIZE 16 // linkwidth == 4X - must be one width only 1,2,8 or 16 #define LINKWIDTH_1x 1 #define LINKWIDTH_4x 2 #define LINKWIDTH_1x_4x 3 #define LINKWIDTH_8x 4 #define LINKWIDTH_1x_8x 5 #define LINKWIDTH_4x_8x 6 #define LINKWIDTH_1x_4x_8x 7 #define LINKWIDTH_12x 8 #define LINKWIDTH_1x_12x 9 #define LINKWIDTH_4x_12x 10 #define LINKWIDTH_1x_4x_12x 11 #define LINKWIDTH_8x_12x 12 #define LINKWIDTH_1x_8x_12x 13 #define LINKWIDTH_4x_8x_12x 14 #define LINKWIDTH_1x_4x_8x_12x 15 #define LINKWIDTH_2x 16 #define LINKWIDTH_1x_2x 17 #define LINKWIDTH_2x_4x 18 #define LINKWIDTH_1x_2x_4x 19 #define LINKWIDTH_2x_8x 20 #define LINKWIDTH_1x_2x_8x 21 #define LINKWIDTH_2x_4x_8x 22 #define LINKWIDTH_1x_2x_4x_8x 23 #define LINKWIDTH_2x_12x 24 #define LINKWIDTH_1x_2x_12x 25 #define LINKWIDTH_2x_4x_12x 26 #define LINKWIDTH_1x_2x_4x_12x 27 #define LINKWIDTH_2x_8x_12x 28 #define LINKWIDTH_1x_2x_8x_12x 29 #define LINKWIDTH_2x_4x_8x_12x 30 #define LINKWIDTH_1x_2x_4x_8x_12x 31 #define LINKSPEED_SDR 1 #define LINKSPEED_DDR 2 #define LINKSPEED_SDR_DDR 3 #define LINKSPEED_QDR 4 #define LINKSPEED_SDR_QDR 5 #define LINKSPEED_SDR_DDR_QDR 7 #define LINKSPEEDEXT_NONE 0 #define LINKSPEEDEXT_FDR 1 #define LINKSPEEDEXT_EDR 2 #define LINKSPEEDEXT_FDR_EDR 3 #define LINKSPEEDEXT_HDR 4 #define LINKSPEEDEXT_HDR_FDR 5 #define LINKSPEEDEXT_HDR_EDR 6 #define LINKSPEEDEXT_HDR_EDR_FDR 7 #define LINKSPEEDEXT_NDR 8 #define LINKSPEEDEXT_NDR_FDR 9 #define LINKSPEEDEXT_NDR_EDR 10 #define LINKSPEEDEXT_NDR_FDR_EDR 11 #define LINKSPEEDEXT_NDR_HDR 12 #define LINKSPEEDEXT_NDR_HDR_FDR 13 #define LINKSPEEDEXT_NDR_HDR_EDR 14 #define LINKSPEEDEXT_NDR_HDR_EDR_FDR 15 #define MLNXLINKSPEED_NONE 0 #define MLNXLINKSPEED_FDR10 1 #define DEFAULT_LINKWIDTH LINKWIDTH_4x #define DEFAULT_LINKSPEED LINKSPEED_SDR #define DEFAULT_LINKSPEEDEXT LINKSPEEDEXT_NONE #define DEFAULT_MLNXLINKSPEED MLNXLINKSPEED_NONE #define NODEPREFIX 20 #define NODEIDLEN 65 #define ALIASLEN 40 #define MAXHOPS 16 enum NODE_TYPES { NO_NODE, 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_ISEXTENDEDSPEEDS = (1<<14), CAPMASK_ISCAPMASK2 = (1<<15), CAPMASK_ISCAPMASKTRAP = (1<<22), }; /* some PortInfo capmask2 fields */ enum PORTINFO_CAPMASK2 { CAPMASK2_ISLINKWIDTH2X = (1<<4), CAPMASK2_ISLINKSPEEDHDR = (1<<5), }; 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 GS_PERF_XMT_WAIT_MASK = (1UL << 16), // PORT_XMIT_WAIT }; // Infiniband ClassPortInfo capmask masks enum IB_CPI_CAPMASK { IB_PM_ALL_PORT_SELECT = (1UL << 8), IB_PM_EXT_WIDTH_SUPPORTED = (1UL << 9), IB_PM_EXT_WIDTH_NOIETF_SUP = (1UL << 10), IB_PM_SAMPLES_ONLY_SUP = (1UL << 11), IB_PM_PC_XMIT_WAIT_SUP = (1UL << 12), IS_PM_INH_LMTD_PKEY_MC_CONSTR_ERR = (1UL << 13), IS_PM_RSFEC_COUNTERS_SUP = (1UL << 14), IB_PM_IS_QP1_DROP_SUP = (1UL << 15), }; 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 RCV_ERROR_DETAILS_COUNTER_SELECT_MASK { GS_PERF_LOCAL_PHYSICAL_ERRORS_MASK = (1UL << 0), // PortLocalPhysicalErrors GS_PERF_MALFORMED_PACKET_ERRORS_MASK = (1UL << 1), // PortMalformedPacketErrors GS_PERF_BUFFER_OVERRUN_ERRORS_MASK = (1UL << 2), // PortBufferOverrunErrors GS_PERF_DLID_MAPPING_ERRORS_MASK = (1UL << 3), // PortDLIDMappingErrors GS_PERF_VL_MAPPING_ERRORS_MASK = (1UL << 4), // PortVLMappingErrors GS_PERF_LOOPING_ERRORS_MASK = (1UL << 5), // PortLoopingErrors }; enum XMIT_DISCARD_DETAILS_SELECT_MASK { GS_PERF_INACTIVE_DISCARDS_MASK = (1UL << 0), // PortInactiveDiscards GS_PERF_NEIGHBOR_MTU_DISCARDS_MASK = (1UL << 1), // PortNeighborMTUDiscards GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_MASK = (1UL << 2), // PortSwLifetimeLimitDiscards GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_MASK = (1UL << 3), // PortSwHOQLifetimeLimitDiscards }; enum OP_RCV_COUNTERS_SELECT_MASK { GS_PERF_OP_RCV_PKTS_MASK = (1UL << 0), // PortOpRcvPkts GS_PERF_OP_RCV_DATA_MASK = (1UL << 1), // PortOpRcvData }; enum FLOW_CTL_COUNTERS_SELECT_MASK { GS_PERF_XMIT_FLOW_PKTS_MASK = (1UL << 0), // PortXmitFlowPkts GS_PERF_RCV_FLOW_PKTS_MASK = (1UL << 1), // PortRcvFlowPkts }; /* Counter select bit masks for PortVLOpPackets[0-15], PortVLOpData[0-15], and PortVLXmitWaitCounters[0-15] are ommitted due to redundency. */ enum GS_PERF_COUNTER_SELECT_LIMIT { GS_PERF_ERR_SYM_LIMIT = 0xffff, GS_PERF_LINK_RECOVERS_LIMIT = 0xff, 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, GS_PERF_XMT_WAIT_LIMIT = 0xffffffff, GS_PERF_LOCAL_PHYSICAL_ERRORS_LIMIT = 0xffff, // PortLocalPhysicalErrors GS_PERF_MALFORMED_PACKET_ERRORS_LIMIT = 0xffff, // PortMalformedPacketErrors GS_PERF_BUFFER_OVERRUN_ERRORS_LIMIT = 0xffff, // PortBufferOverrunErrors GS_PERF_DLID_MAPPING_ERRORS_LIMIT = 0xffff, // PortDLIDMappingErrors GS_PERF_VL_MAPPING_ERRORS_LIMIT = 0xffff, // PortVLMappingErrors GS_PERF_LOOPING_ERRORS_LIMIT = 0xffff, // PortLoopingErrors GS_PERF_INACTIVE_DISCARDS_LIMIT = 0xffff, // PortInactiveDiscards GS_PERF_NEIGHBOR_MTU_DISCARDS_LIMIT = 0xffff, // PortNeighborMTUDiscards GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_LIMIT = 0xffff, // PortSwLifetimeLimitDiscards GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_LIMIT = 0xffff, // PortSwHOQLifetimeLimitDiscards GS_PERF_OP_RCV_PKTS_LIMIT = 0xffffffff, // PortOpRcvPkts GS_PERF_OP_RCV_DATA_LIMIT = 0xffffffff, // PortOpRcvData GS_PERF_XMIT_FLOW_PKTS_LIMIT = 0xffffffff, // PortXmitFlowPkts GS_PERF_RCV_FLOW_PKTS_LIMIT = 0xffffffff, // PortRcvFlowPkts GS_PERF_VL_OP_PACKETS_LIMIT = 0xffff, // PortVLOpPackets[0-15] GS_PERF_VL_OP_DATA_LIMIT = 0xffffffff, // PortVLOpData[0-15] GS_PERF_VL_XMIT_FLOW_CTL_UPDATE_ERRORS = 0x3, // PortVLXmitFlowCtlUpdateErrors[0-15] GS_PERF_VL_XMIT_WAIT_COUNTERS_LIMIT = 0xffff, // PortVLXmitWaitCounters[0-15] }; typedef struct Port Port; 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; int linkspeedexten; }; 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; uint32_t xmt_wait; struct PortRcvErrorDetails { uint16_t PortLocalPhysicalErrors; uint16_t PortMalformedPacketErrors; uint16_t PortBufferOverrunErrors; uint16_t PortDLIDMappingErrors; uint16_t PortVLMappingErrors; uint16_t PortLoopingErrors; } rcv_error_details; struct PortXmitDiscardDetails { uint16_t PortInactiveDiscards; uint16_t PortNeighborMTUDiscards; uint16_t PortSwLifetimeLimitDiscards; uint16_t PortSwHOQLifetimeLimitDiscards; } xmit_discard_details; struct PortOpRcvCounters { uint32_t PortOpRcvPkts; uint32_t PortOpRcvData; } op_rcv_counters; struct PortFlowCtlCounters { uint32_t PortXmitFlowPkts; uint32_t PortRcvFlowPkts; } flow_ctl_counters; struct PortVLOpPackets { uint16_t PortVLOpPackets[16]; } vl_op_packets; struct PortVLOpData { uint32_t PortVLOpData[16]; } vl_op_data; struct PortVLXmitFlowCtlUpdateErrors { uint8_t PortVLXmitFlowCtlUpdateErrors[16]; } vl_xmit_flow_ctl_update_errors; struct PortVLXmitWaitCounters { uint16_t PortVLXmitWait[16]; } vl_xmit_wait_counters; }; struct Port { uint64_t subnet_prefix; uint64_t portguid; int portnum; int lid; int smlid; int linkwidth; int linkwidthena; int linkspeed; int linkspeedena; int linkspeedext; int linkspeedextena; int mlnx_linkspeed; int mlnx_linkspeedena; int state; int physstate; int lmc; int hoqlife; uint8_t portinfo[64]; uint8_t extportinfo[64]; uint8_t op_vls; 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; int numportmask; 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); int alloc_core(void); void free_core(void); // sim_cmd.c int do_cmd(char *buf, FILE *f); // sim_mad.c int process_packet(Client * cl, void *p, int size, Client ** dcl); int send_trap(Port * port, unsigned trapnum); extern Port *default_port; extern int simverb; extern int netstarted; extern int maxnetnodes; extern int maxnetswitches; extern int maxnetports; extern int maxlinearcap; extern int maxmcastcap; extern int maxnetaliases; extern int ignoreduplicate; extern Node *nodes; extern Switch *switches; extern Port *ports; extern Port **lids; extern int netnodes, netports, netswitches; extern int parsedebug; #endif /* __SIM_H__ */ ibsim-0.12/ibsim/sim_cmd.c000066400000000000000000001022521432776202300154310ustar00rootroot00000000000000/* * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. * Copyright (c) 2010 Mellanox Technologies LTD. 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 #include #include #include #include #include #include #include #include #include #include #include "sim.h" #undef DEBUG #define PDEBUG if (parsedebug) IBWARN #define DEBUG if (simverb > 1 || ibdebug) IBWARN #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", "-", "-", "-", "-", "-", "-", "-", " 2x", }; static const char *portlinkspeed[] = { "-", " 2.5G", " 5.0G", "-", "10.0G", }; static const char *portlinkspeedext[] = { "0", " 14G", " 25G", "-", "50G", "-", "-", "-", "100G", }; static const char *portlinkmlnxspeed[] = { "0", " FDR10", }; #define PORTSTATE(i) (((i) < 1 || (i) > 4) ? "?" : portstates[(i)]) #define PHYSSTATE(i) (((i) < 1 || (i) > 6) ? "?" : physstates[(i)]) #define PORTLINKWIDTH(i) (((i) < 1 || (i) > 16) ? "?" : portlinkwidth[(i)]) #define PORTLINKSPEED(i) (((i) < 1 || (i) > 8) ? "?" : portlinkspeed[(i)]) #define PORTLINKSPEEDEXT(i) (((i) < 0 || (i) > 8) ? "?" : portlinkspeedext[(i)]) #define PORTMLNXLINKSPEED(i) (((i) < 0 || (i) > 1) ? "?" : portlinkmlnxspeed[(i)]) static int do_link(FILE * f, char *line) { Port *lport, *rport; Node *lnode, *rnode; char *orig = NULL; char *lnodeid = NULL; char *rnodeid = NULL; 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 = NULL; char *lnodeid = NULL; 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 = NULL; 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 = NULL, name[NAMELEN], *sp, *orig = NULL; int portnum = -1; // def - all ports int startport, numports, set = 0, rate = 0; uint16_t attr = 0; if (strsep(&s, "\"")) orig = strsep(&s, "\""); if (!s) { fprintf(f, "# set error: 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) { if (node->type == SWITCH_NODE) startport = 0; else startport = 1; portnum = strtoul(sp, NULL, 0); if (portnum < startport || 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, NULL, 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, NULL, 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 = NULL, name[NAMELEN], *sp, *orig = NULL; 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, NULL, 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 = NULL, *sp, *orig = NULL; 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, NULL, 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) sprintf(comment+n, "\t# err_attr %d", port->errattr); } static void dump_port(FILE * f, Port * port, int type) { char comment[100] = ""; static const char *link_speed_str; 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 (port->linkspeedext) link_speed_str = PORTLINKSPEEDEXT(port->linkspeedext); else if (port->mlnx_linkspeed) link_speed_str = PORTMLNXLINKSPEED(port->mlnx_linkspeed); else link_speed_str = PORTLINKSPEED(port->linkspeed); if (type == SWITCH_NODE && port->portnum) fprintf(f, "\t %s %s %s/%s%s\n", PORTLINKWIDTH(port->linkwidth), link_speed_str, PORTSTATE(port->state), PHYSSTATE(port->physstate), comment); else fprintf(f, "\t lid %u lmc %d smlid %u %s %s %s/%s%s\n", port->lid, port->lmc, port->smlid, PORTLINKWIDTH(port->linkwidth), link_speed_str, 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 = NULL; int nnodes = 0; time_t t = time(NULL); 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 = NULL; 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 NULL; } static int do_change_baselid(FILE * f, char *line) { Port *port; Node *node; char *s = line; char *nodeid = NULL, name[NAMELEN], *sp, *orig = NULL; 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, NULL, 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, NULL, 0); to = strtoul(p2, NULL, 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 %u\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]) == 0xff || 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 %u\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, NULL, 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, NULL, 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! - run commands from the file\n"); fprintf(f, "\tStart network\n"); fprintf(f, "\tDump [\"nodeid\"] : dump node information in network\n"); fprintf(f, "\tRoute \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] [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 : 21\n" ); fprintf(f, "\tPerformanceSet \"nodeid\"[port] [attribute].[field]=[value] : set perf. counters values\n"); fprintf(f, "\tBaselid \"nodeid\"[port] [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 : suspend simulator prompt\n"); fprintf(f, "\tAttached : list attached clients\n"); fprintf(f, "\tX : (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; } static uint64_t check_limit(uint64_t *value, uint64_t limit) { *value = (limit > *value? *value : limit); return *value; } static int parse_vl_num(char *attr, char *field, int *vl) { char *vl_ptr, *end_ptr; errno = 0; if(strlen(field) < strlen(attr) + 1) return -1; vl_ptr = field + strlen(attr); *vl = (int) strtol(vl_ptr, &end_ptr, 10); if(*vl == 0 && (errno != 0 || vl_ptr == end_ptr)) return -1; else if(*vl > 15 || *vl < 0) return -1; return 0; } static int do_perf_counter_set(FILE *f, char *line) { char *s = line, *orig = NULL, *sp, *nodeid, *attr, *field, *field_trim, *end_ptr; Node *node; int portnum, vl; uint64_t value; char name[NAMELEN]; Port *p; Portcounters *pc; if (strsep(&s, "\"")) orig = strsep(&s, "\""); if (!s) goto format_error; nodeid = expand_name(orig, name, &sp); if (!sp && *s == '[') sp = s + 1; if( !(node = find_node(nodeid))) { fprintf(f, "# nodeid \"%s\" (%s) not found\n", orig, nodeid); return -1; } if (sp == NULL) { fprintf(f, "# port number not found in command\n"); return -1; } portnum = strtoul(sp, &end_ptr, 0); if (end_ptr == sp) { fprintf(f, "# port number not found in command\n"); return -1; } if (!(p = node_get_port(node, portnum))) { fprintf(f, "# port %d not found from node %s\n", portnum, nodeid); return -1; } while (*s != '\0' && !isspace(*s)) s++; while (*s != '\0' && isspace(*s)) s++; attr = strsep(&s, "."); if(s == NULL) goto format_error; if(attr == NULL) { fprintf(f, "# attribute not found in command\n"); return -1; } field = strsep(&s, "="); if(s == NULL) goto format_error; if(field == NULL) { fprintf(f, "# field not found in command\n"); return -1; } field_trim = field + strlen(field) - 1; while(field_trim > field && isspace(*field_trim)) field_trim--; *(field_trim + 1) = 0; #ifndef ULLONG_MAX /* Maximum value an `unsigned long long int' can hold. (Minimum is 0.) */ # define ULLONG_MAX 18446744073709551615ULL #endif errno = 0; value = strtoull(s, &end_ptr, 0); if((value == 0 || value == ULLONG_MAX) && errno != 0) { fprintf(f, "# value '%s' is out of range [%d,%llu]\n", s, 0, ULLONG_MAX); return -1; } if(end_ptr == s || end_ptr == NULL || *end_ptr !='\0') { fprintf(f, "# value '%s' is not valid integer\n", s); return -1; } if (portnum < 0 || portnum > node->numports || (node->type != SWITCH_NODE && portnum == 0)) { fprintf(f, "# bad port number %d at nodeid \"%s\"\n", portnum, nodeid); return -1; } if (node->type == SWITCH_NODE && portnum == 0 && !mad_get_field(node->sw->switchinfo, 0, IB_SW_ENHANCED_PORT0_F)) { fprintf(f, "# Can't set performance counters of base switch port 0\n"); return -1; } pc = &(p->portcounters); if(!strcasecmp(attr, "PortCounters")) { if(!strcasecmp(field, "SymbolErrorCounter")) pc->errs_sym = check_limit(&value, GS_PERF_ERR_SYM_LIMIT); else if(!strcasecmp(field, "LinkErrorRecoveryCounter")) pc->linkrecovers = check_limit(&value, GS_PERF_LINK_RECOVERS_LIMIT); else if(!strcasecmp(field, "LinkDownedCounter")) pc->linkdowned = check_limit(&value, GS_PERF_LINK_DOWNED_LIMIT); else if(!strcasecmp(field, "PortRcvErrors")) pc->errs_rcv = check_limit(&value, GS_PERF_ERR_RCV_LIMIT); else if(!strcasecmp(field, "PortRcvRemotePhysicalErrors")) pc->errs_remphysrcv = check_limit(&value, GS_PERF_ERR_PHYSRCV_LIMIT); else if(!strcasecmp(field, "PortRcvSwitchRelayErrors")) pc->errs_rcvswitchrelay = check_limit(&value, GS_PERF_ERR_SWITCH_REL_LIMIT); else if(!strcasecmp(field, "PortXmitDiscards")) pc->xmitdiscards = check_limit(&value, GS_PERF_XMT_DISCARDS_LIMIT); else if(!strcasecmp(field, "PortXmitConstraintErrors")) pc->errs_xmtconstraint = check_limit(&value, GS_PERF_ERR_XMTCONSTR_LIMIT); else if(!strcasecmp(field, "PortRcvConstraintErrors")) pc->errs_rcvconstraint = check_limit(&value, GS_PERF_ERR_RCVCONSTR_LIMIT); else if(!strcasecmp(field, "LocalLinkIntegrityErrors")) pc->errs_localinteg = check_limit(&value, GS_PERF_ERR_LOCALINTEG_LIMIT); else if(!strcasecmp(field, "ExcessiveBufferOverrunErrors")) pc->errs_excessbufovrrun = check_limit(&value, GS_PERF_ERR_EXCESS_OVR_LIMIT); else if(!strcasecmp(field, "VL15Dropped")) pc->vl15dropped = check_limit(&value, GS_PERF_VL15_DROPPED_LIMIT); else if(!strcasecmp(field, "PortXmitData")) pc->flow_xmt_bytes = check_limit(&value, GS_PERF_XMT_BYTES_LIMIT); else if(!strcasecmp(field, "PortRcvData")) pc->flow_rcv_bytes = check_limit(&value, GS_PERF_RCV_BYTES_LIMIT); else if(!strcasecmp(field, "PortXmitPkts")) pc->flow_xmt_pkts = check_limit(&value, GS_PERF_XMT_PKTS_LIMIT); else if(!strcasecmp(field, "PortRcvPkts")) pc->flow_rcv_pkts = check_limit(&value, GS_PERF_RCV_PKTS_LIMIT); else if(!strcasecmp(field, "PortXmitWait")) pc->xmt_wait = check_limit(&value, GS_PERF_XMT_WAIT_LIMIT); else goto field_not_found; } else if(!strcasecmp(attr, "PortCountersExtended")) { if(!strcasecmp(field, "PortXmitData")) pc->ext_xmit_data = check_limit(&value, UINT64_MAX); else if(!strcasecmp(field, "PortRcvData")) pc->ext_recv_data = check_limit(&value, UINT64_MAX); else if(!strcasecmp(field, "PortXmitPkts")) pc->ext_xmit_pkts = check_limit(&value, UINT64_MAX); else if(!strcasecmp(field, "PortRcvPkts")) pc->ext_recv_pkts = check_limit(&value, UINT64_MAX); else if(!strcasecmp(field, "PortUnicastXmitPkts")) pc->ext_ucast_xmit = check_limit(&value, UINT64_MAX); else if(!strcasecmp(field, "PortUnicastRcvPkts")) pc->ext_ucast_recv = check_limit(&value, UINT64_MAX); else if(!strcasecmp(field, "PortMultiCastXmitPkts")) pc->ext_mcast_xmit = check_limit(&value, UINT64_MAX); else if(!strcasecmp(field, "PortMultiCastRcvPkts")) pc->ext_mcast_recv = check_limit(&value, UINT64_MAX); else goto field_not_found; } else if(!strcasecmp(attr, "PortRcvErrorDetails")) { if(!strcasecmp(field, "PortLocalPhysicalErrors")) pc->rcv_error_details.PortLocalPhysicalErrors = check_limit(&value, GS_PERF_LOCAL_PHYSICAL_ERRORS_LIMIT); else if(!strcasecmp(field, "PortMalformedPacketErrors")) pc->rcv_error_details.PortMalformedPacketErrors = check_limit(&value, GS_PERF_MALFORMED_PACKET_ERRORS_LIMIT); else if(!strcasecmp(field, "PortBufferOverrunErrors")) pc->rcv_error_details.PortBufferOverrunErrors = check_limit(&value, GS_PERF_BUFFER_OVERRUN_ERRORS_LIMIT); else if(!strcasecmp(field, "PortDLIDMappingErrors")) pc->rcv_error_details.PortDLIDMappingErrors = check_limit(&value, GS_PERF_DLID_MAPPING_ERRORS_LIMIT); else if(!strcasecmp(field, "PortVLMappingErrors")) pc->rcv_error_details.PortVLMappingErrors = check_limit(&value, GS_PERF_VL_MAPPING_ERRORS_LIMIT); else if(!strcasecmp(field, "PortLoopingErrors")) pc->rcv_error_details.PortLoopingErrors = check_limit(&value, GS_PERF_LOOPING_ERRORS_LIMIT); else goto field_not_found; } else if(!strcasecmp(attr, "PortXmitDiscardDetails")) { if(!strcasecmp(field, "PortInactiveDiscards")) pc->xmit_discard_details.PortInactiveDiscards = check_limit(&value, GS_PERF_INACTIVE_DISCARDS_LIMIT); else if(!strcasecmp(field, "PortNeighborMTUDiscards")) pc->xmit_discard_details.PortNeighborMTUDiscards = check_limit(&value, GS_PERF_NEIGHBOR_MTU_DISCARDS_LIMIT); else if(!strcasecmp(field, "PortSwLifetimeLimitDiscards")) pc->xmit_discard_details.PortSwLifetimeLimitDiscards = check_limit(&value, GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_LIMIT); else if(!strcasecmp(field, "PortSwHOQLifetimeLimitDiscards")) pc->xmit_discard_details.PortSwHOQLifetimeLimitDiscards = check_limit(&value, GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_LIMIT); else goto field_not_found; } else if(!strcasecmp(attr, "PortOpRcvCounters")) { if(!strcasecmp(field, "PortOpRcvPkts")) pc->op_rcv_counters.PortOpRcvPkts = check_limit(&value, GS_PERF_OP_RCV_PKTS_LIMIT); else if(!strcasecmp(field, "PortOpRcvData")) pc->op_rcv_counters.PortOpRcvData = check_limit(&value, GS_PERF_OP_RCV_DATA_LIMIT); else goto field_not_found; } else if(!strcasecmp(attr, "PortFlowCtlCounters")) { if(!strcasecmp(field, "PortXmitFlowPkts")) pc->flow_ctl_counters.PortXmitFlowPkts = check_limit(&value, GS_PERF_XMIT_FLOW_PKTS_LIMIT); else if(!strcasecmp(field, "PortRcvFlowPkts")) pc->flow_ctl_counters.PortRcvFlowPkts = check_limit(&value, GS_PERF_RCV_FLOW_PKTS_LIMIT); else goto field_not_found; } else if(!strcasecmp(attr, "PortVLOpPackets")) { if(strstr(field, "PortVLOpPackets") != field) goto field_not_found; if(parse_vl_num(attr, field, &vl) < 0) goto field_not_found; pc->vl_op_packets.PortVLOpPackets[vl] = check_limit(&value, GS_PERF_VL_OP_PACKETS_LIMIT); } else if(!strcasecmp(attr, "PortVLOpData")) { if(strstr(field, "PortVLOpData") != field) goto field_not_found; if(parse_vl_num(attr, field, &vl) < 0) goto field_not_found; pc->vl_op_data.PortVLOpData[vl] = check_limit(&value, GS_PERF_VL_OP_DATA_LIMIT); } else if(!strcasecmp(attr, "PortVLXmitFlowCtlUpdateErrors")) { if(strstr(field, "PortVLXmitFlowCtlUpdateErrors") != field) goto field_not_found; if(parse_vl_num(attr, field, &vl) < 0) goto field_not_found; pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[vl] = check_limit(&value, GS_PERF_VL_XMIT_FLOW_CTL_UPDATE_ERRORS); } else if(!strcasecmp(attr, "PortVLXmitWaitCounters")) { if(strstr(field, "PortVLXmitWaitCounters") != field) goto field_not_found; if(parse_vl_num(attr, field, &vl) < 0) goto field_not_found; pc->vl_xmit_wait_counters.PortVLXmitWait[vl] = check_limit(&value, GS_PERF_VL_XMIT_WAIT_COUNTERS_LIMIT); } else { fprintf(f, "# attribute %s not found\n", attr); return -1; } fprintf(f, "%s[%d] %s.%s has been set to %"PRIu64"\n", node->nodeid, p->portnum, attr, field, value); return 0; field_not_found: fprintf(f, "# field %s cannot be found in attribute %s\n", field, attr); return -1; format_error: fprintf(f, "# command does not match: PerformanceSet \"nodeid\"[port] [attribute].[field]=[value]\n"); return -1; } static int sim_cmd_file(FILE * f, char *s) { char line[4096]; FILE *cmd_file; char *p; if (!s) { fprintf(f, "do_cmd_from_file: no file name - skip\n"); return -1; } s++; while (isspace(*s)) s++; if (!*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) { if((p = strchr(line, '\n')) != NULL) *p = '\0'; do_cmd(line, f); } fclose(cmd_file); return 0; } int netstarted; static int match_command(char * line, char *cmd, unsigned int cmd_len) { if (cmd_len != strlen(cmd)) return 0; return !(strncasecmp(line, cmd, strlen(cmd))); } int do_cmd(char *buf, FILE *f) { unsigned int cmd_len = 0; char *line; int r = 0; unsigned int max_cmd_len, i; for (line = buf; *line && isspace(*line); line++) ; max_cmd_len = strlen(line); for (i = 0; i < max_cmd_len; i++) { if (!isspace(line[cmd_len])) cmd_len++; else break; } if (*line == '#') fprintf(f, "%s", line); else if (*line == '!') r = sim_cmd_file(f, line); else if (match_command(line, "Dump", cmd_len)) r = dump_net(f, line); else if (match_command(line, "Route", cmd_len)) r = dump_route(f, line); else if (match_command(line, "Link", cmd_len)) r = do_link(f, line); else if (match_command(line, "Unlink", cmd_len)) r = do_unlink(f, line, 0); else if (match_command(line, "Clear", cmd_len)) r = do_unlink(f, line, 1); else if (match_command(line, "Guid", cmd_len)) r = do_set_guid(f, line); else if (match_command(line, "Error", cmd_len)) r = do_seterror(f, line); else if (match_command(line, "Baselid", cmd_len)) r = do_change_baselid(f, line); else if (match_command(line, "Start", cmd_len)) { if (!netstarted) { DEBUG("starting..."); netstarted = 1; return 0; } } else if (match_command(line, "Verbose", cmd_len)) r = change_verbose(f, line); else if (match_command(line, "Wait", cmd_len)) r = do_wait(f, line); else if (match_command(line, "Attached", cmd_len)) r = list_connections(f); else if (match_command(line, "X", cmd_len)) r = do_disconnect_client(f, strtol(line + 2, NULL, 0)); else if (match_command(line, "Help", cmd_len) || match_command(line, "?", cmd_len)) r = dump_help(f); else if (match_command(line, "Quit", cmd_len)) { fprintf(f, "Exiting network simulator.\n"); free_core(); exit(0); } else if (match_command(line, "ReLink", cmd_len)) r = do_relink(f, line); else if (match_command(line, "PerformanceSet", cmd_len)) r = do_perf_counter_set(f, line); else if (*line != '\n' && *line != '\0') fprintf(f, "command \'%s\' unknown - skipped\n", line); return r; } ibsim-0.12/ibsim/sim_mad.c000066400000000000000000001715201432776202300154330ustar00rootroot00000000000000/* * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. * Copyright (c) 2009 HNR Consulting. All rights reserved. * Copyright (c) 2011 Mellanox Technologies LTD. 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 #include #include #include #include #include #include #include #include #include #include #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_rcv_error_details, do_xmit_discard_details, do_op_rcv_counters, do_flow_ctl_counters, do_vl_op_packets, do_vl_op_data, do_vl_xmit_flow_ctl_update_errors, do_vl_xmit_wait_counters, do_pkeytbl, do_sl2vl, do_vlarb, do_guidinfo, do_cpi, do_extportinfo; static EncodeTrapfn encode_trap128; static EncodeTrapfn encode_trap144; #define ATTRIBUTES_NUMBER 20 typedef struct { unsigned attr_id; Smpfn * handler; } attr_handler; typedef struct { unsigned class_id; attr_handler handlers[ATTRIBUTES_NUMBER]; } class_handler; static class_handler smp_handlers_array[] = { {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_MLNX_EXT_PORT_INFO, do_extportinfo}, {UINT_MAX, NULL} } }, {IB_SMI_DIRECT_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_MLNX_EXT_PORT_INFO, do_extportinfo}, {UINT_MAX, NULL} } }, {IB_PERFORMANCE_CLASS, { {CLASS_PORT_INFO, do_cpi}, {IB_GSI_PORT_SAMPLES_CONTROL, NULL}, {IB_GSI_PORT_SAMPLES_RESULT, NULL}, {IB_GSI_PORT_COUNTERS, do_portcounters}, {IB_GSI_PORT_COUNTERS_EXT, do_extcounters}, {IB_GSI_PORT_RCV_ERROR_DETAILS, do_rcv_error_details}, {IB_GSI_PORT_XMIT_DISCARD_DETAILS, do_xmit_discard_details}, {IB_GSI_PORT_PORT_OP_RCV_COUNTERS, do_op_rcv_counters}, {IB_GSI_PORT_PORT_FLOW_CTL_COUNTERS, do_flow_ctl_counters}, {IB_GSI_PORT_PORT_VL_OP_PACKETS, do_vl_op_packets}, {IB_GSI_PORT_PORT_VL_OP_DATA, do_vl_op_data}, {IB_GSI_PORT_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS, do_vl_xmit_flow_ctl_update_errors}, {IB_GSI_PORT_PORT_VL_XMIT_WAIT_COUNTERS, do_vl_xmit_wait_counters}, {UINT_MAX, NULL} } } , {UINT_MAX, {}} }; static Smpfn * get_smp_handler(unsigned class_id, unsigned attr_id) { int i, j; for (i = 0; smp_handlers_array[i].class_id != UINT_MAX; i++ ) { if (smp_handlers_array[i].class_id != class_id) continue; for (j = 0; smp_handlers_array[i].handlers[j].attr_id != UINT_MAX; j++) { if (smp_handlers_array[i].handlers[j].attr_id != attr_id) continue; return smp_handlers_array[i].handlers[j].handler; } } return NULL; } static EncodeTrapfn *encodetrap[] = { [TRAP_128] = encode_trap128, [TRAP_144] = encode_trap144, [TRAP_NUM_LAST] = NULL, }; extern Node *nodes; extern Switch *switchs; extern Port *ports; extern Port **lids; extern int netnodes, netports, netswitches; extern int maxlinearcap; typedef void (*pc_reset_function)(Portcounters * pc, unsigned mask); typedef void (*pc_get_function)(Portcounters * pc, uint8_t * data); typedef void (*pc_sum_function)(Portcounters * totals, Portcounters * pc); static uint64_t update_trid(uint8_t *mad, unsigned response, Client *cl) { uint64_t trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); 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_cpi(Port * port, unsigned op, uint32_t mod, uint8_t * data) { Node *node = port->node; int status = 0; if (op != IB_MAD_METHOD_GET) status = ERR_METHOD_UNSUPPORTED; memset(data, 0, IB_SMP_DATA_SIZE); mad_set_field(data, 0, IB_CPI_BASEVER_F, 1); mad_set_field(data, 0, IB_CPI_CLASSVER_F, 1); if (node->type != SWITCH_NODE) mad_set_field(data, 0, IB_CPI_CAPMASK_F, IB_PM_EXT_WIDTH_SUPPORTED|IB_PM_PC_XMIT_WAIT_SUP); else mad_set_field(data, 0, IB_CPI_CAPMASK_F, IB_PM_ALL_PORT_SELECT|IB_PM_EXT_WIDTH_SUPPORTED|IB_PM_PC_XMIT_WAIT_SUP); mad_set_field(data, 0, IB_CPI_RESP_TIME_VALUE_F, 0x12); return status; } static int do_nodedesc(Port * port, unsigned op, uint32_t mod, uint8_t * data) { int status = 0; if (op != IB_MAD_METHOD_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) 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 == IB_MAD_METHOD_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, IB_SMP_DATA_SIZE); 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, IB_SMP_DATA_SIZE); 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 = NULL; int r, newlid; int speed, espeed, width; portnum &= 0x7fffffff; 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) { 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] = NULL; } 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 */ 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) 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 %u (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; p->subnet_prefix = mad_get_field64(data, 0, IB_PORT_GID_PREFIX_F); if (!rp && p->remotenode) rp = node_get_port(p->remotenode, p->remoteport); else goto update_port; speed = mad_get_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F); switch (speed) { case LINKSPEED_SDR: p->linkspeed = LINKSPEED_SDR; rp->linkspeed = LINKSPEED_SDR; break; case LINKSPEED_SDR_DDR: p->linkspeed = LINKSPEED_DDR; rp->linkspeed = LINKSPEED_DDR; break; case LINKSPEED_SDR_QDR: case LINKSPEED_SDR_DDR_QDR: p->linkspeed = LINKSPEED_QDR; rp->linkspeed = LINKSPEED_QDR; break; default: speed = 0; } if (speed && speed != p->linkspeedena) p->linkspeedena = speed; else speed = 0; espeed = mad_get_field(data, 0, IB_PORT_LINK_SPEED_EXT_ENABLED_F); switch (espeed) { case LINKSPEEDEXT_FDR: p->linkspeedext = LINKSPEEDEXT_FDR; rp->linkspeedext = LINKSPEEDEXT_FDR; break; case LINKSPEEDEXT_EDR: case LINKSPEEDEXT_FDR_EDR: p->linkspeedext = LINKSPEEDEXT_EDR; rp->linkspeedext = LINKSPEEDEXT_EDR; break; case LINKSPEEDEXT_HDR: case LINKSPEEDEXT_HDR_FDR: case LINKSPEEDEXT_HDR_EDR: case LINKSPEEDEXT_HDR_EDR_FDR: p->linkspeedext = LINKSPEEDEXT_HDR; rp->linkspeedext = LINKSPEEDEXT_HDR; break; case LINKSPEEDEXT_NDR: case LINKSPEEDEXT_NDR_FDR: case LINKSPEEDEXT_NDR_EDR: case LINKSPEEDEXT_NDR_FDR_EDR: case LINKSPEEDEXT_NDR_HDR: case LINKSPEEDEXT_NDR_HDR_FDR: case LINKSPEEDEXT_NDR_HDR_EDR: case LINKSPEEDEXT_NDR_HDR_EDR_FDR: p->linkspeedext = LINKSPEEDEXT_NDR; rp->linkspeedext = LINKSPEEDEXT_NDR; break; default: espeed = 0; } if (espeed && espeed != p->linkspeedextena) p->linkspeedextena = espeed; else espeed = 0; width = mad_get_field(data, 0, IB_PORT_LINK_WIDTH_ENABLED_F); switch (width) { case LINKWIDTH_1x: p->linkwidth = LINKWIDTH_1x; rp->linkwidth = LINKWIDTH_1x; break; case LINKWIDTH_4x: case LINKWIDTH_1x_4x: case LINKWIDTH_2x_4x: case LINKWIDTH_1x_2x_4x: p->linkwidth = LINKWIDTH_4x; rp->linkwidth = LINKWIDTH_4x; break; case LINKWIDTH_8x: case LINKWIDTH_1x_8x: case LINKWIDTH_4x_8x: case LINKWIDTH_1x_4x_8x: case LINKWIDTH_2x_8x: case LINKWIDTH_1x_2x_8x: case LINKWIDTH_2x_4x_8x: case LINKWIDTH_1x_2x_4x_8x: p->linkwidth = LINKWIDTH_8x; rp->linkwidth = LINKWIDTH_8x; break; case LINKWIDTH_12x: case LINKWIDTH_1x_12x: case LINKWIDTH_4x_12x: case LINKWIDTH_1x_4x_12x: case LINKWIDTH_8x_12x: case LINKWIDTH_1x_8x_12x: case LINKWIDTH_4x_8x_12x: case LINKWIDTH_1x_4x_8x_12x: case LINKWIDTH_2x_12x: case LINKWIDTH_1x_2x_12x: case LINKWIDTH_2x_4x_12x: case LINKWIDTH_1x_2x_4x_12x: case LINKWIDTH_2x_8x_12x: case LINKWIDTH_1x_2x_8x_12x: case LINKWIDTH_2x_4x_8x_12x: case LINKWIDTH_1x_2x_4x_8x_12x: p->linkwidth = LINKWIDTH_12x; rp->linkwidth = LINKWIDTH_12x; break; case LINKWIDTH_2x: case LINKWIDTH_1x_2x: p->linkwidth = LINKWIDTH_2x; rp->linkwidth = LINKWIDTH_2x; break; default: width = 0; } if (width && width != p->linkwidthena) p->linkwidthena = width; else width = 0; if (speed || espeed || width) send_trap(port, TRAP_144); } update_port: update_portinfo(p); memcpy(data, p->portinfo, IB_SMP_DATA_SIZE); mad_set_field(data, 0, IB_PORT_LOCAL_PORT_F, port->portnum); return 0; } static int do_extportinfo(Port * port, unsigned op, uint32_t portnum, uint8_t * data) { Node *node = port->node; Port *p; 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) { memcpy(p->extportinfo, data, IB_SMP_DATA_SIZE); } else memcpy(data, p->extportinfo, 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 > 767) return ERR_BAD_PARAM; if (op == IB_MAD_METHOD_SET) mad_get_array(data, 0, IB_LINEAR_FORW_TBL_F, sw->fdb + mod * 64); mad_set_array(data, 0, IB_LINEAR_FORW_TBL_F, sw->fdb + mod * 64); 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 >= sw->numportmask) { int8_t zeroblock[64] = { 0 }; mad_set_array(data, 0, IB_MULTICAST_FORW_TBL_F, zeroblock); return 0; } blockposition = (numBlock32 * sw->numportmask + numPortMsk) * 64; if (op == IB_MAD_METHOD_SET) mad_get_array(data, 0, IB_MULTICAST_FORW_TBL_F, sw->mfdb + blockposition); mad_set_array(data, 0, IB_MULTICAST_FORW_TBL_F, sw->mfdb + blockposition); return 0; } static void pc_reset(Portcounters * pc, unsigned 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; if (mask & GS_PERF_XMT_WAIT_MASK) pc->xmt_wait = 0; } static inline uint32_t addval(uint32_t val, uint32_t delta, uint32_t max) { 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 ; } static void pc_add_error_xmitdiscards(Port * port) { Portcounters *pc = &(port->portcounters); pc->xmitdiscards = addval(pc->xmitdiscards, 1, GS_PERF_XMT_DISCARDS_LIMIT); } static 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); } static 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 got 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(srcpc->ext_xmit_data, madsize_div_4); ADDVAL64(srcpc->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 got into 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->xmt_wait = addval(totals->xmt_wait, pc->xmt_wait, GS_PERF_XMT_WAIT_LIMIT); totals->flow_xmt_pkts = addval(totals->flow_xmt_pkts, pc->flow_xmt_pkts, GS_PERF_XMT_PKTS_LIMIT); 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_WAIT_F, pc->xmt_wait); mad_set_field(data, 0, IB_PC_XMT_PKTS_F, pc->flow_xmt_pkts); mad_set_field(data, 0, IB_PC_XMT_BYTES_F, pc->flow_xmt_bytes); mad_set_field(data, 0, IB_PC_RCV_PKTS_F, pc->flow_rcv_pkts); 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; unsigned mask, mask2; 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); mask2 = mad_get_field(data, 0, IB_PC_COUNTER_SELECT2_F); if (mask2) mask |= GS_PERF_XMT_WAIT_MASK; if (portnum != 0xff) { if (!(p = node_get_port(node, portnum))) 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, unsigned 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 int do_portcounters_common(Port * port, unsigned op, uint32_t unused, uint8_t * data, pc_reset_function pc_reset_ptr, pc_get_function pc_get_ptr, pc_sum_function pc_sum_ptr) { Node *node = port->node; unsigned portnum; Portcounters totals; unsigned mask; Port *p; int i; portnum = mad_get_field(data, 0, IB_PC_PORT_SELECT_F); if (node->type != SWITCH_NODE && portnum != port->portnum) return ERR_BAD_PARAM; if (node->type == SWITCH_NODE && portnum > node->numports && portnum != 0xff) return ERR_BAD_PARAM; DEBUG("in node %" PRIx64 " port %" PRIx64 " portnum %u", node->nodeguid, port->portguid, portnum); mask = mad_get_field(data, 0, IB_PC_COUNTER_SELECT_F); if (portnum != 0xff) { if (!(p = node_get_port(node, portnum))) return ERR_BAD_PARAM; if (op == IB_MAD_METHOD_SET) pc_reset_ptr(&p->portcounters, mask); pc_get_ptr(&p->portcounters, data); return 0; } memset(&totals, 0, sizeof totals); for (i = 0; i <= node->numports; i++) { if (!(p = node_get_port(node, i))) return ERR_BAD_PARAM; if (op == IB_MAD_METHOD_SET) pc_reset_ptr(&p->portcounters, mask); pc_sum_ptr(&totals, &p->portcounters); } pc_get_ptr(&totals, data); return 0; } static void pc_rcv_error_details_get(Portcounters * pc, uint8_t * data) { mad_set_field(data, 0, IB_PC_RCV_LOCAL_PHY_ERR_F, pc->rcv_error_details.PortLocalPhysicalErrors); mad_set_field(data, 0, IB_PC_RCV_MALFORMED_PKT_ERR_F, pc->rcv_error_details.PortMalformedPacketErrors); mad_set_field(data, 0, IB_PC_RCV_BUF_OVR_ERR_F, pc->rcv_error_details.PortBufferOverrunErrors); mad_set_field(data, 0, IB_PC_RCV_DLID_MAP_ERR_F, pc->rcv_error_details.PortDLIDMappingErrors); mad_set_field(data, 0, IB_PC_RCV_VL_MAP_ERR_F, pc->rcv_error_details.PortVLMappingErrors); mad_set_field(data, 0, IB_PC_RCV_LOOPING_ERR_F, pc->rcv_error_details.PortLoopingErrors); } static void pc_rcv_error_details_sum(Portcounters * totals, Portcounters * pc) { totals->rcv_error_details.PortLocalPhysicalErrors = addval(totals->rcv_error_details.PortLocalPhysicalErrors, pc->rcv_error_details.PortLocalPhysicalErrors, GS_PERF_LOCAL_PHYSICAL_ERRORS_LIMIT); totals->rcv_error_details.PortMalformedPacketErrors = addval(totals->rcv_error_details.PortMalformedPacketErrors, pc->rcv_error_details.PortMalformedPacketErrors, GS_PERF_MALFORMED_PACKET_ERRORS_LIMIT); totals->rcv_error_details.PortBufferOverrunErrors = addval(totals->rcv_error_details.PortBufferOverrunErrors, pc->rcv_error_details.PortBufferOverrunErrors, GS_PERF_BUFFER_OVERRUN_ERRORS_LIMIT); totals->rcv_error_details.PortDLIDMappingErrors = addval(totals->rcv_error_details.PortDLIDMappingErrors, pc->rcv_error_details.PortDLIDMappingErrors, GS_PERF_DLID_MAPPING_ERRORS_LIMIT); totals->rcv_error_details.PortVLMappingErrors = addval(totals->rcv_error_details.PortVLMappingErrors, pc->rcv_error_details.PortVLMappingErrors, GS_PERF_VL_MAPPING_ERRORS_LIMIT); totals->rcv_error_details.PortLoopingErrors = addval(totals->rcv_error_details.PortLoopingErrors, pc->rcv_error_details.PortLoopingErrors, GS_PERF_LOOPING_ERRORS_LIMIT); } static void pc_rcv_error_details_reset(Portcounters * pc, unsigned mask) { if(mask & GS_PERF_LOCAL_PHYSICAL_ERRORS_MASK) pc->rcv_error_details.PortLocalPhysicalErrors = 0; if(mask & GS_PERF_MALFORMED_PACKET_ERRORS_MASK) pc->rcv_error_details.PortMalformedPacketErrors = 0; if(mask & GS_PERF_BUFFER_OVERRUN_ERRORS_MASK) pc->rcv_error_details.PortBufferOverrunErrors = 0; if(mask & GS_PERF_DLID_MAPPING_ERRORS_MASK) pc->rcv_error_details.PortDLIDMappingErrors = 0; if(mask & GS_PERF_VL_MAPPING_ERRORS_MASK) pc->rcv_error_details.PortVLMappingErrors = 0; if(mask & GS_PERF_LOOPING_ERRORS_MASK) pc->rcv_error_details.PortLoopingErrors = 0; } static int do_rcv_error_details(Port * port, unsigned op, uint32_t unused, uint8_t * data) { return do_portcounters_common(port, op, unused, data, pc_rcv_error_details_reset, pc_rcv_error_details_get, pc_rcv_error_details_sum); } static void pc_xmit_discard_details_get(Portcounters * pc, uint8_t * data) { mad_set_field(data, 0, IB_PC_XMT_INACT_DISC_F, pc->xmit_discard_details.PortInactiveDiscards); mad_set_field(data, 0, IB_PC_XMT_NEIGH_MTU_DISC_F, pc->xmit_discard_details.PortNeighborMTUDiscards); mad_set_field(data, 0, IB_PC_XMT_SW_LIFE_DISC_F, pc->xmit_discard_details.PortSwLifetimeLimitDiscards); mad_set_field(data, 0, IB_PC_XMT_SW_HOL_DISC_F, pc->xmit_discard_details.PortSwHOQLifetimeLimitDiscards); } static void pc_xmit_discard_details_sum(Portcounters * totals, Portcounters * pc) { totals->xmit_discard_details.PortInactiveDiscards = addval(totals->xmit_discard_details.PortInactiveDiscards, pc->xmit_discard_details.PortInactiveDiscards, GS_PERF_INACTIVE_DISCARDS_LIMIT); totals->xmit_discard_details.PortNeighborMTUDiscards = addval(totals->xmit_discard_details.PortNeighborMTUDiscards, pc->xmit_discard_details.PortNeighborMTUDiscards, GS_PERF_NEIGHBOR_MTU_DISCARDS_LIMIT); totals->xmit_discard_details.PortSwLifetimeLimitDiscards = addval(totals->xmit_discard_details.PortSwLifetimeLimitDiscards, pc->xmit_discard_details.PortSwLifetimeLimitDiscards, GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_LIMIT); totals->xmit_discard_details.PortSwHOQLifetimeLimitDiscards = addval(totals->xmit_discard_details.PortSwHOQLifetimeLimitDiscards, pc->xmit_discard_details.PortSwHOQLifetimeLimitDiscards, GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_LIMIT); } static void pc_xmit_discard_details_reset(Portcounters * pc, unsigned mask) { if(mask & GS_PERF_INACTIVE_DISCARDS_MASK) pc->xmit_discard_details.PortInactiveDiscards = 0; if(mask & GS_PERF_NEIGHBOR_MTU_DISCARDS_MASK) pc->xmit_discard_details.PortNeighborMTUDiscards = 0; if(mask & GS_PERF_SW_LIFETIME_LIMIT_DISCARDS_MASK) pc->xmit_discard_details.PortSwLifetimeLimitDiscards = 0; if(mask & GS_PERF_SW_HOQ_LIFETIME_LIMIT_DISCARDS_MASK) pc->xmit_discard_details.PortSwHOQLifetimeLimitDiscards = 0; } static int do_xmit_discard_details(Port * port, unsigned op, uint32_t unused, uint8_t * data) { return do_portcounters_common(port, op, unused, data, pc_xmit_discard_details_reset, pc_xmit_discard_details_get, pc_xmit_discard_details_sum); } static void pc_op_rcv_counters_get(Portcounters * pc, uint8_t * data) { mad_set_field(data, 0, IB_PC_PORT_OP_RCV_PKTS_F, pc->op_rcv_counters.PortOpRcvPkts); mad_set_field(data, 0, IB_PC_PORT_OP_RCV_DATA_F, pc->op_rcv_counters.PortOpRcvData); } static void pc_op_rcv_counters_sum(Portcounters * totals, Portcounters * pc) { totals->op_rcv_counters.PortOpRcvPkts = addval(totals->op_rcv_counters.PortOpRcvPkts, pc->op_rcv_counters.PortOpRcvPkts, GS_PERF_OP_RCV_PKTS_LIMIT); totals->op_rcv_counters.PortOpRcvData = addval(totals->op_rcv_counters.PortOpRcvData, pc->op_rcv_counters.PortOpRcvData, GS_PERF_OP_RCV_DATA_LIMIT); } static void pc_op_rcv_counters_reset(Portcounters * pc, unsigned mask) { if(mask & GS_PERF_OP_RCV_PKTS_MASK) pc->op_rcv_counters.PortOpRcvPkts = 0; if(mask & GS_PERF_OP_RCV_DATA_MASK) pc->op_rcv_counters.PortOpRcvData = 0; } static int do_op_rcv_counters(Port * port, unsigned op, uint32_t unused, uint8_t * data) { return do_portcounters_common(port, op, unused, data, pc_op_rcv_counters_reset, pc_op_rcv_counters_get, pc_op_rcv_counters_sum); } static void pc_flow_ctl_counters_get(Portcounters * pc, uint8_t * data) { mad_set_field(data, 0, IB_PC_PORT_XMIT_FLOW_PKTS_F, pc->flow_ctl_counters.PortXmitFlowPkts); mad_set_field(data, 0, IB_PC_PORT_RCV_FLOW_PKTS_F, pc->flow_ctl_counters.PortRcvFlowPkts); } static void pc_flow_ctl_counters_sum(Portcounters * totals, Portcounters * pc) { totals->flow_ctl_counters.PortXmitFlowPkts = addval(totals->flow_ctl_counters.PortXmitFlowPkts, pc->flow_ctl_counters.PortXmitFlowPkts, GS_PERF_XMIT_FLOW_PKTS_LIMIT); totals->flow_ctl_counters.PortRcvFlowPkts = addval(totals->flow_ctl_counters.PortRcvFlowPkts, pc->flow_ctl_counters.PortRcvFlowPkts, GS_PERF_RCV_FLOW_PKTS_LIMIT); } static void pc_flow_ctl_counters_reset(Portcounters * pc, unsigned mask) { if(mask & GS_PERF_XMIT_FLOW_PKTS_MASK) pc->flow_ctl_counters.PortXmitFlowPkts = 0; if(mask & GS_PERF_RCV_FLOW_PKTS_MASK) pc->flow_ctl_counters.PortRcvFlowPkts = 0; } static int do_flow_ctl_counters(Port * port, unsigned op, uint32_t unused, uint8_t * data) { return do_portcounters_common(port, op, unused, data, pc_flow_ctl_counters_reset, pc_flow_ctl_counters_get, pc_flow_ctl_counters_sum); } static void pc_vl_op_packets_get(Portcounters * pc, uint8_t * data) { mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS0_F, pc->vl_op_packets.PortVLOpPackets[0]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS1_F, pc->vl_op_packets.PortVLOpPackets[1]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS2_F, pc->vl_op_packets.PortVLOpPackets[2]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS3_F, pc->vl_op_packets.PortVLOpPackets[3]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS4_F, pc->vl_op_packets.PortVLOpPackets[4]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS5_F, pc->vl_op_packets.PortVLOpPackets[5]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS6_F, pc->vl_op_packets.PortVLOpPackets[6]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS7_F, pc->vl_op_packets.PortVLOpPackets[7]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS8_F, pc->vl_op_packets.PortVLOpPackets[8]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS9_F, pc->vl_op_packets.PortVLOpPackets[9]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS10_F, pc->vl_op_packets.PortVLOpPackets[10]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS11_F, pc->vl_op_packets.PortVLOpPackets[11]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS12_F, pc->vl_op_packets.PortVLOpPackets[12]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS13_F, pc->vl_op_packets.PortVLOpPackets[13]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS14_F, pc->vl_op_packets.PortVLOpPackets[14]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_PACKETS15_F, pc->vl_op_packets.PortVLOpPackets[15]); } static void pc_vl_op_packets_sum(Portcounters * totals, Portcounters * pc) { int i; for(i = 0; i < 16; i++) totals->vl_op_packets.PortVLOpPackets[i] = addval(totals->vl_op_packets.PortVLOpPackets[i], pc->vl_op_packets.PortVLOpPackets[i], GS_PERF_VL_OP_PACKETS_LIMIT); } static void pc_vl_op_packets_reset(Portcounters * pc, unsigned mask) { int i; for(i = 0; i < 16; i++) if(mask & (1UL << i)) pc->vl_op_packets.PortVLOpPackets[i] = 0; } static int do_vl_op_packets(Port * port, unsigned op, uint32_t unused, uint8_t * data) { return do_portcounters_common(port, op, unused, data, pc_vl_op_packets_reset, pc_vl_op_packets_get, pc_vl_op_packets_sum); } static void pc_vl_op_data_get(Portcounters * pc, uint8_t * data) { mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA0_F, pc->vl_op_data.PortVLOpData[0]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA1_F, pc->vl_op_data.PortVLOpData[1]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA2_F, pc->vl_op_data.PortVLOpData[2]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA3_F, pc->vl_op_data.PortVLOpData[3]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA4_F, pc->vl_op_data.PortVLOpData[4]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA5_F, pc->vl_op_data.PortVLOpData[5]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA6_F, pc->vl_op_data.PortVLOpData[6]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA7_F, pc->vl_op_data.PortVLOpData[7]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA8_F, pc->vl_op_data.PortVLOpData[8]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA9_F, pc->vl_op_data.PortVLOpData[9]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA10_F, pc->vl_op_data.PortVLOpData[10]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA11_F, pc->vl_op_data.PortVLOpData[11]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA12_F, pc->vl_op_data.PortVLOpData[12]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA13_F, pc->vl_op_data.PortVLOpData[13]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA14_F, pc->vl_op_data.PortVLOpData[14]); mad_set_field(data, 0, IB_PC_PORT_VL_OP_DATA15_F, pc->vl_op_data.PortVLOpData[15]); } static void pc_vl_op_data_sum(Portcounters * totals, Portcounters * pc) { int i; for(i = 0; i < 16; i++) totals->vl_op_data.PortVLOpData[i] = addval(totals->vl_op_data.PortVLOpData[i], pc->vl_op_data.PortVLOpData[i], GS_PERF_VL_OP_DATA_LIMIT); } static void pc_vl_op_data_reset(Portcounters * pc, unsigned mask) { int i; for(i = 0; i < 16; i++) { if(mask & (1UL << i)) pc->vl_op_data.PortVLOpData[i] = 0; } } static int do_vl_op_data(Port * port, unsigned op, uint32_t unused, uint8_t * data) { return do_portcounters_common(port, op, unused, data, pc_vl_op_data_reset, pc_vl_op_data_get, pc_vl_op_data_sum); } static void pc_vl_xmit_flow_ctl_update_errors_get(Portcounters * pc, uint8_t * data) { mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS0_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[0]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS1_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[1]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS2_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[2]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS3_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[3]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS4_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[4]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS5_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[5]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS6_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[6]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS7_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[7]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS8_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[8]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS9_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[9]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS10_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[10]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS11_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[11]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS12_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[12]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS13_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[13]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS14_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[14]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS15_F, pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[15]); } static void pc_vl_xmit_flow_ctl_update_errors_sum(Portcounters * totals, Portcounters * pc) { int i; for(i = 0; i < 16; i++) totals->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[i] = addval(totals->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[i], pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[i], GS_PERF_VL_XMIT_FLOW_CTL_UPDATE_ERRORS); } static void pc_vl_xmit_flow_ctl_update_errors_reset(Portcounters * pc, unsigned mask) { int i; for(i = 0; i < 16; i++) if(mask & (1UL << i)) pc->vl_xmit_flow_ctl_update_errors.PortVLXmitFlowCtlUpdateErrors[i] = 0; } static int do_vl_xmit_flow_ctl_update_errors(Port * port, unsigned op, uint32_t unused, uint8_t * data) { return do_portcounters_common(port, op, unused, data, pc_vl_xmit_flow_ctl_update_errors_reset, pc_vl_xmit_flow_ctl_update_errors_get, pc_vl_xmit_flow_ctl_update_errors_sum); } static void pc_vl_xmit_wait_counters_get(Portcounters * pc, uint8_t * data) { mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT0_F, pc->vl_xmit_wait_counters.PortVLXmitWait[0]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT1_F, pc->vl_xmit_wait_counters.PortVLXmitWait[1]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT2_F, pc->vl_xmit_wait_counters.PortVLXmitWait[2]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT3_F, pc->vl_xmit_wait_counters.PortVLXmitWait[3]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT4_F, pc->vl_xmit_wait_counters.PortVLXmitWait[4]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT5_F, pc->vl_xmit_wait_counters.PortVLXmitWait[5]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT6_F, pc->vl_xmit_wait_counters.PortVLXmitWait[6]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT7_F, pc->vl_xmit_wait_counters.PortVLXmitWait[7]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT8_F, pc->vl_xmit_wait_counters.PortVLXmitWait[8]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT9_F, pc->vl_xmit_wait_counters.PortVLXmitWait[9]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT10_F, pc->vl_xmit_wait_counters.PortVLXmitWait[10]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT11_F, pc->vl_xmit_wait_counters.PortVLXmitWait[11]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT12_F, pc->vl_xmit_wait_counters.PortVLXmitWait[12]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT13_F, pc->vl_xmit_wait_counters.PortVLXmitWait[13]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT14_F, pc->vl_xmit_wait_counters.PortVLXmitWait[14]); mad_set_field(data, 0, IB_PC_PORT_VL_XMIT_WAIT15_F, pc->vl_xmit_wait_counters.PortVLXmitWait[15]); } static void pc_vl_xmit_wait_counters_sum(Portcounters * totals, Portcounters * pc) { int i; for(i = 0; i < 16; i++) totals->vl_xmit_wait_counters.PortVLXmitWait[i] = addval(totals->vl_xmit_wait_counters.PortVLXmitWait[i], pc->vl_xmit_wait_counters.PortVLXmitWait[i], GS_PERF_VL_XMIT_WAIT_COUNTERS_LIMIT); } static void pc_vl_xmit_wait_counters_reset(Portcounters * pc, unsigned mask) { int i; for(i = 0; i < 16; i++) if(mask & (1UL << i)) pc->vl_xmit_wait_counters.PortVLXmitWait[i] = 0; } static int do_vl_xmit_wait_counters(Port * port, unsigned op, uint32_t unused, uint8_t * data) { return do_portcounters_common(port, op, unused, data, pc_vl_xmit_wait_counters_reset, pc_vl_xmit_wait_counters_get, pc_vl_xmit_wait_counters_sum); } static char *pathstr(int lid, ib_dr_path_t * path) { static char buf[1024] = "local"; unsigned n = 0; int i; if (0 && lid != -1) { sprintf(buf, "lid %u", 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 %u", node->nodeguid, lid); if (!node->sw) return -1; if (lid > node->sw->linearFDBtop || (outport = node->sw->fdb[lid]) == 0xff) { IBWARN("sw guid %" PRIx64 ": bad lid %u", 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 %u lmc %d target lid %u", port->portguid, port->lid, port->lmc, lid); if (lid < port->lid || lid > port->lid + (1 << port->lmc) - 1) return 0; 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 %u", node->nodeguid, port->portguid, port->portnum, lid); if (lid == 0) { IBWARN("invalid lid 0"); return NULL; } 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 NULL; } if (!pc_updated(&tport, port)) // if Client connected via HCA ... return NULL; 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 %u (outport %d node %s ports %d)", lid, portnum, node->nodeid, node->numports); return NULL; } 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 NULL; } 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 NULL; } if (!node || !port) // double check ?... IBPANIC("bad node %p or port %p", node, port); if (!link_valid(port)) { pc_add_error_xmitdiscards(tport); return NULL; } if (!pc_updated(&tport, port)) //try to transmit PKT return NULL; } 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); } static Smpfn *get_handle_fn(ib_rpc_t rpc, int response) { Smpfn *fn; if (response) return NULL; fn = get_smp_handler(rpc.mgtclass & 0xf , rpc.attr.id); return fn; } 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("lid %u got trap repress - dropping", ntohs(r->dlid)); *dcl = NULL; return 0; } if (!(port = route_MAD(cl->port, response, ntohs(r->dlid), &path))) { IBWARN("routing failed: no route to dest lid %u 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; 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 %u with smlid %u", 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 %u with smlid %u", 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, unsigned trapnum) { struct sim_request req; Client *cl; int ret, lid = port->lid; char *data = req.mad + 64; /* data offset */ EncodeTrapfn *encode_trapfn; Port *destport; if (trapnum >= TRAP_NUM_LAST) { IBWARN("trap number %d not supported", trapnum); return -1; } encode_trapfn = encodetrap[trapnum]; memset(&req, 0, sizeof(req)); 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 %u", port->smlid); return -1; } req.dlid = htons(port->smlid); req.slid = htons(lid); 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; } ibsim-0.12/ibsim/sim_net.c000066400000000000000000001164271432776202300154650ustar00rootroot00000000000000/* * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. * Copyright (c) 2011 Mellanox Technologies LTD. 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sim.h" #undef DEBUG #define PDEBUG if (parsedebug) IBWARN #define DEBUG if (simverb || ibdebug) IBWARN #define MAX_INCLUDE 9 #define LINKSPEED_STR_SDR "SDR" #define LINKSPEED_STR_DDR "DDR" #define LINKSPEED_STR_QDR "QDR" #define LINKSPEED_STR_FDR "FDR" #define LINKSPEED_STR_EDR "EDR" #define LINKSPEED_STR_HDR "HDR" #define LINKSPEED_STR_NDR "NDR" #define LINKSPEED_STR_FDR10 "FDR10" static int inclines[MAX_INCLUDE]; static char *incfiles[MAX_INCLUDE]; static int inclevel; 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, 0xC0, 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, 0x04, 0x30, 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, 0x12, 0x52, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08, 0x08, 0x04, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 /* 0x11 */, 0x01, }; 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, 0x01 /* 0x11 */, 0x01, }; 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, 0x40, 0xC0, 0x48, 0x00, 0x00, 0x0F, 0xF9, 0x01, 0x03, 0x03, 0x02, 0x12, 0x52, 0x00, 0x11, 0x40, 0x40, 0x00, 0x08, 0x08, 0x04, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x30, 0x01 /* 0x11 */, 0x01, }; 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, 0xC0, 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, 0x04, 0x30, 0x01 /* 0x11 */, 0x01, }; 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@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; static char (*aliases)[NODEIDLEN + NODEPREFIX + 1]; // aliases map format: "%s@%s" int netnodes, netswitches, netports; static int 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; static int netspeedext = DEFAULT_LINKSPEEDEXT; static int mlnx_netspeed = DEFAULT_LINKSPEEDEXT; 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 NULL; } sw = switches + netswitches++; sw->node = nd; sw->linearcap = maxlinearcap; // assume identical val for all switches sw->multicastcap = maxmcastcap; // assume identical val for all switches sw->numportmask = (nd->numports + MCASTMASKSIZE) / MCASTMASKSIZE; 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 * sw->numportmask * 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 * sw->numportmask * sizeof(uint16_t)); return sw; } 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 NULL; if (find_node(nodeid)) { IBWARN("node id %s already exists", nodeid); return NULL; } if (netnodes >= maxnetnodes) { IBPANIC("no more nodes (max %d)", maxnetnodes); return NULL; } if (find_node_by_guid(guids[type])) { IBWARN("node %s guid %" PRIx64 " already exists", node_type_name(type), guids[type]); return NULL; } 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)); if (type == ROUTER_NODE) mad_set_field(nd->nodeinfo, 0, IB_NODE_TYPE_F, ROUTER_NODE); 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 NULL; } netvendid = 0; netsysimgguid = 0; return nd; } static int parse_node_ports(char *buf) { while (*buf && !isdigit(*buf)) buf++; return strtoul(buf, NULL, 0); } static char *parse_node_id(char *buf, char **rest_buf) { char *s, *e = NULL; if (!(s = strchr(buf, '"')) || !(e = strchr(s + 1, '"'))) { IBWARN("can't find valid id in <%s>", buf); return NULL; } *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 2x */ if (width < 1 || width > 31) { IBWARN("bad enabled width %d - should be between 1 to 31", width); return 0; } return 1; } static int is_linkspeed_valid(int speed) { /* speed is 2.5G, 5.0G, or 10.0G */ if (speed < 1 || speed > 7) { IBWARN("bad speed %d - should be between 1 to 7", speed); return 0; } return 1; } static int is_linkspeedext_valid(int speed) { /* extended speed is none, FDR, EDR, HDR, NDR, or some combination */ if (speed < 0 || speed > 15) { IBWARN("bad extended speed %d = should be between 0 to 15", 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_link_width_and_speed(Port * port, char *line) { int rlid = 0; int width = 0; char speed[10]; speed[0] = '\0'; if (3 != sscanf(line, "lid %d %dx%9s", &rlid, &width, speed)) { IBWARN("failed parsing port connection type"); return 0; } /* update port width */ if (width == 12) port->linkwidthena = LINKWIDTH_1x_4x_12x; else if (width == 8) port->linkwidthena = LINKWIDTH_8x; else if (width == 4) port->linkwidthena = LINKWIDTH_1x_4x; else if (width == 1) port->linkwidthena = LINKWIDTH_1x; else if (width == 2) port->linkwidthena = LINKWIDTH_2x; else { IBWARN("cannot parse width / invalid width"); } /* parse connection rate */ if (!strncmp(speed, LINKSPEED_STR_SDR, strlen(speed))) { port->linkspeedena = LINKSPEED_SDR; } else if (!strncmp(speed, LINKSPEED_STR_DDR, strlen(speed))) { port->linkspeedena = LINKSPEED_SDR | LINKSPEED_DDR; } else if (!strncmp(speed, LINKSPEED_STR_QDR, strlen(speed))) { port->linkspeedena = LINKSPEED_QDR | LINKSPEED_SDR | LINKSPEED_DDR; } else if (!strncmp(speed, LINKSPEED_STR_FDR, strlen(speed))) { port->linkspeedextena = LINKSPEEDEXT_FDR; port->linkspeedena = LINKSPEED_QDR | LINKSPEED_SDR | LINKSPEED_DDR; port->mlnx_linkspeedena = MLNXLINKSPEED_FDR10; } else if (!strncmp(speed, LINKSPEED_STR_EDR, strlen(speed))) { port->linkspeedextena = LINKSPEEDEXT_FDR_EDR; port->linkspeedena = LINKSPEED_QDR | LINKSPEED_SDR | LINKSPEED_DDR; port->mlnx_linkspeedena = MLNXLINKSPEED_FDR10; } else if (!strncmp(speed, LINKSPEED_STR_HDR, strlen(speed))) { port->linkspeedextena = LINKSPEEDEXT_HDR_EDR_FDR; port->linkspeedena = LINKSPEED_QDR | LINKSPEED_SDR | LINKSPEED_DDR; port->mlnx_linkspeedena = MLNXLINKSPEED_FDR10; } else if (!strncmp(speed, LINKSPEED_STR_NDR, strlen(speed))) { port->linkspeedextena = LINKSPEEDEXT_NDR_HDR_EDR_FDR; port->linkspeedena = LINKSPEED_QDR | LINKSPEED_SDR | LINKSPEED_DDR; port->mlnx_linkspeedena = MLNXLINKSPEED_FDR10; } else if (!strncmp(speed, LINKSPEED_STR_FDR10, strlen(speed))){ port->linkspeedena = LINKSPEED_QDR | LINKSPEED_SDR | LINKSPEED_DDR; port->mlnx_linkspeedena = MLNXLINKSPEED_FDR10; } else { IBWARN("cannot parse speed / invalid speed"); } return 0; } static int parse_port_connection_data(Port * port, int type, char *line) { int rc; char *line_connection_type = line; regex_t regex; regmatch_t regmatch[1]; if (line == NULL) { IBWARN("cannot parse empty line"); return -1; } regcomp(®ex,"lid[^\"]*$", 0); rc = regexec(®ex, line, 1, regmatch, 0); if (rc) { IBWARN("cannot parse remote lid and connection type"); regfree(®ex); return 0; } line_connection_type = line + regmatch[0].rm_so; regfree(®ex); if (type == SWITCH_NODE) { /* expecting line with the following format: * [1] "H-000123456789ABCD"[2](123456789ABCE) # "description" lid 1 4xQDR ... */ if (parse_port_link_width_and_speed(port, line_connection_type)) return -1; } if (type == HCA_NODE) { /* expecting line with the following format: * [1](123456789ABCDE) "S-000123456789ABCDF"[2] # lid 2 lmc 0 "description" lid 1 4xQDR ... */ if (parse_port_lid_and_lmc(port, line) || parse_port_link_width_and_speed(port, line_connection_type)) return -1; } return 0; } static int parse_port_opt(Port * port, char *opt, char *val) { int v; switch (*opt) { case 'w': v = strtoul(val, NULL, 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, NULL, 0); if (v && !is_linkspeed_valid(v)) return -1; /* If 0, assume QDR */ v = v ? v : LINKSPEED_QDR; port->linkspeedena = v; DEBUG("port %p linkspeed enabled set to %d", port, port->linkspeedena); break; case 'e': v = strtoul(val, NULL, 0); if (!is_linkspeedext_valid(v)) return -1; port->linkspeedextena = v; DEBUG("port %p linkspeedext enabled set to %d", port, port->linkspeedextena); 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; port->linkspeedextena = netspeedext; port->linkspeedext = DEFAULT_LINKSPEEDEXT; port->mlnx_linkspeedena = mlnx_netspeed; port->mlnx_linkspeed = DEFAULT_MLNXLINKSPEED; 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(default_vlarb_high)); memcpy(port->vlarb_low, default_vlarb_low, sizeof(default_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; } static 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 NULL; } char *expand_name(char *base, char *name, char **portstr) { char *s; if (!base) return NULL; 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 : NULL); return name; } snprintf(name, NODEIDLEN, "%s%s", base[0] == '@' ? netprefix : "", base); PDEBUG("alias %s", name); if (!(s = map_alias(name))) return NULL; strncpy(name, s, NODEIDLEN - 1); if (portstr) { *portstr = name; strsep(portstr, "["); } PDEBUG("name %s port %s", name, portstr ? *portstr : NULL); 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 = NULL; 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; } } if ((type == HCA_NODE || type == SWITCH_NODE) && line && parse_port_connection_data(port, type, line) < 0) { IBWARN("cannot parse port data"); 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; 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 0); if (!is_linkspeed_valid(speed)) { IBPANIC("invalid enabled link speed %d", speed); return -1; } netspeed = speed; return 1; } static int parse_speedext(int fd, char *line) { char *s; int speed; if (!(s = strchr(line, '='))) { IBWARN("bad assignment: missing '=' sign"); return -1; } speed = strtol(s + 1, NULL, 0); if (!is_linkspeedext_valid(speed)) { IBPANIC("invalid enabled link speed extended %d", speed); return -1; } netspeedext = 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, NULL, 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, "extspeed", 8)) r = parse_speedext(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_2x) return LINKWIDTH_2x; 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; } static int get_active_linkspeedext(Port * lport, Port * rport) { int speed = lport->linkspeedextena & rport->linkspeedextena; if (speed & LINKSPEEDEXT_NDR) return LINKSPEEDEXT_NDR; if (speed & LINKSPEEDEXT_HDR) return LINKSPEEDEXT_HDR; if (speed & LINKSPEEDEXT_EDR) return LINKSPEEDEXT_EDR; if (speed & LINKSPEEDEXT_FDR) return LINKSPEEDEXT_FDR; if (speed == LINKSPEEDEXT_NONE) return LINKSPEEDEXT_NONE; // same as 0 IBPANIC("mismatched enabled speedext between %" PRIx64 " P#%d S=%d and %" PRIx64 " P#%d S=%d", lport->portguid, lport->portnum, lport->linkspeedextena, rport->portguid, rport->portnum, rport->linkspeedextena); return 0; } static int get_active_mlnx_linkspeed(Port * lport, Port * rport) { int speed = lport->mlnx_linkspeedena & rport->mlnx_linkspeedena; if (speed & MLNXLINKSPEED_FDR10) return MLNXLINKSPEED_FDR10; if (speed == MLNXLINKSPEED_NONE) return MLNXLINKSPEED_NONE; // same as 0 IBPANIC("mismatched enabled mlnx speedext between %" PRIx64 " P#%d S=%d and %" PRIx64 " P#%d S=%d", lport->portguid, lport->portnum, lport->mlnx_linkspeedena, rport->portguid, rport->portnum, rport->mlnx_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_field64(pi, 0, IB_PORT_GID_PREFIX_F, p->subnet_prefix); 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_2x_4x_8x_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_QDR); 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); if (p->linkspeedext) { mad_set_field(pi, 0, IB_PORT_LINK_SPEED_EXT_ENABLED_F, p->linkspeedextena); mad_set_field(pi, 0, IB_PORT_LINK_SPEED_EXT_SUPPORTED_F, LINKSPEEDEXT_NDR_HDR_EDR_FDR); mad_set_field(pi, 0, IB_PORT_LINK_SPEED_EXT_ACTIVE_F, p->linkspeedext); } else { mad_set_field(pi, 0, IB_PORT_LINK_SPEED_EXT_ENABLED_F, 0); mad_set_field(pi, 0, IB_PORT_LINK_SPEED_EXT_SUPPORTED_F, 0); mad_set_field(pi, 0, IB_PORT_LINK_SPEED_EXT_ACTIVE_F, 0); /* FDR10 support */ if (p->mlnx_linkspeed) { mad_set_field(p->extportinfo, 0, IB_MLNX_EXT_PORT_LINK_SPEED_ENABLED_F, p->mlnx_linkspeedena); mad_set_field(p->extportinfo, 0, IB_MLNX_EXT_PORT_LINK_SPEED_SUPPORTED_F, p->mlnx_linkspeedena); mad_set_field(p->extportinfo, 0, IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F, p->mlnx_linkspeed); } } } 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; // Initialize 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); lport->mlnx_linkspeed = rport->mlnx_linkspeed = get_active_mlnx_linkspeed(lport, rport); lport->linkspeedext = rport->linkspeedext = get_active_linkspeedext(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 NULL; for (nd = nodes, e = nodes + netnodes; nd < e; nd++) if (!strcmp(desc, nd->nodeid)) return nd; return NULL; } Node *find_node_by_desc(char *desc) { Node *nd, *e; if (!desc) return NULL; for (nd = nodes, e = nodes + netnodes; nd < e; nd++) if (!strcmp(desc, nd->nodedesc)) return nd; return NULL; } Node *find_node_by_guid(uint64_t guid) { Node *nd, *e; if (ignoreduplicate) return NULL; for (nd = nodes, e = nodes + netnodes; nd < e; nd++) if (nd->nodeguid == guid) return nd; return NULL; } 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); } ibsim-0.12/include/000077500000000000000000000000001432776202300141705ustar00rootroot00000000000000ibsim-0.12/include/ibsim.h000066400000000000000000000054411432776202300154500ustar00rootroot00000000000000/* * 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 #include #include 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_ */ ibsim-0.12/net-examples/000077500000000000000000000000001432776202300151475ustar00rootroot00000000000000ibsim-0.12/net-examples/examples.README000066400000000000000000000006531432776202300176500ustar00rootroot00000000000000As 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 ' - includes named topology file 'do ' - executes ibsim console command during the topology file parsing ibsim-0.12/net-examples/net000066400000000000000000000014231432776202300156600ustar00rootroot00000000000000# Net configuration 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] ibsim-0.12/net-examples/net.1000066400000000000000000000011131432776202300160130ustar00rootroot00000000000000# Net configuration 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] ibsim-0.12/net-examples/net.2sw2path000066400000000000000000000012431432776202300173310ustar00rootroot00000000000000# Net configuration 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] ibsim-0.12/net-examples/net.2sw2path4hca000066400000000000000000000013761432776202300201000ustar00rootroot00000000000000# Net configuration 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] ibsim-0.12/net-examples/net.2sw2path4hca2port000066400000000000000000000013411432776202300210570ustar00rootroot00000000000000# Net configuration 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] ibsim-0.12/scripts/000077500000000000000000000000001432776202300142345ustar00rootroot00000000000000ibsim-0.12/scripts/run_opensm.sh000077500000000000000000000023521432776202300167620ustar00rootroot00000000000000#!/bin/bash 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 ibsim-0.12/scripts/travis-build000077500000000000000000000007351432776202300165740ustar00rootroot00000000000000#!/bin/bash PATH=/home/`whoami`/.local/bin:$PATH DIR=$(readlink -f .) # Stop on error set -e # Echo all commands to Travis log set -x # Cleanup first make clean CC=clang CFLAGS=-Werror make make clean # Run sparse on the subdirectories which are sparse clean CC=cgcc CFLAGS="-Werror" make > /dev/null 2>&1 | grep -v '^/usr/include' | tee out make clean # sparse does not fail gcc on messages if [ -s out ]; then false fi # Test out gcc-8 CC=gcc-8 CFLAGS="-Werror" make ibsim-0.12/scripts/travis-checkpatch000077500000000000000000000025521432776202300175710ustar00rootroot00000000000000#!/bin/bash # Copyright 2017 Mellanox Technologies Ltd. # Licensed under BSD (MIT variant) or GPLv2. See COPYING. if [ "x$TRAVIS_EVENT_TYPE" != "xpull_request" ]; then # Peform checkpatch checks on pull requests only exit 0 fi # The below "set" is commented, because the checkpatch.pl returns 1 (error) for warnings too. # And the rdma-core code is not mature enough to be warning safe # set -e if [ "x$TRAVIS_COMMIT_RANGE" != "x" ]; then wget -q https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/scripts/checkpatch.pl \ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/scripts/spelling.txt DIR_FOR_PATCHES_TO_CHECK=$(mktemp -d) git format-patch --no-cover-letter $TRAVIS_COMMIT_RANGE ^$TRAVIS_BRANCH -o $DIR_FOR_PATCHES_TO_CHECK/ CHECKPATCH_OPT="--no-tree --ignore PREFER_KERNEL_TYPES,FILE_PATH_CHANGES,EXECUTE_PERMISSIONS,USE_NEGATIVE_ERRNO,CONST_STRUCT $DIR_FOR_PATCHES_TO_CHECK/*" perl checkpatch.pl $CHECKPATCH_OPT if [ $? -ne 0 ]; then # We rerun checkpatch to simplify parsing and to understand if we failed for errors # For example, the output on some arbitrary patchset of the following line without awk is: # total: 1 errors, 3 warnings, 42 lines checked NUMB_ERRRORS=$(perl checkpatch.pl --terse $CHECKPATCH_OPT | awk 'BEGIN {FS = "total:"} ; {sum+=$2} END {print sum}') exit $NUMB_ERRRORS fi fi ibsim-0.12/scripts/travis-runtest000077500000000000000000000011711432776202300171740ustar00rootroot00000000000000#!/bin/bash PATH=/home/`whoami`/.local/bin:$PATH DIR=$(readlink -f .) # Stop on error set -e # Echo all commands to Travis log set -x ./ibsim/ibsim -s net-examples/net --no-console & IBSIM_PID=$! # Give some time for the network to start sleep 2 TMPDIR=$(mktemp -d) LD_PRELOAD=$DIR/umad2sim/libumad2sim.so OSM_TMP_DIR=$TMPDIR OSM_CACHE_DIR=$TMPDIR opensm -f osm.log & OSM_PID=$! # Give time for the SM to start sleep 2 LD_PRELOAD=$DIR/umad2sim/libumad2sim.so $DIR/tests/subnet_discover LD_PRELOAD=$DIR/umad2sim/libumad2sim.so $DIR/tests/mcast_storm rereg joins leave # Kill all pending processes kill -9 $OSM_PID $IBSIM_PID ibsim-0.12/tests/000077500000000000000000000000001432776202300137075ustar00rootroot00000000000000ibsim-0.12/tests/Makefile000066400000000000000000000001421432776202300153440ustar00rootroot00000000000000bins:= subnet_discover query_many mcast_storm -include ../defs.mk all: $(bins) $(bins): %: %.o ibsim-0.12/tests/get_all_ca_port_guids.sh000077500000000000000000000001161432776202300205550ustar00rootroot00000000000000#!/bin/sh ibnetdiscover \ | sed -ne 's/^\[[1-9]\](\([a-f|0-9]\+\)).*$/0x\1/p' ibsim-0.12/tests/mcast_storm.c000066400000000000000000000466031432776202300164170ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #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...) (void)0 #endif #define TMO 100 #define DEFAULT_PREFIX 0xfe80000000000000ULL #define DEFAULT_MGID_PREFIX 0xff00000000000000ULL /* 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; }; struct mcmember_params { uint32_t qkey; uint16_t mlid; uint8_t mtu; int tclass; uint16_t pkey; uint8_t rate; int sl; int flow_label; int hop_limit; uint8_t scope; uint8_t join_state; int proxy_join; }; static const struct mcmember_params null_params = { .tclass = -1, .sl = -1, .flow_label = -1, .hop_limit = -1, .proxy_join = -1, }; static const struct mcmember_params mcmember_params_join = { .tclass = -1, .sl = -1, .flow_label = -1, .hop_limit = -1, .join_state = 1, .proxy_join = -1, }; static const struct mcmember_params mcmember_params_create = { .qkey = 0x80010000, .mtu = 4, .tclass = 0, .pkey = 0xffff, .rate = 3, .sl = 0, .flow_label = 0, .hop_limit = -1, .join_state = 1, .proxy_join = -1, }; static ibmad_gid_t mgid_ipoib = { 0xff, 0x12, 0x40, 0x1b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }; static int64_t add_rid(uint8_t *data, ibmad_gid_t mgid, ibmad_gid_t port_gid) { mad_set_array(data, 0, IB_SA_MCM_MGID_F, mgid); mad_set_array(data, 0, IB_SA_MCM_PORTGID_F, port_gid); return IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID; } static uint64_t build_mcm_rec(uint8_t * data, const struct mcmember_params *p) { #define SET_FIELD1(val, mask, field) \ if (val) { \ mad_set_field(data, 0, field, val); \ comp_mask |= mask; \ } #define SET_FIELD(obj, name, mask, field) \ if (obj->name != null_params.name) { \ mad_set_field(data, 0, field, obj->name); \ comp_mask |= mask; \ } uint64_t comp_mask = 0; memset(data, 0, IB_SA_DATA_SIZE); if (!p) return comp_mask; SET_FIELD(p, qkey, IB_MCR_COMPMASK_QKEY, IB_SA_MCM_QKEY_F); SET_FIELD(p, mlid, IB_MCR_COMPMASK_MLID, IB_SA_MCM_MLID_F); SET_FIELD(p, mtu, IB_MCR_COMPMASK_MTU, IB_SA_MCM_MTU_F); SET_FIELD(p, tclass, IB_MCR_COMPMASK_TCLASS, IB_SA_MCM_TCLASS_F); SET_FIELD(p, pkey, IB_MCR_COMPMASK_PKEY, IB_SA_MCM_PKEY_F); SET_FIELD(p, rate, IB_MCR_COMPMASK_RATE, IB_SA_MCM_RATE_F); SET_FIELD(p, sl, IB_MCR_COMPMASK_SL, IB_SA_MCM_SL_F); SET_FIELD(p, flow_label, IB_MCR_COMPMASK_FLOW, IB_SA_MCM_FLOW_LABEL_F); SET_FIELD(p, join_state, IB_MCR_COMPMASK_JOIN_STATE, IB_SA_MCM_JOIN_STATE_F); SET_FIELD(p, proxy_join, IB_MCR_COMPMASK_PROXY, IB_SA_MCM_PROXY_JOIN_F); return comp_mask; } static void build_mcm_rec_umad(void *umad, ib_portid_t * dport, int method, 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 be64toh(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_join(struct addr_data *a, uint8_t * umad, int len, ibmad_gid_t mgid, ibmad_gid_t port_gid, uint64_t comp_mask, uint8_t data[]) { comp_mask |= add_rid(data, mgid, port_gid); return send_req(a, umad, len, IB_MAD_METHOD_SET, comp_mask, data); } static int send_leave(struct addr_data *a, uint8_t * umad, int len, ibmad_gid_t mgid, ibmad_gid_t port_gid, uint64_t comp_mask, uint8_t data[]) { comp_mask |= add_rid(data, mgid, port_gid); return send_req(a, umad, len, IB_MAD_METHOD_DELETE, comp_mask, data); } static int send_query(struct addr_data *a, uint8_t * umad, int len, ibmad_gid_t mgid, ibmad_gid_t port_gid, uint64_t comp_mask, uint8_t data[]) { comp_mask |= add_rid(data, mgid, port_gid); 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) { 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, uint64_t comp_mask, uint8_t data[]) { if (send_leave(a, umad, len, mgid, list->gid, comp_mask, data)) return -1; if (send_join(a, umad, len, mgid, list->gid, comp_mask, data)) return -1; list->trid = mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F); return 0; } static int rereg_recv_all(struct addr_data *a, void *umad, int len, ibmad_gid_t mgid, struct gid_list *list, unsigned cnt, uint64_t comp_mask, uint8_t data[]) { uint8_t *mad; uint64_t trid; unsigned n, method, status; unsigned i; info("%s...\n", __func__); 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], comp_mask, data); } } info("%s: got %u responses\n", __func__, n); return 0; } static int rereg_query_all(struct addr_data *a, void *umad, int len, ibmad_gid_t mgid, struct gid_list *list, unsigned cnt, uint64_t comp_mask, uint8_t data[]) { uint8_t *mad; unsigned method, status; unsigned i; int ret; info("%s...\n", __func__); for (i = 0; i < cnt; i++) { ret = send_query(a, umad, len, mgid, list[i].gid, comp_mask, data); 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); return 0; } /* tests framework */ struct test_data { unsigned gids_size; struct gid_list *gids; unsigned mgids_size; struct gid_list *mgids; const struct mcmember_params *params; }; #define MAX_CLIENTS 100 static int run_port_rereg_test(struct addr_data *a, struct test_data *td) { uint8_t data[256]; uint64_t comp_mask; uint8_t *umad; int len = 256; int cnt, i, n, size = td->gids_size; umad = calloc(1, len + umad_size()); if (!umad) { err("cannot alloc mem for umad: %s\n", strerror(errno)); return -1; } if (!td->params) td->params = &mcmember_params_join; comp_mask = build_mcm_rec(data, td->params); for (cnt = size; cnt;) { n = cnt > MAX_CLIENTS ? MAX_CLIENTS : cnt; for (i = 0; i < n; i++) { rereg_port(a, umad, len, td->mgids[0].gid, &td->gids[size - cnt + i], comp_mask, data); info("%s: sent %u requests\n", __func__, n * 2); } rereg_recv_all(a, umad, len, td->mgids[0].gid, td->gids, size, comp_mask, data); cnt -= i; } rereg_query_all(a, umad, len, td->mgids[0].gid, td->gids, size, comp_mask, data); free(umad); return 0; } static int run_mcast_member_test(struct addr_data *a, struct test_data *td, int (*func)(struct addr_data *a, uint8_t * umad, int len, ibmad_gid_t mgid, ibmad_gid_t gid, uint64_t comp_mask, uint8_t *data)) { uint8_t data[256]; uint64_t comp_mask; uint8_t *umad; int len = 256; unsigned i, j; umad = calloc(1, len + umad_size()); if (!umad) { err("cannot alloc mem for umad: %s\n", strerror(errno)); return -1; } comp_mask = build_mcm_rec(data, td->params); for (i = 0; i < td->gids_size; i++) for (j = 0; j < td->mgids_size; j++) if (func(a, umad, len, td->mgids[j].gid, td->gids[i].gid, comp_mask, data)) return -1; if (recv_all(a, umad, len) < 0) return -1; free(umad); return 0; } static int run_mcast_joins_test(struct addr_data *a, struct test_data *td) { if (!td->params) td->params = &mcmember_params_create; return run_mcast_member_test(a, td, send_join); } static int run_mcast_leave_test(struct addr_data *a, struct test_data *td) { if (!td->params) td->params = &mcmember_params_join; return run_mcast_member_test(a, td, send_leave); } /* main stuff */ struct test { 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 ibmad_port *mad_port) { struct addr_data addr; int ret; info("Running \'%s\'...\n", t->name); ib_resolve_smlid_via(&addr.dport, TMO, mad_port); 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 = mad_rpc_portid(mad_port); 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); 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 = be64toh(prefix); guid = be64toh(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 = be64toh(prefix); memcpy(&guid, &gid[8], 8); guid = be64toh(guid); for (i = 0; i <= n; i++) make_gid(list[i].gid, prefix, guid++); *gid_list = list; return i; } static int parse_gid_str(ibmad_gid_t gid, char *str, uint64_t default_prefix) { uint64_t guid, prefix = 0; char *p, *e; p = str; while (isspace(*p)) p++; e = strchr(p, '\n'); if (e) { while (isspace(*e)) *e-- = '\0'; } if (*p == '\0' || *p == '#') return 1; if (inet_pton(AF_INET6, p, gid) > 0) return 0; e = strchr(p, ':'); if (e) { prefix = strtoull(p, NULL, 0); guid = strtoull(e + 1, NULL, 0); } else if (strlen(p) > 18) { e = p + strlen(p) - 16; guid = strtoull(e, NULL, 16); *e = '\0'; prefix = strtoull(p, NULL, 0); } else guid = strtoull(p, NULL, 0); if (!guid) return -1; if (!prefix) prefix = default_prefix; make_gid(gid, prefix, guid); return 0; } static int parse_gids_file(const char *guid_file, struct gid_list **gid_list) { char line[256]; ibmad_gid_t gid; FILE *f; struct gid_list *list = NULL; unsigned list_size = 0; unsigned 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)) { if (parse_gid_str(gid, line, DEFAULT_PREFIX)) continue; 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])); } memcpy(list[i].gid, gid, 16); i++; } fclose(f); *gid_list = list; return i; } static void make_str_opts(char *p, unsigned size, const struct option *o) { unsigned n; int i; 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] \n", prog); printf("\n, where 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, NULL, 'g'}, {"mgidfile", 1, NULL, 'm'}, {"GUID", 1, NULL, 'G'}, {"MGID", 1, NULL, 'M'}, {"ipv4", 0, NULL, 'i'}, {"increment", 1, NULL, 'I'}, {"qkey", 1, NULL, 'q'}, {"mlid", 1, NULL, 'z'}, {"mtu", 1, NULL, 'y'}, {"tclass", 1, NULL, 't'}, {"pkey", 1, NULL, 'p'}, {"rate", 1, NULL, 'r'}, {"sl", 1, NULL, 's'}, {"flowlabel", 1, NULL, 'f'}, {"joinstate", 1, NULL, 'j'}, {"proxy", 0, NULL, 'x'}, {"version", 0, NULL, 'V'}, {"verbose", 0, NULL, 'v'}, {"help", 0, NULL, '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"}, {NULL, NULL, NULL} }; char opt_str[256]; int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS }; struct mcmember_params params; struct test_data tdata; ibmad_gid_t gid, mgid = {}; uint64_t guid = 0; const char *guid_file = NULL, *mgid_file = NULL; struct ibmad_port *mad_port; const struct test *t; unsigned is_mgid = 0, is_ipv4 = 1, increment = 0; int ret, ch; params = null_params; make_str_opts(opt_str, sizeof(opt_str), long_opts); while ((ch = getopt_long(argc, argv, opt_str, long_opts, NULL)) != -1) { switch (ch) { case 'G': guid = strtoull(optarg, NULL, 0); break; case 'M': if (parse_gid_str(mgid, optarg, DEFAULT_MGID_PREFIX)) { err("cannot parse MGID \'%s\'", optarg); exit(2); } is_mgid = 1; break; case 'I': increment = strtoul(optarg, NULL, 0); break; case 'g': guid_file = optarg; break; case 'm': mgid_file = optarg; break; case 'q': params.qkey = strtoul(optarg, NULL, 0); break; case 'z': params.mlid = strtoul(optarg, NULL, 0); break; case 'y': params.mtu = strtoul(optarg, NULL, 0); break; case 't': params.tclass = strtoul(optarg, NULL, 0); break; case 'p': params.pkey = strtoul(optarg, NULL, 0); break; case 'r': params.rate = strtoul(optarg, NULL, 0); break; case 's': params.sl = strtoul(optarg, NULL, 0); break; case 'f': params.flow_label = strtoul(optarg, NULL, 0); break; case 'j': params.join_state = strtoul(optarg, NULL, 0); break; case 'x': params.proxy_join = 1; break; case 'v': break; case 'V': printf("%s version %s\n", argv[0], "0.1"); exit(0); case 'h': default: usage(argv[0], long_opts, tests); break; } } mad_port = mad_rpc_open_port(NULL, 0, mgmt_classes, 2); if (!mad_port) { err("Cannot open local port...\n"); exit(-1); } memset(&tdata, 0, sizeof(tdata)); 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_via(&portid, NULL, &gid, mad_port) < 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, DEFAULT_MGID_PREFIX, guid); ret = make_gids_list(gid, increment, &tdata.mgids); } if (ret < 0) return ret; tdata.mgids_size = ret; if (memcmp(¶ms, &null_params, sizeof(params))) tdata.params = ¶ms; if (argc <= optind) return run_test(&tests[0], &tdata, mad_port); do { t = find_test(tests, argv[optind]); if (!t) usage(argv[0], long_opts, tests); ret = run_test(t, &tdata, mad_port); if (ret) break; } while (argc > ++optind); if (tdata.gids) free(tdata.gids); if (tdata.mgids) free(tdata.mgids); mad_rpc_close_port(mad_port); return ret; } ibsim-0.12/tests/query_many.c000066400000000000000000000171261432776202300162530ustar00rootroot00000000000000/* * Copyright (c) 2009 Voltaire, Inc. All rights reserved. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * */ #include #include #include #include #include #include #include #include static unsigned number_queries = 1; static uint8_t dr_path[64]; static size_t dr_path_size = 0; static uint16_t attribute_id = IB_ATTR_NODE_INFO; static uint32_t attribute_mod = 0; static unsigned timeout = 100; static unsigned retries = 3; static unsigned verbose = 0; #define ERROR(fmt, ...) fprintf(stderr, "ERR: " fmt, ##__VA_ARGS__) #define VERBOSE(fmt, ...) if (verbose) fprintf(stderr, fmt, ##__VA_ARGS__) #define NOISE(fmt, ...) if (verbose > 1) fprintf(stderr, fmt, ##__VA_ARGS__) static const char *print_path(uint8_t path[], size_t path_cnt) { static char buf[256]; size_t i; int n = 0; for (i = 0; i <= path_cnt; i++) n += snprintf(buf + n, sizeof(buf) - n, "%u,", path[i]); buf[n] = '\0'; return buf; } static size_t parse_direct_path(const char *str, uint8_t path[], size_t size) { size_t i; for (i = 0; i < size; i++) { path[i] = strtoul(str, NULL, 0); str = strchr(str, ','); if (!str) break; str++; } return i; } static void build_umad_req(void *umad, uint8_t * path, unsigned path_cnt, uint64_t trid, uint8_t method, uint16_t attr_id, uint32_t attr_mod, uint64_t mkey) { void *mad = umad_get_mad(umad); memset(umad, 0, umad_size() + IB_MAD_SIZE); umad_set_addr(umad, 0xffff, 0, 0, 0); mad_set_field(mad, 0, IB_MAD_METHOD_F, method); mad_set_field(mad, 0, IB_MAD_CLASSVER_F, 1); mad_set_field(mad, 0, IB_MAD_MGMTCLASS_F, IB_SMI_DIRECT_CLASS); mad_set_field(mad, 0, IB_MAD_BASEVER_F, 1); mad_set_field(mad, 0, IB_DRSMP_HOPCNT_F, path_cnt); mad_set_field(mad, 0, IB_DRSMP_HOPPTR_F, 0); mad_set_field64(mad, 0, IB_MAD_TRID_F, trid); mad_set_field(mad, 0, IB_DRSMP_DRDLID_F, 0xffff); mad_set_field(mad, 0, IB_DRSMP_DRSLID_F, 0xffff); mad_set_array(mad, 0, IB_DRSMP_PATH_F, path); mad_set_field(mad, 0, IB_MAD_ATTRID_F, attr_id); mad_set_field(mad, 0, IB_MAD_ATTRMOD_F, attr_mod); mad_set_field64(mad, 0, IB_MAD_MKEY_F, mkey); } static void check_diff(const char *name, void *mad, struct timeval *tv1, struct timeval *tv) { unsigned long diff = (tv1->tv_sec - tv->tv_sec) * 1000000 + tv1->tv_usec - tv->tv_usec; if (diff > 1000) { uint8_t path[256]; uint8_t method = mad_get_field(mad, 0, IB_MAD_METHOD_F); uint64_t trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); uint16_t attr_id = mad_get_field(mad, 0, IB_MAD_ATTRID_F); uint32_t attr_mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); size_t path_cnt = mad_get_field(mad, 0, IB_DRSMP_HOPCNT_F); mad_get_array(mad, 0, IB_DRSMP_PATH_F, path); printf("LONG %s (%lu) %016" PRIx64 ": method %x, attr %x," " mod %x, path %s\n", name, diff, trid, method, attr_id, attr_mod, print_path(path, path_cnt)); fflush(stdout); } } static int send_query(int fd, int agent, void *umad, uint64_t trid, uint8_t * path, size_t path_cnt, uint16_t attr_id, uint32_t attr_mod) { struct timeval tv, tv1; int ret; build_umad_req(umad, path, path_cnt, trid, IB_MAD_METHOD_GET, attr_id, attr_mod, 0); gettimeofday(&tv, NULL); ret = umad_send(fd, agent, umad, IB_MAD_SIZE, timeout, retries); gettimeofday(&tv1, NULL); if (ret < 0) { ERROR("umad_send failed: trid 0x%016" PRIx64 ", attr_id %x, attr_mod %x: %s\n", trid, attr_id, attr_mod, strerror(errno)); return -1; } VERBOSE("send %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id, attr_mod, print_path(path, path_cnt)); check_diff("SEND", umad_get_mad(umad), &tv1, &tv); return ret; } static int recv_response(int fd, int agent, uint8_t * umad, uint8_t path[]) { struct timeval tv, tv1; void *mad; uint64_t trid; uint32_t attr_mod; uint16_t attr_id, status; size_t path_size; int len = IB_MAD_SIZE, ret; gettimeofday(&tv, NULL); do { ret = umad_recv(fd, umad, &len, timeout); } while (ret >= 0 && ret != agent); gettimeofday(&tv1, NULL); if (ret < 0 || umad_status(umad)) { ERROR("umad_recv failed: umad status %x: %s\n", umad_status(umad), strerror(errno)); return -1; } check_diff("RESP", umad_get_mad(umad), &tv1, &tv); mad = umad_get_mad(umad); status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F); trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); attr_id = mad_get_field(mad, 0, IB_MAD_ATTRID_F); attr_mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); path_size = mad_get_field(mad, 0, IB_DRSMP_HOPCNT_F); mad_get_array(mad, 0, IB_DRSMP_PATH_F, path); if (status) { ERROR("error response 0x%016" PRIx64 ": attr_id %x" ", attr_mod %x from %s with status %x\n", trid, attr_id, attr_mod, print_path(path, path_size), status); return -1; } VERBOSE("recv %016" PRIx64 ": attr %x, mod %x from %s\n", trid, attr_id, attr_mod, print_path(path, path_size)); return ret; } static int query(int fd, int agent) { uint8_t path[64] = { 0 }; uint64_t trid = 0x20090000; void *umad; unsigned n = 0; int ret = 0; umad = malloc(IB_MAD_SIZE + umad_size()); if (!umad) return -ENOMEM; while (n++ < number_queries) send_query(fd, agent, umad, trid++, dr_path, dr_path_size, attribute_id, attribute_mod); n = 0; do { ret = recv_response(fd, agent, umad, path); } while (ret >= 0 && ++n < number_queries); free(umad); return ret; } static int umad_query(char *card_name, unsigned int port_num) { int fd, agent, ret; ret = umad_init(); if (ret) { ERROR("cannot init umad\n"); return -1; } fd = umad_open_port(card_name, port_num); if (fd < 0) { ERROR("cannot open umad port %s:%u: %s\n", card_name ? card_name : "NULL", port_num, strerror(errno)); return -1; } agent = umad_register(fd, IB_SMI_DIRECT_CLASS, 1, 0, NULL); if (agent < 0) { ERROR("cannot register SMI DR class for umad port %s:%u: %s\n", card_name ? card_name : "NULL", port_num, strerror(errno)); return -1; } ret = query(fd, agent); if (ret) ERROR("Failed.\n"); umad_unregister(fd, agent); umad_close_port(fd); umad_done(); return ret; } int main(int argc, char **argv) { const struct option long_opts[] = { {"number", 1, NULL, 'n'}, {"drpath", 1, NULL, 'd'}, {"attribute", 1, NULL, 'a'}, {"modifier", 1, NULL, 'm'}, {"Card", 1, NULL, 'C'}, {"Port", 1, NULL, 'P'}, {"timeout", 1, NULL, 't'}, {"retries", 1, NULL, 'r'}, {} }; char *card_name = NULL; unsigned int port_num = 0; int ch, ret; while (1) { ch = getopt_long(argc, argv, "n:d:a:m:C:P:t:r:v", long_opts, NULL); if (ch == -1) break; switch (ch) { case 'n': number_queries = strtoul(optarg, NULL, 0); break; case 'd': dr_path_size = parse_direct_path(optarg, dr_path, sizeof(dr_path)); break; case 'a': attribute_id = strtoul(optarg, NULL, 0); break; case 'm': attribute_mod = strtoul(optarg, NULL, 0); break; case 'C': card_name = optarg; break; case 'P': port_num = strtoul(optarg, NULL, 0); break; case 't': timeout = strtoul(optarg, NULL, 0); break; case 'r': retries = strtoul(optarg, NULL, 0); break; case 'v': verbose++; break; default: printf("Usage: %s [-n num_queries] [-d path]" " [-a attr] [-m mod]" " [-C card_name] [-P port_num]" " [-t timeout] [-r retries] [-v[v]]\n", argv[0]); exit(2); break; } } ret = umad_query(card_name, port_num); return ret; } ibsim-0.12/tests/subnet_discover.c000066400000000000000000000400231432776202300172500ustar00rootroot00000000000000/* * Copyright (c) 2009 Voltaire, Inc. All rights reserved. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * */ #include #include #include #include #include #include #include #define MAX_HOPS 63 struct port { struct node *node; uint64_t guid; struct port *remote; uint8_t port_info[IB_SMP_DATA_SIZE]; }; struct node { uint64_t guid; unsigned num_ports; unsigned is_switch; size_t path_size; uint8_t path[64]; uint8_t node_info[IB_SMP_DATA_SIZE]; uint8_t node_desc[IB_SMP_DATA_SIZE]; uint8_t switch_info[IB_SMP_DATA_SIZE]; struct port ports[]; }; static struct node *node_array[32 * 1024]; static unsigned node_count = 0; static unsigned trid_cnt = 0; static unsigned outstanding = 0; static unsigned max_outstanding = 8; static unsigned timeout = 100; static unsigned retries = 3; static unsigned verbose = 0; static unsigned total_mads = 0; static unsigned max_hops = 0; #define ERROR(fmt, ...) fprintf(stderr, "ERR: " fmt, ##__VA_ARGS__) #define VERBOSE(fmt, ...) if (verbose) fprintf(stderr, fmt, ##__VA_ARGS__) #define VERBOSE1(fmt, ...) if (verbose > 1) fprintf(stderr, fmt, ##__VA_ARGS__) #define VERBOSE2(fmt, ...) if (verbose > 2) fprintf(stderr, fmt, ##__VA_ARGS__) #define NOISE(fmt, ...) VERBOSE2(fmt, ##__VA_ARGS__) static const char *print_path(uint8_t path[], size_t path_cnt) { static char buf[256]; unsigned i; int n = 0; for (i = 0; i <= path_cnt; i++) n += snprintf(buf + n, sizeof(buf) - n, "%u,", path[i]); buf[n] = '\0'; return buf; } static char dbg_buf[8192]; #define DBG_DUMP_FUNC(name) static void dbg_dump_##name(void *data) \ { \ mad_dump_##name(dbg_buf, sizeof(dbg_buf), data, IB_SMP_DATA_SIZE); \ NOISE("### "#name":\n%s\n", dbg_buf); \ } DBG_DUMP_FUNC(nodeinfo); DBG_DUMP_FUNC(nodedesc); DBG_DUMP_FUNC(portinfo); DBG_DUMP_FUNC(switchinfo); static void build_umad_req(void *umad, uint8_t path[], unsigned path_cnt, uint64_t trid, uint8_t method, uint16_t attr_id, uint32_t attr_mod, uint64_t mkey) { void *mad = umad_get_mad(umad); memset(umad, 0, umad_size() + IB_MAD_SIZE); umad_set_addr(umad, 0xffff, 0, 0, 0); mad_set_field(mad, 0, IB_MAD_METHOD_F, method); mad_set_field(mad, 0, IB_MAD_CLASSVER_F, 1); mad_set_field(mad, 0, IB_MAD_MGMTCLASS_F, IB_SMI_DIRECT_CLASS); mad_set_field(mad, 0, IB_MAD_BASEVER_F, 1); mad_set_field(mad, 0, IB_DRSMP_HOPCNT_F, path_cnt); mad_set_field(mad, 0, IB_DRSMP_HOPPTR_F, 0); mad_set_field64(mad, 0, IB_MAD_TRID_F, trid); mad_set_field(mad, 0, IB_DRSMP_DRDLID_F, 0xffff); mad_set_field(mad, 0, IB_DRSMP_DRSLID_F, 0xffff); mad_set_array(mad, 0, IB_DRSMP_PATH_F, path); mad_set_field(mad, 0, IB_MAD_ATTRID_F, attr_id); mad_set_field(mad, 0, IB_MAD_ATTRMOD_F, attr_mod); mad_set_field64(mad, 0, IB_MAD_MKEY_F, mkey); } static int send_request(int fd, int agent, uint64_t trid, uint8_t * path, size_t path_cnt, uint16_t attr_id, uint32_t attr_mod) { uint8_t umad[IB_MAD_SIZE + umad_size()]; int ret; build_umad_req(umad, path, path_cnt, trid, IB_MAD_METHOD_GET, attr_id, attr_mod, 0); ret = umad_send(fd, agent, umad, IB_MAD_SIZE, timeout, retries); if (ret < 0) { ERROR("umad_send failed: trid 0x%016" PRIx64 ", attr_id %x, attr_mod %x: %s\n", trid, attr_id, attr_mod, strerror(errno)); return -1; } VERBOSE1("send %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id, attr_mod, print_path(path, path_cnt)); return ret; } static struct request_queue { struct request_queue *next; uint64_t trid; uint16_t attr_id; uint32_t attr_mod; size_t path_cnt; uint8_t path[0]; } request_queue; static struct request_queue *request_last = &request_queue; static unsigned tr_table_size; static struct request_queue **tr_table; static void add_to_tr_table(struct request_queue *q, uint64_t trid) { unsigned n = trid >> 16; if (n >= tr_table_size) { unsigned new_size = tr_table_size ? tr_table_size * 2 : 4096; if (n > new_size) new_size = n + 1; tr_table = realloc(tr_table, new_size * sizeof(tr_table[0])); if (!tr_table) { ERROR("cannot realloc request table\n"); tr_table_size = 0; return; } memset(tr_table + tr_table_size, 0, (new_size - tr_table_size) * sizeof(tr_table[0])); tr_table_size = new_size; } tr_table[n] = q; } static void clean_from_tr_table(uint64_t trid) { unsigned n = (trid >> 16) & 0xffff; if (n >= tr_table_size) { ERROR("invalid request table index %u\n", n); return; } free(tr_table[n]); tr_table[n] = NULL; } static void free_unresponded(void) { struct request_queue *q; unsigned i; for (i = 0 ; i < tr_table_size; i++) { if (!(q = tr_table[i])) continue; fprintf(stderr, "Unresponded transaction %016" PRIx64 ": %s " "attr_id %x, attr_mod %x\n", q->trid, print_path(q->path, q->path_cnt), q->attr_id, q->attr_mod); free(q); } } static void run_request_queue(int fd, int agent) { struct request_queue *q = request_queue.next; while (q) { if (outstanding >= max_outstanding) break; if (send_request(fd, agent, q->trid, q->path, q->path_cnt, q->attr_id, q->attr_mod) < 0) break; q = q->next; outstanding++; total_mads++; } request_queue.next = q; if (!q) request_last = &request_queue; } static int queue_request(uint64_t trid, uint8_t * path, size_t path_cnt, uint16_t attr_id, uint32_t attr_mod) { struct request_queue *q = malloc(sizeof(*q) + path_cnt + 1); if (!q) return -1; q->next = NULL; q->trid = trid; q->attr_id = attr_id; q->attr_mod = attr_mod; memcpy(q->path, path, path_cnt + 1); q->path_cnt = path_cnt; request_last->next = q; request_last = q; add_to_tr_table(q, trid); return 0; } static int send_query(int fd, int agent, unsigned node_id, uint8_t path[], size_t path_cnt, uint16_t attr_id, uint32_t attr_mod) { uint64_t trid; int ret; trid = (trid_cnt++ << 16) | (node_id & 0xffff); ret = queue_request(trid, path, path_cnt, attr_id, attr_mod); if (ret < 0) { ERROR("queue failed: trid 0x%016" PRIx64 ", attr_id %x," " attr_mod %x\n", trid, attr_id, attr_mod); return -1; } VERBOSE1("queue %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id, attr_mod, print_path(path, path_cnt)); run_request_queue(fd, agent); return ret; } static int recv_response(int fd, int agent, uint8_t * umad, size_t length) { int len = length, ret; do { ret = umad_recv(fd, umad, &len, timeout); } while (ret >= 0 && ret != agent); if (ret < 0 || umad_status(umad)) { ERROR("umad_recv failed: umad status %x: %s\n", umad_status(umad), strerror(errno)); return (unsigned)len > umad_size() ? 1 : -1; } return 0; } static int query_node_info(int fd, int agent, unsigned node_id, uint8_t path[], size_t path_cnt) { return send_query(fd, agent, node_id, path, path_cnt, IB_ATTR_NODE_INFO, 0); } static int query_node_desc(int fd, int agent, unsigned node_id, uint8_t path[], size_t path_cnt) { return send_query(fd, agent, node_id, path, path_cnt, IB_ATTR_NODE_DESC, 0); } static int query_switch_info(int fd, int agent, unsigned node_id, uint8_t path[], size_t path_cnt) { return send_query(fd, agent, node_id, path, path_cnt, IB_ATTR_SWITCH_INFO, 0); } static int query_port_info(int fd, int agent, unsigned node_id, uint8_t path[], size_t path_cnt, unsigned port_num) { return send_query(fd, agent, node_id, path, path_cnt, IB_ATTR_PORT_INFO, port_num); } static int add_node(uint8_t * node_info, uint8_t path[], size_t path_size) { struct node *node; unsigned i, num_ports = mad_get_field(node_info, 0, IB_NODE_NPORTS_F); node = malloc(sizeof(*node) + (num_ports + 1) * sizeof(node->ports[0])); if (!node) return -1; memset(node, 0, sizeof(*node) + (num_ports + 1) * sizeof(node->ports[0])); node->num_ports = num_ports; node->guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F); node->is_switch = ((mad_get_field(node_info, 0, IB_NODE_TYPE_F)) == IB_NODE_SWITCH); memcpy(node->path, path, path_size + 1); node->path_size = path_size; memcpy(node->node_info, node_info, sizeof(node->node_info)); for (i = 0; i <= num_ports; i++) node->ports[i].node = node; node_array[node_count] = node; return node_count++; } static int find_node(uint8_t * node_info) { uint64_t guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F); unsigned i; for (i = 0; i < node_count; i++) if (node_array[i]->guid == guid) return i; return -1; } static int process_port_info(void *umad, unsigned node_id, int fd, int agent, uint8_t path[], size_t path_cnt) { struct node *node = node_array[node_id]; struct port *port; uint8_t *port_info = umad + umad_size() + IB_SMP_DATA_OFFS; unsigned port_num, local_port; dbg_dump_portinfo(port_info); port_num = mad_get_field(umad_get_mad(umad), 0, IB_MAD_ATTRMOD_F); local_port = mad_get_field(port_info, 0, IB_PORT_LOCAL_PORT_F); port = &node->ports[port_num]; memcpy(port->port_info, port_info, sizeof(port->port_info)); if (port_num && mad_get_field(port_info, 0, IB_PORT_PHYS_STATE_F) == 5 && ((node->is_switch && port_num != local_port) || (node_id == 0 && port_num == local_port)) && path_cnt++ < MAX_HOPS) { if (path_cnt > max_hops) max_hops = path_cnt; path[path_cnt] = port_num; return query_node_info(fd, agent, node_id, path, path_cnt); } return 0; } static int process_switch_info(unsigned node_id, uint8_t * switch_info) { struct node *node = node_array[node_id]; dbg_dump_switchinfo(switch_info); memcpy(node->switch_info, switch_info, sizeof(node->switch_info)); return 0; } static int process_node_desc(unsigned node_id, uint8_t * node_desc) { struct node *node = node_array[node_id]; dbg_dump_nodedesc(node_desc); memcpy(node->node_desc, node_desc, sizeof(node->node_desc)); return 0; } static void connect_ports(unsigned node1_id, unsigned port1_num, unsigned node2_id, unsigned port2_num) { struct port *port1 = &node_array[node1_id]->ports[port1_num]; struct port *port2 = &node_array[node2_id]->ports[port2_num]; VERBOSE1("connecting %u:%u <--> %u:%u\n", node1_id, port1_num, node2_id, port2_num); port1->remote = port2; port2->remote = port1; } static int process_node(void *umad, unsigned remote_id, int fd, int agent, uint8_t path[], size_t path_cnt) { struct node *node; uint8_t *node_info = umad_get_mad(umad) + IB_SMP_DATA_OFFS; unsigned port_num = mad_get_field(node_info, 0, IB_NODE_LOCAL_PORT_F); unsigned node_is_new = 0; unsigned i; int id; dbg_dump_nodeinfo(node_info); if ((id = find_node(node_info)) < 0) { id = add_node(node_info, path, path_cnt); if (id < 0) return -1; node_is_new = 1; } node = node_array[id]; VERBOSE("%-5s %-6s with guid 0x%" PRIx64 " discovered at %s\n", node_is_new ? "new" : "known", node->is_switch ? "Switch" : "Ca", node->guid, print_path(path, path_cnt)); node->ports[port_num].guid = mad_get_field64(node_info, 0, IB_NODE_PORT_GUID_F); if (id) /* skip connect for very first node */ connect_ports(id, port_num, remote_id, path[path_cnt]); if (!node_is_new) return 0; query_node_desc(fd, agent, id, path, path_cnt); if (node->is_switch) query_switch_info(fd, agent, id, path, path_cnt); for (i = !node->is_switch; i <= node->num_ports; i++) query_port_info(fd, agent, id, path, path_cnt, i); return 0; } static int recv_smp_resp(int fd, int agent, uint8_t * umad, uint8_t path[]) { void *mad; uint64_t trid; uint8_t method; uint16_t status; uint16_t attr_id; uint32_t attr_mod; size_t path_cnt; unsigned node_id; int ret; ret = recv_response(fd, agent, umad, IB_MAD_SIZE); mad = umad_get_mad(umad); status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F); method = mad_get_field(mad, 0, IB_MAD_METHOD_F); trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); attr_id = mad_get_field(mad, 0, IB_MAD_ATTRID_F); attr_mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); path_cnt = mad_get_field(mad, 0, IB_DRSMP_HOPCNT_F); mad_get_array(mad, 0, IB_DRSMP_PATH_F, path); if (method != IB_MAD_METHOD_GET) return 0; outstanding--; run_request_queue(fd, agent); if (ret < 0) return ret; else if (ret || status) { ERROR("error response 0x%016" PRIx64 ": attr_id %x" ", attr_mod %x from %s with status %x\n", trid, attr_id, attr_mod, print_path(path, path_cnt), status); return -1; } clean_from_tr_table(trid); node_id = trid & 0xffff; VERBOSE1("recv %016" PRIx64 ": attr %x, mod %x from %s\n", trid, attr_id, attr_mod, print_path(path, path_cnt)); switch (attr_id) { case IB_ATTR_NODE_INFO: process_node(umad, node_id, fd, agent, path, path_cnt); break; case IB_ATTR_NODE_DESC: process_node_desc(node_id, mad + IB_SMP_DATA_OFFS); break; case IB_ATTR_SWITCH_INFO: process_switch_info(node_id, mad + IB_SMP_DATA_OFFS); break; case IB_ATTR_PORT_INFO: process_port_info(umad, node_id, fd, agent, path, path_cnt); break; default: VERBOSE("unsolicited response 0x%016" PRIx64 ": attr_id %x" ", attr_mod %x\n", trid, attr_id, attr_mod); return 0; } return ret; } static int discover(int fd, int agent) { uint8_t umad[IB_MAD_SIZE + umad_size()]; uint8_t path[64] = { 0 }; int ret; ret = query_node_info(fd, agent, 0, path, 0); if (ret < 0) return ret; while (outstanding) if (recv_smp_resp(fd, agent, umad, path)) ret = 1; free_unresponded(); return ret; } static int umad_discover(char *card_name, unsigned int port_num) { int fd, agent, ret; ret = umad_init(); if (ret) { ERROR("cannot init umad\n"); return -1; } fd = umad_open_port(card_name, port_num); if (fd < 0) { ERROR("cannot open umad port %s:%u: %s\n", card_name ? card_name : "NULL", port_num, strerror(errno)); return -1; } agent = umad_register(fd, IB_SMI_DIRECT_CLASS, 1, 0, NULL); if (agent < 0) { ERROR("cannot register SMI DR class for umad port %s:%u: %s\n", card_name ? card_name : "NULL", port_num, strerror(errno)); return -1; } ret = discover(fd, agent); if (ret) fprintf(stderr, "\nThere are problems during discovery.\n"); umad_unregister(fd, agent); umad_close_port(fd); umad_done(); return ret; } static void print_subnet(void) { struct node *node; struct port *local, *remote; unsigned i, j; printf("\n# The subnet discovered using %u mads, reaching %d hops\n\n", total_mads, max_hops); for (i = 0; i < node_count; i++) { node = node_array[i]; printf("%s %u \"%s-%016" PRIx64 "\" \t# %s %s\n", node->is_switch ? "Switch" : "Ca", node->num_ports, node->is_switch ? "S" : "H", node->guid, print_path(node->path, node->path_size), node->node_desc); for (j = 1; j <= node->num_ports; j++) { local = &node->ports[j]; remote = local->remote; if (!remote) continue; printf("[%u] \t\"%s-%016" PRIx64 "\"[%lu] \t# %s\n", j, remote->node->is_switch ? "S" : "H", remote->node->guid, remote - remote->node->ports, remote->node->node_desc); } printf("\n"); } } int main(int argc, char **argv) { const struct option long_opts[] = { {"Card", 1, NULL, 'C'}, {"Port", 1, NULL, 'P'}, {"maxsmps", 1, NULL, 'n'}, {"timeout", 1, NULL, 't'}, {"retries", 1, NULL, 'r'}, {"verbose", 0, NULL, 'v'}, {"help", 0, NULL, 'h'}, {} }; char *card_name = NULL; unsigned int port_num = 0; int ch, ret; while (1) { ch = getopt_long(argc, argv, "C:P:n:t:r:vh", long_opts, NULL); if (ch == -1) break; switch (ch) { case 'C': card_name = optarg; break; case 'P': port_num = strtoul(optarg, NULL, 0); break; case 'n': max_outstanding = strtoul(optarg, NULL, 0); if (!max_outstanding) max_outstanding = -1; break; case 't': timeout = strtoul(optarg, NULL, 0); break; case 'r': retries = strtoul(optarg, NULL, 0); break; case 'v': verbose++; break; case 'h': default: printf("usage: %s [-C card_name] [-P port_num]" " [-n maxsmps] [-t timeout] [-r retries]" " [-v[v]]\n", argv[0]); exit(2); break; } } ret = umad_discover(card_name, port_num); print_subnet(); return ret; } ibsim-0.12/umad2sim/000077500000000000000000000000001432776202300142665ustar00rootroot00000000000000ibsim-0.12/umad2sim/Makefile000066400000000000000000000003131432776202300157230ustar00rootroot00000000000000srcs:=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) ibsim-0.12/umad2sim/sim_client.c000066400000000000000000000201241432776202300165570ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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 char* socket_basename; 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, char *issm) { struct sim_client_info info = { 0 }; info.id = id; if (issm) info.issm = 1; else 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, NULL, 0); } static int sim_init(struct sim_client *sc, char *nodeid, char *issm) { 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"); socket_basename = getenv("IBSIM_SOCKNAME"); if(!socket_basename) socket_basename = SIM_BASENAME; if (connect_host && *connect_host) remote_mode = 1; DEBUG("init client pid=%d, nodeid=%s", pid, nodeid ? nodeid : "none"); if ((fd = socket(remote_mode ? PF_INET : PF_LOCAL, SOCK_DGRAM, 0)) < 0) IBPANIC("can't get socket (fd)"); 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", socket_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", socket_basename); sim_attach(ctlfd, &name, size); sc->fd_ctl = ctlfd; size = make_name(&name, NULL, 0, "%s:in%d", socket_basename, pid); if (bind(fd, (struct sockaddr *)&name, size) < 0) IBPANIC("can't bind input socket"); 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, 0, nodeid, issm); if (sc->clientid < 0) IBPANIC("connect failed"); port = connect_port ? atoi(connect_port) : IBSIM_DEFAULT_SERVER_PORT; size = make_name(&name, connect_host, port + sc->clientid + 1, "%s:out%d", socket_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; char *issm; nodeid = getenv("SIM_HOST"); issm = getenv("SIM_SET_ISSM"); if (sim_init(sc, nodeid, issm) < 0) return -1; if (sim_ctl(sc, SIM_CTL_GET_VENDOR, &sc->vendor, sizeof(sc->vendor)) < 0) goto _exit; if (sim_ctl(sc, SIM_CTL_GET_NODEINFO, sc->nodeinfo, sizeof(sc->nodeinfo)) < 0) goto _exit; sc->portinfo[0] = 0; // portno requested if (sim_ctl(sc, SIM_CTL_GET_PORTINFO, sc->portinfo, sizeof(sc->portinfo)) < 0) goto _exit; if (sim_ctl(sc, SIM_CTL_GET_PKEYS, sc->pkeys, sizeof(sc->pkeys)) < 0) goto _exit; if (issm) sim_client_set_sm(sc, 1); return 0; _exit: sim_disconnect(sc); sc->fd_ctl = sc->fd_pktin = sc->fd_pktout = -1; return -1; } void sim_client_exit(struct sim_client *sc) { sim_disconnect(sc); sc->fd_ctl = sc->fd_pktin = sc->fd_pktout = -1; } ibsim-0.12/umad2sim/sim_client.h000066400000000000000000000036361432776202300165750ustar00rootroot00000000000000/* * 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 struct sim_client { int clientid; int fd_pktin, fd_pktout, fd_ctl; struct sim_vendor vendor; uint8_t nodeinfo[64]; uint8_t portinfo[64]; uint8_t extportinfo[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); extern void sim_client_exit(struct sim_client *sc); #endif /* _SIM_CLIENT_H_ */ ibsim-0.12/umad2sim/umad2sim.c000066400000000000000000001026641432776202300161640ustar00rootroot00000000000000/* * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. * Copyright (c) 2011 Mellanox Technologies LTD. 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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])) #define EVENT_NO_TIMEOUT 0xFFFFFFFF #define FD_TIMEOUT 12 #define IB_PORT_EXT_SPEED_SUPPORTED_MASK (1<<14) struct umad_buf_t { ssize_t size; char *umad; }; struct list_elem_t { struct umad_buf_t *data; struct list_elem_t *next; }; struct msg_queue_t { struct list_elem_t *tail; struct list_elem_t *head; ssize_t queue_size; }; struct fd_event_t { pthread_cond_t condvar; pthread_mutex_t mutex; }; struct fd_data_t { struct fd_event_t fd_event; struct msg_queue_t *mqueue; } fd_data_t; 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; }; #define FD_PER_DEVICE 8 struct umad2sim_dev { pthread_t thread_id; unsigned num; char name[32]; uint8_t port; struct sim_client sim_client; unsigned int agent_idx[256]; unsigned int agent_fds[256]; struct ib_user_mad_reg_req agents[32]; char umad_path[256]; char issm_path[256]; struct fd_data_t *fds[FD_PER_DEVICE]; }; 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); #if __GLIBC_PREREQ(2,10) static int (*real_scandir) (const char *dir, struct dirent *** namelist, int (*filter) (const struct dirent *), int (*compar) (const struct dirent **, const struct dirent **)); #else static int (*real_scandir) (const char *dir, struct dirent *** namelist, int (*filter) (const struct dirent *), int (*compar) (const void *, const void *)); #endif static char sysfs_infiniband_dir[] = SYS_INFINIBAND; static char sysfs_infiniband_mad_dir[] = IB_UMAD_ABI_DIR; static char umad_dev_dir[] = "/dev/infiniband"; static char umad2sim_sysfs_prefix[32]; static unsigned umad2sim_initialized; static struct umad2sim_dev *devices[32]; static pthread_mutex_t global_devices_mutex; static ssize_t umad2sim_read(struct umad2sim_dev *dev, void *buf, size_t count, unsigned int *mgmt_class); static ssize_t fd_data_mqueue_size(struct fd_data_t *fd_data); static int fd_event_init(struct fd_event_t * const p_event) { if (pthread_cond_init(&p_event->condvar, NULL)) return -1; if (pthread_mutex_init(&p_event->mutex, NULL)) { pthread_cond_destroy(&p_event->condvar); return -1; } return 0; } static void fd_event_destroy(struct fd_event_t * const p_event) { pthread_cond_broadcast(&p_event->condvar); pthread_cond_destroy(&p_event->condvar); pthread_mutex_destroy(&p_event->mutex); } static void fd_event_signal(struct fd_event_t * const p_event) { pthread_cond_signal(&p_event->condvar); } static int fd_event_wait_on(struct fd_data_t * const fd_data, const uint32_t wait_us) { int status = -1; int wait_ret; struct timespec timeout; struct timeval curtime; struct fd_event_t *p_event = &fd_data->fd_event; ssize_t size; pthread_mutex_lock(&p_event->mutex); size = fd_data_mqueue_size(fd_data); if (size) { pthread_mutex_unlock(&p_event->mutex); return 0; } if (wait_us == 0) { pthread_mutex_unlock(&p_event->mutex); return FD_TIMEOUT; } if (wait_us == EVENT_NO_TIMEOUT) { /* Wait for condition variable to be signaled */ if (!pthread_cond_wait(&p_event->condvar, &p_event->mutex)) status = 0; pthread_mutex_unlock(&p_event->mutex); return status; } if (gettimeofday(&curtime, NULL) == 0) { unsigned long long n_sec = curtime.tv_usec*1000 + ((wait_us % 1000000)) * 1000; timeout.tv_sec = curtime.tv_sec + (wait_us / 1000000) + (n_sec / 1000000000); timeout.tv_nsec = n_sec % 1000000000; wait_ret = pthread_cond_timedwait(&p_event->condvar, &p_event->mutex, &timeout); if (wait_ret == 0) { size = fd_data_mqueue_size(fd_data); status = size ? 0 : -1; } else if (wait_ret == ETIMEDOUT) status = FD_TIMEOUT; pthread_mutex_unlock(&p_event->mutex); } return status; } static struct umad_buf_t *alloc_umad_buf(ssize_t size) { struct umad_buf_t *buf; buf = (struct umad_buf_t *) malloc(sizeof(struct umad_buf_t)); if (!buf) return NULL; buf->umad = malloc(size); if (!buf->umad) { free(buf); return NULL; } buf->size = size; return buf; } static void free_umad_buf(struct umad_buf_t *buf) { free(buf->umad); buf->size = 0; free(buf); } static struct msg_queue_t *mqueue_create(void) { struct msg_queue_t *ptr; ptr = (struct msg_queue_t *) malloc(sizeof(struct msg_queue_t)); if (!ptr) return NULL; ptr->head = NULL; ptr->tail = NULL; ptr->queue_size = 0; return ptr; } static struct list_elem_t *mqueue_add_tail(struct msg_queue_t *mqueue, void *data) { struct list_elem_t *ptr; ptr = (struct list_elem_t *) malloc(sizeof(struct list_elem_t)); if (!ptr) return NULL; ptr->data = data; ptr->next = NULL; if (mqueue->head == NULL) { mqueue->tail = ptr; mqueue->head = mqueue->tail; } else { mqueue->tail->next = ptr; mqueue->tail = ptr; } mqueue->queue_size++; return ptr; } static ssize_t mqueue_get_size(struct msg_queue_t *mqueue) { return mqueue->queue_size; } static struct list_elem_t *mqueue_remove_head(struct msg_queue_t *mqueue) { struct list_elem_t *ptr; if (mqueue->head == NULL) return NULL; ptr = mqueue->head; if (mqueue->head == mqueue->tail) { mqueue->head = NULL; mqueue->tail = NULL; } else { mqueue->head = ptr->next; } mqueue->queue_size--; ptr->next = NULL; return ptr; } static void mqueue_destroy(struct msg_queue_t *mqueue) { free(mqueue); } static struct fd_data_t *fd_data_create(void) { struct fd_data_t *ptr; ptr = (struct fd_data_t *) malloc(sizeof(struct fd_data_t)); if (!ptr) return NULL; ptr->mqueue = mqueue_create(); if (!ptr->mqueue) { free(ptr); return NULL; } if (fd_event_init(&ptr->fd_event)) { mqueue_destroy(ptr->mqueue); free(ptr); return NULL; } return ptr; } /* should be called under fd_data->fd_event.mutex */ static struct umad_buf_t *fd_data_dequeue(struct fd_data_t *fd_data) { struct list_elem_t *ptr; struct umad_buf_t *data_ptr = NULL; ptr = mqueue_remove_head(fd_data->mqueue); if (ptr) { data_ptr = ptr->data; free(ptr); } return data_ptr; } /* should be called under global lock */ static void fd_data_release(struct fd_data_t *fd_data) { struct umad_buf_t *ptr; while ((ptr = fd_data_dequeue(fd_data)) != NULL) free_umad_buf(ptr); mqueue_destroy(fd_data->mqueue); fd_event_destroy(&fd_data->fd_event); free(fd_data); } /* should be called under fd_data->fd_event.mutex */ static int fd_data_enqueue(struct fd_data_t *fd_data, void *data) { struct list_elem_t *ptr; int result = 0; ptr = mqueue_add_tail(fd_data->mqueue, data); if (!ptr) result = -1; return result; } /* should be called under global lock */ static struct fd_data_t *get_fd_data(struct umad2sim_dev *dev, unsigned int fd) { if (fd < 1024 && fd >= 2048) return NULL; if (!dev) return NULL; return dev->fds[(fd - 1024) % FD_PER_DEVICE]; } /* should be called under fd_data->fd_event.mutex */ static ssize_t fd_data_mqueue_size(struct fd_data_t *fd_data) { return mqueue_get_size(fd_data->mqueue); } /* Returns index into dev->fds where new fd_data_t pointer was stored */ static int get_new_fd(struct umad2sim_dev *dev) { int i; for (i = 0; i < FD_PER_DEVICE; i++) { if (dev->fds[i] != NULL) continue; dev->fds[i] = fd_data_create(); return (dev->fds[i] == NULL) ? -1 : i; } /* all FDs allocated */ return -1; } static struct umad2sim_dev *fd_to_dev(unsigned int fd) { if (fd >= 2048) return devices[fd - 2048]; if (fd >= 1024) return devices[(fd - 1024) / FD_PER_DEVICE]; return NULL; } static int close_fd(unsigned int fd) { struct umad2sim_dev *dev; int i, idx; struct fd_data_t *fd_data; if (fd < 1024) return 0; dev = fd_to_dev(fd); if (!dev) return 0; if (fd >= 2048) { sim_client_set_sm(&dev->sim_client, 0); return 0; } fd_data = get_fd_data(dev, fd); if (fd_data) fd_data_release(fd_data); for (i = 0; i < 256; i++) { if (dev->agent_fds[i] == fd) { dev->agent_fds[i] = -1; idx = dev->agent_idx[i]; dev->agents[idx].id = (uint32_t)(-1); dev->agent_idx[i] = -1; break; } } dev->fds[(fd - 1024) % FD_PER_DEVICE] = NULL; return 0; } static void *__receiver(void *arg) { struct umad2sim_dev *dev = (struct umad2sim_dev *) arg; struct pollfd pfds; struct umad_buf_t *buf; unsigned int mgmt_class; unsigned int fd; struct fd_data_t *fd_data; pfds.fd = dev->sim_client.fd_pktin; pfds.events = POLLIN; pfds.revents = 0; while (1) { if (real_poll(&pfds, 1, -1) < 0) { ERROR("real_poll failure\n"); continue; } /* Do real read and post the message to the queue */ buf = alloc_umad_buf(sizeof(struct sim_request)); if (!buf) continue; buf->size = umad2sim_read(dev, buf->umad, buf->size, &mgmt_class); pthread_mutex_lock(&global_devices_mutex); fd = dev->agent_fds[mgmt_class]; fd_data = get_fd_data(dev, fd); pthread_mutex_unlock(&global_devices_mutex); pthread_mutex_lock(&fd_data->fd_event.mutex); /* find appropriate mqueue and push to it */ if ((fd_data == NULL) || fd_data_enqueue(fd_data, buf) < 0) { ERROR("Empty fd_data or fd_data_enqueue failed for FD %d\n", fd); free_umad_buf(buf); } else { /* signal reader */ fd_event_signal(&fd_data->fd_event); } pthread_mutex_unlock(&fd_data->fd_event.mutex); } return NULL; } /* * 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 void 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'; if (mkdir(dir, 0755) && errno != EEXIST) IBPANIC("Failed to make directory <%s>", dir); if (p) { *p = '/'; p++; } } while (p && p[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) - strlen(file_name) - 1); strncat(file_name, name, sizeof(file_name) - strlen(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 = ""; 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) - strlen(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 = ""; 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 = ""; 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_CAPMASK_F); if (val & IB_PORT_EXT_SPEED_SUPPORTED_MASK) speed = mad_get_field(portinfo, 0, IB_PORT_LINK_SPEED_EXT_ACTIVE_F); else speed = 0; val = mad_get_field(portinfo, 0, IB_PORT_LINK_WIDTH_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) { speed = mad_get_field(portinfo, 0, IB_PORT_LINK_SPEED_ACTIVE_F); 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); } else { if (speed == 1) str = " FDR"; else if (speed == 2) str = " EDR"; else if (speed == 4) str = " HDR"; else if (speed == 8) str = " NDR"; else str = ""; file_printf(path, SYS_PORT_RATE, "%d Gb/sec (%dX%s)\n", (speed == 1) ? 14 * val : 26 * val, 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) - strlen(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) - strlen(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, unsigned int *mgmt_class) { struct sim_request req; ib_user_mad_t *umad = (ib_user_mad_t *) buf; 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; *mgmt_class = 0; 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() + be64toh(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) == IB_MAD_METHOD_TRAP_REPRESS) { printf("Dropping 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 = htobe64(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(unsigned int fd, struct ib_user_mad_reg_req *req) { unsigned int i; struct umad2sim_dev *dev; pthread_mutex_lock(&global_devices_mutex); dev = fd_to_dev(fd); if (!dev) { pthread_mutex_unlock(&global_devices_mutex); return -1; } DEBUG("%s: fd = %u, qpn = %u, mgmt_class = %u," " mgmt_class_version = %u, rmpp_version = %u\n", __func__, fd, 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; dev->agent_fds[req->mgmt_class] = fd; DEBUG("agent registered: %d\n", i); pthread_mutex_unlock(&global_devices_mutex); return 0; } pthread_mutex_unlock(&global_devices_mutex); errno = ENOMEM; return -1; } static int unregister_agent(unsigned int fd, unsigned int id) { unsigned int mgmt_class; struct umad2sim_dev *dev; pthread_mutex_lock(&global_devices_mutex); dev = fd_to_dev(fd); if (!dev) { pthread_mutex_unlock(&global_devices_mutex); return -1; } if (id >= arrsize(dev->agents)) { pthread_mutex_unlock(&global_devices_mutex); errno = EINVAL; return -1; } mgmt_class = dev->agents[id].mgmt_class; dev->agents[id].id = (uint32_t)(-1); dev->agent_idx[mgmt_class] = -1; dev->agent_fds[mgmt_class] = -1; pthread_mutex_unlock(&global_devices_mutex); return 0; } static int umad2sim_ioctl(unsigned int fd, unsigned long request, void *arg) { DEBUG("umad2sim_ioctl: %lu, %p...\n", request, arg); switch (request) { case IB_USER_MAD_REGISTER_AGENT: return register_agent(fd, arg); case IB_USER_MAD_UNREGISTER_AGENT: return unregister_agent(fd, *((unsigned int *)arg)); case IB_USER_MAD_ENABLE_PKEY: return 0; default: errno = EINVAL; } return -1; } static struct umad2sim_dev *umad2sim_dev_create(unsigned int num, const char *name) { struct umad2sim_dev *dev; int 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) < 0) goto _error; if (pthread_create(&dev->thread_id, NULL, __receiver, dev) < 0) { sim_client_exit(&dev->sim_client); 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 int)(-1); dev->agent_fds[i] = (unsigned int)(-1); } for (i = 0; i < FD_PER_DEVICE; i++) dev->fds[i] = NULL; 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) { int i; sim_client_exit(&dev->sim_client); pthread_cancel(dev->thread_id); pthread_join(dev->thread_id, NULL); for (i = 0; i < FD_PER_DEVICE; i++) { if (dev->fds[i] != NULL) { fd_data_release(dev->fds[i]); dev->fds[i] = NULL; } } 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]; int i; DEBUG("umad2sim_cleanup...\n"); pthread_mutex_lock(&global_devices_mutex); for (i = 0; i < arrsize(devices); i++) if (devices[i]) { umad2sim_dev_delete(devices[i]); devices[i] = NULL; } pthread_mutex_unlock(&global_devices_mutex); strncpy(path, umad2sim_sysfs_prefix, sizeof(path) - 1); unlink_dir(path, sizeof(path)); pthread_mutex_destroy(&global_devices_mutex); } 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); } pthread_mutex_init(&global_devices_mutex, NULL); 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(); if (!umad2sim_initialized && (is_sysfs_file(path) || !strncmp(path, umad_dev_dir, strlen(umad_dev_dir)))) umad2sim_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); } #if __GLIBC_PREREQ(2,10) int scandir(const char *path, struct dirent ***namelist, int (*filter) (const struct dirent *), int (*compar) (const struct dirent **, const struct dirent **)) #else int scandir(const char *path, struct dirent ***namelist, int (*filter) (const struct dirent *), int (*compar) (const void *, const void *)) #endif { char new_path[4096]; CHECK_INIT(); if (!umad2sim_initialized && (is_sysfs_file(path) || !strncmp(path, umad_dev_dir, strlen(umad_dev_dir)))) umad2sim_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; int 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); } pthread_mutex_lock(&global_devices_mutex); for (i = 0; i < arrsize(devices); i++) { if (!(dev = devices[i])) continue; if (!strncmp(path, dev->umad_path, sizeof(dev->umad_path))) { int fd_index; fd_index = get_new_fd(dev); pthread_mutex_unlock(&global_devices_mutex); return (fd_index < 0) ? -1 : 1024 + i * FD_PER_DEVICE + fd_index; } if (!strncmp(path, dev->issm_path, sizeof(dev->issm_path))) { sim_client_set_sm(&dev->sim_client, 1); pthread_mutex_unlock(&global_devices_mutex); return 2048 + i; } } pthread_mutex_unlock(&global_devices_mutex); return real_open(path, flags, mode); } int close(int fd) { DEBUG("libs_wrap: close %d...\n", fd); CHECK_INIT(); if (fd >= 1024) return close_fd(fd); return real_close(fd); } ssize_t read(int fd, void *buf, size_t count) { struct umad2sim_dev *dev; struct fd_data_t *fd_data; struct umad_buf_t *umad_buf; int ret; CHECK_INIT(); if (fd >= 2048) return -1; else if (fd >= 1024) { pthread_mutex_lock(&global_devices_mutex); dev = fd_to_dev(fd); fd_data = get_fd_data(dev, fd); if (!fd_data) { pthread_mutex_unlock(&global_devices_mutex); return -1; } pthread_mutex_unlock(&global_devices_mutex); pthread_mutex_lock(&fd_data->fd_event.mutex); umad_buf = fd_data_dequeue(fd_data); pthread_mutex_unlock(&fd_data->fd_event.mutex); if (!umad_buf) { DEBUG("No data in queue\n"); return -EWOULDBLOCK; } if (umad_buf->size > count) { ERROR("received data size %u larger than requested buf size %u\n", (unsigned int) umad_buf->size, (unsigned int) count); umad_buf->size = count; } memcpy(buf, umad_buf->umad, umad_buf->size); ret = umad_buf->size; free_umad_buf(umad_buf); return ret; } else return real_read(fd, buf, count); } ssize_t write(int fd, const void *buf, size_t count) { struct umad2sim_dev *dev; ssize_t res; CHECK_INIT(); if (fd >= 2048) return -1; else if (fd >= 1024) { pthread_mutex_lock(&global_devices_mutex); dev = fd_to_dev(fd); if (!dev) res = -1; else res = umad2sim_write(dev, buf, count); pthread_mutex_unlock(&global_devices_mutex); return res; } 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(fd, request, arg); else return real_ioctl(fd, request, arg); } /* Only single FD per devives is support */ /* This fits current libibumad implementation */ int poll(struct pollfd *pfds, nfds_t nfds, int timeout) { struct umad2sim_dev *dev = NULL; struct fd_data_t *fd_data = NULL; unsigned int i, index; int ret; CHECK_INIT(); pthread_mutex_lock(&global_devices_mutex); for (i = 0; i < nfds; i++) { if (pfds[i].fd >= 1024 && pfds[i].fd < 2048) { dev = fd_to_dev(pfds[i].fd); fd_data = get_fd_data(dev, pfds[i].fd); index = i; break; } } pthread_mutex_unlock(&global_devices_mutex); if (fd_data != NULL) { /* timeout in microsec*/ ret = fd_event_wait_on(fd_data, (timeout < 0) ? EVENT_NO_TIMEOUT : timeout * 1000); pfds[index].revents = 0; if (ret == 0) { pfds[index].revents = POLLIN; ret = 1; } else if (ret == FD_TIMEOUT) ret = 0; else ret = -1; } else { ret = real_poll(pfds, nfds, timeout); } return ret; }