diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2013-01-04 21:55:57 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2013-01-04 21:55:57 -0800 |
commit | 1736fa987eb6b66b6eaedbc1cd3df4f48b873721 (patch) | |
tree | fab9a0cf0d8a8bfbabf131ae0e3209fed30f98b0 | |
parent | 96abbc571f9645e14ba9d9faf549ebcb4df40036 (diff) | |
parent | 0315bd568b78bcae16e368cfce9311891b05e686 (diff) | |
download | android_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.tar.gz android_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.tar.bz2 android_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.zip |
Merge "Merge remote-tracking branch 'origin/caf/kernel-bridge-utils/master'"
41 files changed, 3686 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f0342b --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# +# NOTE! Don't add files that are generated in specific +# subdirectories here. Add them in the ".gitignore" file +# in that subdirectory instead. +# +# Normal rules +# +.* +*.o +*.o.* +*.a +*.s +*.so + +# Generated by configure +Makefile +bridge-utils.spec +configure +config.* + +# +# Top-level generic files +# +tags +TAGS + +# quilt's files +patches +series + +# cscope files +cscope.* + +*.orig +*.rej @@ -0,0 +1,2 @@ +Stephen Hemminger <shemminger@vyatta.com> +Lennert Buytenhek <buytenh@gnu.org> @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..435d2f5 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,133 @@ +2006-05-31 Stephen Hemminger <shemminger@zqx3.pdx.osdl.net> + + * Fixed bug where setting port priority set path cost instead + +2006-01-31 Stephen Hemminger <shemminger@osdl.org> + + * Released bridge-utils 1.1 + * Change to use libsysfs 2.0 + +2005-03-16 Stephen Hemminger <shemminger@osdl.org> + + * Released bridge-utils 1.0.6 + * Fix for libsys detection (for FC) + * Update autoconf usage + * Allow multiple interfaces for addif,delif + +2004-12-02 Stephen Hemminger <shemminger@osdl.org> + + * Released bridge-utils 1.0.5 + * Remove brctld out of date, buggy not used + * Cleanup command line help and error messages + * Fix segv with wrong # of args to 'brctl stp' + + +20040601 Stephen Hemminger <shemminger@osdl.org> + * Released bridge-utils 1.0.4 + - should build with out sysfs now. + - report errors on foreach_port failing + - more build cleanup + +20040525 Stephen Hemminger <shemminger@osdl.org> + * Released bridge-utils 1.0.1 + - Change configure option + from --with-linux=<path> + to --with-linux-headers=<path> + so options match help message. + - Fix so utilities work with earlier 2.6 kernels that + have sysfs but not new ioctl's or directories yet. + - Build spec file from template. + +20040524 Stephen Hemminger <shemminger@osdl.org> + * Released bridge-utils 1.0 + - Use sysfs to control bridge parameters + - Add new ioctl syntax to handle mixed 32/64 bit mode + (Earlier method would not work on all platforms). + - Change libbbridge API to do work as needed, rather + than reading all bridges/ports at startup. Old way + would not scale with 1000's of entries + - Minor cleanups. + +20040401 Stephen Hemminger <shemminger@osdl.org> + * Releases bridge-utils 0.9.7 + - add -V option + - support 100's of bridge ports + - minor bug fixes + +20021002 Lennert Buytenhek <buytenh@gnu.org> + + * Released bridge-utils 0.9.6. + +20020403 Lennert Buytenhek <buytenh@gnu.org> + + * autoconfization by Andreas Hofmeister. + +20020116 Lennert Buytenhek <buytenh@gnu.org> + + * On sparc, try to detect 32/64-bitness of the kernel at runtime. + + * Released bridge-utils 0.9.5. + +20020106 Lennert Buytenhek <buytenh@gnu.org> + + * Remove 'tap'. + + * Added TODO list. + + * Added extra check for argument count to brctl + + * Added error message for circular bridge dev enslavement to brctl. + + * Get rid of some compiler warnings. + + * Steal Red Hat rawhide spec file. + + * Added 'how to use libbridge_compat.c' explanation by Serge Caron. + + * Try to work around sparc64 brokenness (FUCK ARGHH FUCK FUCK FUCK) + + * Release bridge-utils 0.9.4. + +20011107 Lennert Buytenhek <buytenh@gnu.org> + + * Moved FAQ to the website. + + * Updated docs for 2.4 firewalling. + + * Add out-of-date notice to the THANKS file. + +???????? Lennert Buytenhek <buytenh@gnu.org> + + * Fixed brctl timeout 42.94s wrap buglet. + + * Cleanup some docs. + + * Released bridge-utils 0.9.3. + +20001002 Lennert Buytenhek <buytenh@gnu.org> + + * Incorporated two cleanup patches from H. J. Lu (one splits + the CC define into CC and CFLAGS, the other one changes a few + occurances of __close into the libc5 compatibility stub to + close). + + * Removed all RCS tags. + + * Removed sample scripts dir. + + * Tweaked THANKS file a bit (it needs updating as well..) + + * Made 'show' command show an interface list. + + * Changed the 'showbr' command to 'showstp' + + * Tweaked FAQ. + + * Added explanation for iptables firewalling. + + * Released bridge-utils 0.9.2. + +20000905 Lennert Buytenhek <buytenh@gnu.org> + + * Incorporated Roger Venning's patch to tap which will let you + specify a local address to be used for the 'tunnel'. diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..6028513 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,35 @@ + +DESTDIR= +KERNEL_HEADERS=-I@KERNEL_HEADERS@ + +INSTALL=@INSTALL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +sbindir=@sbindir@ +mandir=@mandir@ +distdir = $(PACKAGE)-$(VERSION) + +SUBDIRS=libbridge brctl doc + +all: + for x in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$x ; done + +clean: + for x in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$x clean ; done + +distclean: clean + rm -f config.log + rm -f config.cache + rm -f config.status + +maintainer-clean: distclean + rm -f Makefile + rm -f brctl/Makefile + rm -f libbridge/Makefile + rm -f doc/Makefile + +install: + for x in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$x install; done + @@ -0,0 +1,45 @@ +This version of the bridge utilities is for Linux 2.4 and 2.6, +it uses the sysfs interface if possible on Linux 2.6. + +The code repository is: + git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git + +Advantages of the new code are: +- Support for multiple bridge port groups (i.e. multiple independent + bridges in one machine). +- Each bridge is seen as a logical device, which allows you to do + firewalling between port groups for example. +- Everything is dynamic; bridges are created dynamically using the + userspace configuration tool, ports are 'enslaved' dynamically, etc. +- It is being actively maintained. +- It uses a hash table for MAC addresses, not an AVL tree. +- It's small (currently 4 pages of i386 code) and modular. +- The source isn't a mess. +- It works as a module. + + +If you have any comments, questions or suggestions, please send email to +the mailing list bridge@linux-foundation.org +-------------------------- + +Files in this package: + +AUTHORS Authors of this package + +COPYING The GNU General Public License. + +Makefile Recursive Makefile. + +README This file. + +brctl/ The userspace bridge configuration tool. + +bridge-utils.spec + A .spec file for Red Hat package building. "rpm -tb + <tar.gz file>" ought to give you a .RPM file. + +doc/ Some documentation files. + +libbridge/ The bridge configuration interface library. + +misc/ Miscellaneous utilities. @@ -0,0 +1,40 @@ +Thanks go to (this list is REALLY out-of-date): + +F. Nicolaas Benders <benders@pinpoint.com> +Lars Bohn <lars-erik-christian.bohn@student.uni-ulm.de> +Jim Chapman <jim.chapman@iname.com> +Robert Collier <rob@lspace.org> +Steven Dewinter <steven@zeus.rug.ac.be> +Arne Fitzenreiter <arne.fitzenreiter@gmx.de> +Alejando Garcia <alexgc@edu.aytolacoruna.es> +Matthew Grant <grantma@anathoth.gen.nz> +Mark Hahn <hahn@coffee.psychology.mcmaster.ca> +Andreas Hofmeister <Andreas.Hofmeister@pyramid.de> +Oskari Jaaskelainen <osi@fyslab.hut.fi> +Joshua Jensen <joshua@redhat.com> +Jason Lambert <jlambert@lambert-comm.net> +Christoph Lameter <christoph@lameter.com> +Miles Lane <miles@amazon.com> +Janne Liimatainen <liimjann@trade.hamkk.fi> +Benoit Locher <themagpie@wanadoo.fr> +Daniel Lopez <daniel@rawbyte.com> +Stuart Lynne <sdjl@fireplug.net> +Andrew McRory <amacc@iron-bridge.net> +David S. Miller <davem@redhat.com> +Philippe Moutarlier <philippe@kscable.com> +Petr Novopashenniy <pety@au.ru> +Monte Ohrt <monte@ispi.net> +Joachim Ott <ott@ardala.han.de> +Kristian Rietveld <kristian@planet.nl> +Jacob Schroeder <jacob@quantec.de> +Bart de Schuymer <bart.de.schuymer@pandora.be> +Heikki Vatiainen <hessu@cs.tut.fi> +Ernest Yik <ernestyik@cuhk.edu.hk> + +and everyone else I forgot. Thanks also go to Leiden University +for letting me use their equipment and allowing me to work on this +during work hours. + + +I would also like to express my thanks and eternal gratitude to +Margaret Suda. I hope you'll read this some day. @@ -0,0 +1,30 @@ +main code +--------- +Add netlink based API? +we have a tiny deviation from IEEE 802.1d: we don't kill the awaiting-tx skb + queue when a port leaves the FORWARDING state +RH initscripts for setting up bridge interfaces automatically +bridge ID change notifications + +move the spanning tree code to userspace +to be MLT (Nortel Multi Link Trunking) compatible: send bpdu's on all + interfaces in the bonding bundle + +faster switch to forward mode + per-port STP disabling + 'fast start': listening->learning->forwarding in 2*hello instead of 2*fd + +enslaved devs same MAC (like tap), then one changes + +managerial +---------- +improve documentation.. + +netfilter patch +--------------- +sync MAC addresses DNAT/SNAT +make src mac substitution configurable +br_nf_pre_routing: ip_route_output -> output_key +check: don't send unreachables +stp state delay +kernel panic on REDIRECT on bridge device w/o IP address diff --git a/brctl/Makefile.in b/brctl/Makefile.in new file mode 100644 index 0000000..e1956d6 --- /dev/null +++ b/brctl/Makefile.in @@ -0,0 +1,44 @@ + +KERNEL_HEADERS=-I@KERNEL_HEADERS@ + +CC=@CC@ +CFLAGS= -Wall @CFLAGS@ +LDFLAGS=@LDFLAGS@ +INCLUDE=-I../libbridge $(KERNEL_HEADERS) +LIBS= -L ../libbridge -lbridge @LIBS@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +sbindir=@sbindir@ +mandir=@mandir@ + +INSTALL=@INSTALL@ + + +common_SOURCES= brctl_cmd.c brctl_disp.c +brctl_SOURCES= brctl.c $(common_SOURCES) + +common_OBJECTS= $(common_SOURCES:.c=.o) +brctl_OBJECTS= $(brctl_SOURCES:.c=.o) + +OBJECTS= $(common_OBJECTS) $(brctl_OBJECTS) + +PROGRAMS= brctl + + +all: $(PROGRAMS) + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(sbindir) + $(INSTALL) -m 755 $(PROGRAMS) $(DESTDIR)$(sbindir) + +brctl: $(brctl_OBJECTS) ../libbridge/libbridge.a + $(CC) $(LDFLAGS) $(brctl_OBJECTS) $(LIBS) -o brctl + +%.o: %.c brctl.h + $(CC) $(CFLAGS) $(INCLUDE) -c $< + +clean: + rm -f *.o brctl core + diff --git a/brctl/brctl.c b/brctl/brctl.c new file mode 100644 index 0000000..46ca352 --- /dev/null +++ b/brctl/brctl.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/errno.h> +#include <getopt.h> + +#include "libbridge.h" +#include "config.h" + +#include "brctl.h" + +static void help() +{ + printf("Usage: brctl [commands]\n"); + printf("commands:\n"); + command_helpall(); +} + +int main(int argc, char *const* argv) +{ + const struct command *cmd; + int f; + static const struct option options[] = { + { .name = "help", .val = 'h' }, + { .name = "version", .val = 'V' }, + { 0 } + }; + + while ((f = getopt_long(argc, argv, "Vh", options, NULL)) != EOF) + switch(f) { + case 'h': + help(); + return 0; + case 'V': + printf("%s, %s\n", PACKAGE_NAME, PACKAGE_VERSION); + return 0; + default: + fprintf(stderr, "Unknown option '%c'\n", f); + goto help; + } + + if (argc == optind) + goto help; + + if (br_init()) { + fprintf(stderr, "can't setup bridge control: %s\n", + strerror(errno)); + return 1; + } + + argc -= optind; + argv += optind; + if ((cmd = command_lookup(*argv)) == NULL) { + fprintf(stderr, "never heard of command [%s]\n", *argv); + goto help; + } + + if (argc < cmd->nargs + 1) { + printf("Incorrect number of arguments for command\n"); + printf("Usage: brctl %s %s\n", cmd->name, cmd->help); + return 1; + } + + return cmd->func(argc, argv); + +help: + help(); + return 1; +} diff --git a/brctl/brctl.h b/brctl/brctl.h new file mode 100644 index 0000000..55b7897 --- /dev/null +++ b/brctl/brctl.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _BRCTL_H +#define _BRCTL_H + +struct command +{ + int nargs; + const char *name; + int (*func)(int argc, char *const* argv); + const char *help; +}; + +const struct command *command_lookup(const char *cmd); +void command_help(const struct command *); +void command_helpall(void); + +void br_dump_bridge_id(const unsigned char *x); +void br_show_timer(const struct timeval *tv); +void br_dump_interface_list(const char *br); +void br_dump_info(const char *br, const struct bridge_info *bri); + +#endif diff --git a/brctl/brctl_cmd.c b/brctl/brctl_cmd.c new file mode 100644 index 0000000..b4ed104 --- /dev/null +++ b/brctl/brctl_cmd.c @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <errno.h> +#include <asm/param.h> +#include "libbridge.h" +#include "brctl.h" + +static int strtotimeval(struct timeval *tv, const char *time) +{ + double secs; + if (sscanf(time, "%lf", &secs) != 1) + return -1; + tv->tv_sec = secs; + tv->tv_usec = 1000000 * (secs - tv->tv_sec); + return 0; +} + +static int br_cmd_addbr(int argc, char*const* argv) +{ + int err; + + switch (err = br_add_bridge(argv[1])) { + case 0: + return 0; + + case EEXIST: + fprintf(stderr, "device %s already exists; can't create " + "bridge with the same name\n", argv[1]); + return 1; + default: + fprintf(stderr, "add bridge failed: %s\n", + strerror(err)); + return 1; + } +} + +static int br_cmd_delbr(int argc, char*const* argv) +{ + int err; + + switch (err = br_del_bridge(argv[1])){ + case 0: + return 0; + + case ENXIO: + fprintf(stderr, "bridge %s doesn't exist; can't delete it\n", + argv[1]); + return 1; + + case EBUSY: + fprintf(stderr, "bridge %s is still up; can't delete it\n", + argv[1]); + return 1; + + default: + fprintf(stderr, "can't delete bridge %s: %s\n", + argv[1], strerror(err)); + return 1; + } +} + +static int br_cmd_addif(int argc, char *const* argv) +{ + const char *brname; + int err; + + argc -= 2; + brname = *++argv; + + while (argc-- > 0) { + const char *ifname = *++argv; + err = br_add_interface(brname, ifname); + + switch(err) { + case 0: + continue; + + case ENODEV: + if (if_nametoindex(ifname) == 0) + fprintf(stderr, "interface %s does not exist!\n", ifname); + else + fprintf(stderr, "bridge %s does not exist!\n", brname); + break; + + case EBUSY: + fprintf(stderr, "device %s is already a member of a bridge; " + "can't enslave it to bridge %s.\n", ifname, + brname); + break; + + case ELOOP: + fprintf(stderr, "device %s is a bridge device itself; " + "can't enslave a bridge device to a bridge device.\n", + ifname); + break; + + default: + fprintf(stderr, "can't add %s to bridge %s: %s\n", + ifname, brname, strerror(err)); + } + return 1; + } + return 0; +} + +static int br_cmd_delif(int argc, char *const* argv) +{ + const char *brname; + int err; + + argc -= 2; + brname = *++argv; + + while (argc-- > 0) { + const char *ifname = *++argv; + err = br_del_interface(brname, ifname); + switch (err) { + case 0: + continue; + + case ENODEV: + if (if_nametoindex(ifname) == 0) + fprintf(stderr, "interface %s does not exist!\n", ifname); + else + fprintf(stderr, "bridge %s does not exist!\n", brname); + break; + + case EINVAL: + fprintf(stderr, "device %s is not a slave of %s\n", + ifname, brname); + break; + + default: + fprintf(stderr, "can't delete %s from %s: %s\n", + ifname, brname, strerror(err)); + } + return 1; + } + return 0; +} + +static int br_cmd_setageing(int argc, char *const* argv) +{ + int err; + struct timeval tv; + + if (strtotimeval(&tv, argv[2])) { + fprintf(stderr, "bad ageing time value\n"); + return 1; + } + + err = br_set_ageing_time(argv[1], &tv); + if (err) + fprintf(stderr, "set ageing time failed: %s\n", + strerror(err)); + + return err != 0; +} + +static int br_cmd_setbridgeprio(int argc, char *const* argv) +{ + int prio; + int err; + + if (sscanf(argv[2], "%i", &prio) != 1) { + fprintf(stderr,"bad priority\n"); + return 1; + } + + err = br_set_bridge_priority(argv[1], prio); + if (err) + fprintf(stderr, "set bridge priority failed: %s\n", + strerror(err)); + return err != 0; +} + +static int br_cmd_setfd(int argc, char *const* argv) +{ + struct timeval tv; + int err; + + if (strtotimeval(&tv, argv[2])) { + fprintf(stderr, "bad forward delay value\n"); + return 1; + } + + err = br_set_bridge_forward_delay(argv[1], &tv); + if (err) + fprintf(stderr, "set forward delay failed: %s\n", + strerror(err)); + + return err != 0; +} + +static int br_cmd_sethello(int argc, char *const* argv) +{ + struct timeval tv; + int err; + + if (strtotimeval(&tv, argv[2])) { + fprintf(stderr, "bad hello timer value\n"); + return 1; + } + + err = br_set_bridge_hello_time(argv[1], &tv); + if (err) + fprintf(stderr, "set hello timer failed: %s\n", + strerror(err)); + + return err != 0; +} + +static int br_cmd_setmaxage(int argc, char *const* argv) +{ + struct timeval tv; + int err; + + if (strtotimeval(&tv, argv[2])) { + fprintf(stderr, "bad max age value\n"); + return 1; + } + err = br_set_bridge_max_age(argv[1], &tv); + if (err) + fprintf(stderr, "set max age failed: %s\n", + strerror(err)); + + return err != 0; +} + +static int br_cmd_setpathcost(int argc, char *const* argv) +{ + int cost, err; + + if (sscanf(argv[3], "%i", &cost) != 1) { + fprintf(stderr, "bad path cost value\n"); + return 1; + } + + err = br_set_path_cost(argv[1], argv[2], cost); + if (err) + fprintf(stderr, "set path cost failed: %s\n", + strerror(err)); + return err != 0; +} + +static int br_cmd_setportprio(int argc, char *const* argv) +{ + int cost, err; + + if (sscanf(argv[3], "%i", &cost) != 1) { + fprintf(stderr, "bad path priority value\n"); + return 1; + } + + err = br_set_port_priority(argv[1], argv[2], cost); + if (err) + fprintf(stderr, "set port priority failed: %s\n", + strerror(errno)); + + return err != 0; +} + +static int br_cmd_stp(int argc, char *const* argv) +{ + int stp, err; + + if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes") + || !strcmp(argv[2], "1")) + stp = 1; + else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no") + || !strcmp(argv[2], "0")) + stp = 0; + else { + fprintf(stderr, "expect on/off for argument\n"); + return 1; + } + + err = br_set_stp_state(argv[1], stp); + if (err) + fprintf(stderr, "set stp status failed: %s\n", + strerror(errno)); + return err != 0; +} + +static int br_cmd_showstp(int argc, char *const* argv) +{ + struct bridge_info info; + + if (br_get_bridge_info(argv[1], &info)) { + fprintf(stderr, "%s: can't get info %s\n", argv[1], + strerror(errno)); + return 1; + } + + br_dump_info(argv[1], &info); + return 0; +} + +static int show_bridge(const char *name, void *arg) +{ + struct bridge_info info; + + printf("%s\t\t", name); + fflush(stdout); + + if (br_get_bridge_info(name, &info)) { + fprintf(stderr, "can't get info %s\n", + strerror(errno)); + return 1; + } + + br_dump_bridge_id((unsigned char *)&info.bridge_id); + printf("\t%s\t\t", info.stp_enabled?"yes":"no"); + + br_dump_interface_list(name); + return 0; +} + +static int br_cmd_show(int argc, char *const* argv) +{ + int i; + + printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n"); + if (argc == 1) + br_foreach_bridge(show_bridge, NULL); + else + for(i = 2; i <= argc; i++) + show_bridge(argv[i - 1], NULL); + + return 0; +} + +static int compare_fdbs(const void *_f0, const void *_f1) +{ + const struct fdb_entry *f0 = _f0; + const struct fdb_entry *f1 = _f1; + + return memcmp(f0->mac_addr, f1->mac_addr, 6); +} + +static int br_cmd_showmacs(int argc, char *const* argv) +{ + const char *brname = argv[1]; +#define CHUNK 128 + int i, n; + struct fdb_entry *fdb = NULL; + int offset = 0; + + for(;;) { + fdb = realloc(fdb, (offset + CHUNK) * sizeof(struct fdb_entry)); + if (!fdb) { + fprintf(stderr, "Out of memory\n"); + return 1; + } + + n = br_read_fdb(brname, fdb+offset, offset, CHUNK); + if (n == 0) + break; + + if (n < 0) { + fprintf(stderr, "read of forward table failed: %s\n", + strerror(errno)); + return 1; + } + + offset += n; + } + + qsort(fdb, offset, sizeof(struct fdb_entry), compare_fdbs); + + printf("port no\tmac addr\t\tis local?\tageing timer\n"); + for (i = 0; i < offset; i++) { + const struct fdb_entry *f = fdb + i; + printf("%3i\t", f->port_no); + printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t", + f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], + f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]); + printf("%s\t\t", f->is_local?"yes":"no"); + br_show_timer(&f->ageing_timer_value); + printf("\n"); + } + return 0; +} + +static int br_cmd_hairpin(int argc, char *const* argv) +{ + int hairpin, err; + const char *brname = *++argv; + const char *ifname = *++argv; + const char *hpmode = *++argv; + + if (!strcmp(hpmode, "on") || !strcmp(hpmode, "yes") + || !strcmp(hpmode, "1")) + hairpin = 1; + else if (!strcmp(hpmode, "off") || !strcmp(hpmode, "no") + || !strcmp(hpmode, "0")) + hairpin = 0; + else { + fprintf(stderr, "expect on/off for argument\n"); + return 1; + } + if (if_nametoindex(ifname) == 0) { + fprintf(stderr, "interface %s does not exist!\n", + ifname); + return 1; + } else if (if_nametoindex(brname) == 0) { + fprintf(stderr, "bridge %s does not exist!\n", + brname); + return 1; + } + + err = br_set_hairpin_mode(brname, ifname, hairpin); + + if (err) { + fprintf(stderr, "can't set %s to hairpin on bridge %s: %s\n", + ifname, brname, strerror(err)); + } + return err != 0; +} + +static const struct command commands[] = { + { 1, "addbr", br_cmd_addbr, "<bridge>\t\tadd bridge" }, + { 1, "delbr", br_cmd_delbr, "<bridge>\t\tdelete bridge" }, + { 2, "addif", br_cmd_addif, + "<bridge> <device>\tadd interface to bridge" }, + { 2, "delif", br_cmd_delif, + "<bridge> <device>\tdelete interface from bridge" }, + { 3, "hairpin", br_cmd_hairpin, + "<bridge> <port> {on|off}\tturn hairpin on/off" }, + { 2, "setageing", br_cmd_setageing, + "<bridge> <time>\t\tset ageing time" }, + { 2, "setbridgeprio", br_cmd_setbridgeprio, + "<bridge> <prio>\t\tset bridge priority" }, + { 2, "setfd", br_cmd_setfd, + "<bridge> <time>\t\tset bridge forward delay" }, + { 2, "sethello", br_cmd_sethello, + "<bridge> <time>\t\tset hello time" }, + { 2, "setmaxage", br_cmd_setmaxage, + "<bridge> <time>\t\tset max message age" }, + { 3, "setpathcost", br_cmd_setpathcost, + "<bridge> <port> <cost>\tset path cost" }, + { 3, "setportprio", br_cmd_setportprio, + "<bridge> <port> <prio>\tset port priority" }, + { 0, "show", br_cmd_show, + "[ <bridge> ]\t\tshow a list of bridges" }, + { 1, "showmacs", br_cmd_showmacs, + "<bridge>\t\tshow a list of mac addrs"}, + { 1, "showstp", br_cmd_showstp, + "<bridge>\t\tshow bridge stp info"}, + { 2, "stp", br_cmd_stp, + "<bridge> {on|off}\tturn stp on/off" }, +}; + +const struct command *command_lookup(const char *cmd) +{ + int i; + + for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { + if (!strcmp(cmd, commands[i].name)) + return &commands[i]; + } + + return NULL; +} + +void command_helpall(void) +{ + int i; + + for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { + printf("\t%-10s\t%s\n", commands[i].name, commands[i].help); + } +} diff --git a/brctl/brctl_disp.c b/brctl/brctl_disp.c new file mode 100644 index 0000000..3e81241 --- /dev/null +++ b/brctl/brctl_disp.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include "libbridge.h" +#include "brctl.h" + +void br_dump_bridge_id(const unsigned char *x) +{ + printf("%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x", x[0], x[1], x[2], x[3], + x[4], x[5], x[6], x[7]); +} + +void br_show_timer(const struct timeval *tv) +{ + printf("%4i.%.2i", (int)tv->tv_sec, (int)tv->tv_usec/10000); +} + +static int first; + +static int dump_interface(const char *b, const char *p, void *arg) +{ + + if (first) + first = 0; + else + printf("\n\t\t\t\t\t\t\t"); + + printf("%s", p); + + return 0; +} + +void br_dump_interface_list(const char *br) +{ + int err; + + first = 1; + err = br_foreach_port(br, dump_interface, NULL); + if (err < 0) + printf(" can't get port info: %s\n", strerror(-err)); + else + printf("\n"); +} + +static int dump_port_info(const char *br, const char *p, void *arg) +{ + struct port_info pinfo; + + if (br_get_port_info(br, p, &pinfo)) { + printf("Can't get info for %p",p); + return 1; + } + + printf("%s (%d)\n", p, pinfo.port_no); + printf(" port id\t\t%.4x", pinfo.port_id); + printf("\t\t\tstate\t\t%15s\n", br_get_state_name(pinfo.state)); + printf(" designated root\t"); + br_dump_bridge_id((unsigned char *)&pinfo.designated_root); + printf("\tpath cost\t\t%4i\n", pinfo.path_cost); + + printf(" designated bridge\t"); + br_dump_bridge_id((unsigned char *)&pinfo.designated_bridge); + printf("\tmessage age timer\t"); + br_show_timer(&pinfo.message_age_timer_value); + printf("\n designated port\t%.4x", pinfo.designated_port); + printf("\t\t\tforward delay timer\t"); + br_show_timer(&pinfo.forward_delay_timer_value); + printf("\n designated cost\t%4i", pinfo.designated_cost); + printf("\t\t\thold timer\t\t"); + br_show_timer(&pinfo.hold_timer_value); + printf("\n flags\t\t\t"); + if (pinfo.config_pending) + printf("CONFIG_PENDING "); + if (pinfo.top_change_ack) + printf("TOPOLOGY_CHANGE_ACK "); + if (pinfo.hairpin_mode) + printf("\n hairpin mode\t\t\%4i", pinfo.hairpin_mode); + printf("\n"); + printf("\n"); + return 0; +} + +void br_dump_info(const char *br, const struct bridge_info *bri) +{ + int err; + + printf("%s\n", br); + printf(" bridge id\t\t"); + br_dump_bridge_id((unsigned char *)&bri->bridge_id); + printf("\n designated root\t"); + br_dump_bridge_id((unsigned char *)&bri->designated_root); + printf("\n root port\t\t%4i\t\t\t", bri->root_port); + printf("path cost\t\t%4i\n", bri->root_path_cost); + printf(" max age\t\t"); + br_show_timer(&bri->max_age); + printf("\t\t\tbridge max age\t\t"); + br_show_timer(&bri->bridge_max_age); + printf("\n hello time\t\t"); + br_show_timer(&bri->hello_time); + printf("\t\t\tbridge hello time\t"); + br_show_timer(&bri->bridge_hello_time); + printf("\n forward delay\t\t"); + br_show_timer(&bri->forward_delay); + printf("\t\t\tbridge forward delay\t"); + br_show_timer(&bri->bridge_forward_delay); + printf("\n ageing time\t\t"); + br_show_timer(&bri->ageing_time); + printf("\n hello timer\t\t"); + br_show_timer(&bri->hello_timer_value); + printf("\t\t\ttcn timer\t\t"); + br_show_timer(&bri->tcn_timer_value); + printf("\n topology change timer\t"); + br_show_timer(&bri->topology_change_timer_value); + printf("\t\t\tgc timer\t\t"); + br_show_timer(&bri->gc_timer_value); + printf("\n flags\t\t\t"); + if (bri->topology_change) + printf("TOPOLOGY_CHANGE "); + if (bri->topology_change_detected) + printf("TOPOLOGY_CHANGE_DETECTED "); + printf("\n"); + printf("\n"); + printf("\n"); + + err = br_foreach_port(br, dump_port_info, NULL); + if (err < 0) + printf("can't get ports: %s\n", strerror(-err)); +} diff --git a/bridge-utils.spec.in b/bridge-utils.spec.in new file mode 100644 index 0000000..468513b --- /dev/null +++ b/bridge-utils.spec.in @@ -0,0 +1,76 @@ +Name: @PACKAGE@ +Version: @VERSION@ +Release: 1 +Copyright: GPL +Group: System Environment/Base +Url: git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git +Summary: Utilities for configuring the linux ethernet bridge. +Buildroot: %{_tmppath}/%{name}-%{version} +Source: %{name}-%{version}.tar.gz + +%description +This package contains utilities for configuring the linux ethernet +bridge. The linux ethernet bridge can be used for connecting multiple +ethernet devices together. The connecting is fully transparent: hosts +connected to one ethernet device see hosts connected to the other +ethernet devices directly. + +Install bridge-utils if you want to use the linux ethernet bridge. + +%package -n bridge-utils-devel +Summary: Utilities for configuring the linux ethernet bridge. +Group: Development/Libraries + +%description -n bridge-utils-devel +The bridge-utils-devel package contains the header and object files +necessary for developing programs which use 'libbridge.a', the +interface to the linux kernel ethernet bridge. If you are developing +programs which need to configure the linux ethernet bridge, your +system needs to have these standard header and object files available +in order to create the executables. + +Install bridge-utils-devel if you are going to develop programs which +will use the linux ethernet bridge interface library. + +%prep +%setup -q + +%build +CFLAGS="${RPM_OPT_FLAGS}" ./configure --prefix=/usr --mandir=%{_mandir} +make + +%install +rm -rf %{buildroot} + +mkdir -p %{buildroot}%{_sbindir} +mkdir -p %{buildroot}%{_includedir} +mkdir -p %{buildroot}%{_libdir} +mkdir -p %{buildroot}%{_mandir}/man8 +install -m755 brctl/brctl %{buildroot}%{_sbindir} +gzip doc/brctl.8 +install -m 644 doc/brctl.8.gz %{buildroot}%{_mandir}/man8 +install -m 644 libbridge/libbridge.h %{buildroot}%{_includedir} +install -m 644 libbridge/libbridge.a %{buildroot}%{_libdir} + +%clean +[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT + +%files +%defattr (-,root,root) +%doc AUTHORS COPYING doc/FAQ doc/HOWTO doc/RPM-GPG-KEY +%{_sbindir}/brctl +%{_mandir}/man8/brctl.8.gz + +%files -n bridge-utils-devel +%defattr (-,root,root) +%{_includedir}/libbridge.h +%{_libdir}/libbridge.a + +%changelog +* Tue May 25 2004 Stephen Hemminger <shemminger@osdl.org> +- cleanup to work for 1.0 code +- add dependency on sysfs + +* Wed Nov 07 2001 Matthew Galgoci <mgalgoci@redhat.com> +- initial cleanup of spec file from net release + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..5e3f89b --- /dev/null +++ b/configure.in @@ -0,0 +1,27 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(bridge-utils, 1.5) +AC_CONFIG_HEADERS(libbridge/config.h) + +AC_ARG_WITH( linux-headers, [ --with-linux-headers Location of the linux headers to use], + KERNEL_HEADERS=$withval, KERNEL_HEADERS="/usr/src/linux/include") + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(sys/ioctl.h sys/time.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_HEADER_TIME + +dnl Checks for library functions. +AC_CHECK_FUNCS(gethostname socket strdup uname) +AC_CHECK_FUNCS(if_nametoindex if_indextoname) + +AC_SUBST(KERNEL_HEADERS) + +AC_OUTPUT(doc/Makefile libbridge/Makefile brctl/Makefile Makefile bridge-utils.spec) @@ -0,0 +1,2 @@ +The FAQ is now located at + http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge diff --git a/doc/FIREWALL b/doc/FIREWALL new file mode 100644 index 0000000..7ffff86 --- /dev/null +++ b/doc/FIREWALL @@ -0,0 +1,38 @@ +Bridging and firewalling +------------------------ +It is possible to use bridging in combination with firewalling. This is +a blatant violation of the OSI model, but it's very useful, so we don't +care. + +Assuming you are on a non-stone age kernel (less than 5 years old). +You can use the regular iptables firewalling as if you were doing +routing. So, rules for forwarding are added to the FORWARD chain, +rules for input to the local machine are added to the INPUT chain, +etc. Things will work like you expect them to. +So a rule like + + # iptables -A INPUT -i eth0 -j DROP + +will drop all traffic coming from 'eth0', even if the interface the packets +are logically from is, say, 'br0'. + + + +Lennert Buytenhek, November 7th 2001 +<buytenh@gnu.org> + + + +-------------------------- +Bridge+firewalling with 2.2 kernels is also possible, but deprecated. I +would severely recommend against using a 2.2 kernel and ipchains for bridge +firewalling. But if there's really a need, it's still possible. Apply the +extra firewalling patch available from the 'patches' section to your +already-patched-with-the-vanilla-bridge-patch 2.2 kernel, and recompile. Now +if you boot this kernel, the bridging code will check each to-be-forwarded +packet against the ipchains chain which has the same name as the bridge. So.. +if a packet on eth0 is to be forwarded to eth1, and those interfaces are +both part of the bridge group br0, the bridging code will check the packet +against the chain called 'br0'. If the chain does not exist, the packet will +be forwarded. So if you want to do firewalling, you'll have to create the +chain yourself. This is important! diff --git a/doc/HOWTO b/doc/HOWTO new file mode 100644 index 0000000..3729618 --- /dev/null +++ b/doc/HOWTO @@ -0,0 +1,105 @@ +Hello everybody, + +Although there is a man page which documents most of the actual +commands, there is still a 'gap' concerning what bridges are, and how +to set them up. This document attempts to fill this gap. + +In fact, this document is a 15-min hack, so feel free to {complain +about,improve on} it. Especially if this document (or the FAQ) does +not tell you what you want to know; I would consider that to be a bug. + + +Have fun! +Lennert Buytenhek + + +<================= CUT HERE AND DAMAGE YOUR SCREEN =================> + + + +1. The basics +------------- + +What does a bridge actually do? In plain English, a bridge connects +two or more different physical ethernets together to form one large +(logical) ethernet. The physical ethernets being connected together +correspond to network interfaces in your linux box. The bigger +(logical) ethernet corresponds to a virtual network interface in linux +(often called br0, br1, br2, etc.) + +Let's say we want to tie eth0 and eth1 together, turning those +networks into one larger network. What do we do? Well, we need to +create an instance of the bridge first. + + # brctl addbr br0 + +(You can check that this gives you a network interface called br0.) +Now we want to enslave eth0 and eth1 to this bridge. + + # brctl addif br0 eth0 + # brctl addif br0 eth1 + +And now... because we connected the two ethernets together, they now +form one large subnet. We are actually only on only one subnet, namely +br0. We can forget about the fact that br0 is actually eth[01] in +disguise; we will only deal with br0 from now on. Because we are only +on one subnet, we only need one IP address for the bridge. This +address we assign to br0. eth0 and eth1 should not have IP addresses +allocated to them. + + # ifconfig eth0 0.0.0.0 + # ifconfig eth1 0.0.0.0 + # ifconfig br0 my.ip.address.here + +The last command also puts the interface br0 into the 'up' state. This +will activate the forwarding of packets, which in plain English means +that from that point on, eth0 and eth1 will be 'joined' +together. Hosts on eth0 should 'see' hosts on eth1 and vice versa. + +The bridge will also (automatically) activate the Spanning Tree +Protocol: this is a network protocol spoken by switches for (roughly +speaking) calculating the shortest distances and eliminating loops in +the topology of the network. You can disable the stp if you really +want/need to; see brctl(8) for details. + + + +2. More complicated setups +-------------------------- + +We can create multiple bridge port groups and do filtering/NATting +between them, just like we can do that with ordinary network +interfaces. + +For example: on a quadport network card, dedicate two ports to a LAN +on which we have IP 10.16.0.254, and the other two ports to a LAN on +which we have IP 192.168.10.1 (this is an actual setup) + + # brctl addbr br_10 + # brctl addif br_10 eth0 + # brctl addif br_10 eth1 + # ifconfig br_10 10.16.0.254 + + # brctl addbr br_192 + # brctl addif br_192 eth2 + # brctl addif br_192 eth3 + # ifconfig br_192 192.168.10.1 + +You now have logical network interfaces br_10 and br_192, which will +act just like ordinary interfaces. The only difference is that they +each correspond to two physical network interfaces, but nobody cares +about that. + +So.. for example, if 192.168.10.2 is the only host on the 192.* +network that is allowed to access the 10.* network, we would do: + +ipchains -P forward REJECT +ipchains -A forward -s 192.168.10.2/32 -d 10.0.0.0/8 -i br_10 -j ACCEPT + +(just like you were used to). + + + + + +Hope this helped. If not, send a cry for help to the mailing list. diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..23bfb06 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,21 @@ + +DESTDIR= +KERNEL_HEADERS=-I@KERNEL_HEADERS@ + +INSTALL=@INSTALL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +sbindir=@sbindir@ +mandir=@mandir@ + +SUBDIRS=libbridge brctl + +all: + +clean: + +install: + mkdir -p $(DESTDIR)$(mandir)/man8 + $(INSTALL) -m 644 brctl.8 $(DESTDIR)$(mandir)/man8 diff --git a/doc/PROJECTS b/doc/PROJECTS new file mode 100644 index 0000000..de6dfb3 --- /dev/null +++ b/doc/PROJECTS @@ -0,0 +1,2 @@ +- Kristian Rietveld <kristian@planet.nl> is working on a GNOME + interface. diff --git a/doc/RPM-GPG-KEY b/doc/RPM-GPG-KEY new file mode 100644 index 0000000..83b1956 --- /dev/null +++ b/doc/RPM-GPG-KEY @@ -0,0 +1,30 @@ +Hi, + +This public key is the GPG public key I use to sign the bridge-utils +and bridge-utils-devel RPM packages. You can use this key to verify +the integrity of those packages. + +Lennert Buytenhek +<buytenh@gnu.org> + + + + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.1 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +mQGiBDiT6YIRBADbn6OduygntL0gYcBD3333gje45DSWl0PVghw9CtJQUZRZSBFp +Z1CgkxI1F3kza4gJwIj/fgtuC8PWi1200rOwCLL8kLkFIH9Zy0VEuXskoXLeDU/f +V14e+9GVtoVLQ5Bx2bTez3+2dEU7N0axKH5MJQsyWZx+U863unNk/qGO1wCgjYZ5 +zKhTuvWnR51tYjdwbfXyq0sD/iflTEUFkQ0MEQc/eJ+RU9kL55GyhT7f227CR6XZ +/d2LCUkdaCdihAsJLXEL66gS7MOUd5I6dolPXG0vG0wQMBqt/jcKr2JRZsSf2Zjg +IxTvlv+6h6LyaHBiq45yCAE1KC2ka2ebtdK0BubdRjKlxDMmGJMrMTeK6RsLbDej +SEhqBACTtgUO9gOAFB53TAAjpftMW91mTOiokg1znKxqunbJ/4Ndo9Z9KI1m4wH8 +RsyGJBEkwlR5PNjnLZbE0ET2hk01RLFWX8yDXORXDx1bkcW/NJgMkyUua3A2QaTV +D1SdIfnMLB2vg4FzjUdo9QXS+zNQ24jS7G6tDq8McvVM2DSwp7Q3TGVubmVydCBC +dXl0ZW5oZWsgKFJQTSBzaWduYXR1cmUga2V5KSA8YnV5dGVuaEBnbnUub3JnPohW +BBMRAgAWBQI4k+mCBAsKBAMDFQMCAxYCAQIXgAAKCRD/CxH2tC7NLt6pAKCGnrIT +EfdFTc5S/Fz+LAYokMWKTwCfU7DQG4bkaOJTcv5fRUOD4UZ2MTk= +=om8h +-----END PGP PUBLIC KEY BLOCK----- diff --git a/doc/SMPNOTES b/doc/SMPNOTES new file mode 100644 index 0000000..ba54836 --- /dev/null +++ b/doc/SMPNOTES @@ -0,0 +1,21 @@ +Notes on the (20000210) SMP-ization of the bridging code: + +Each bridge has a hash table of MAC addresses. This table is protected +by a rwlock hash_lock. The entries are refcounted; 'getting' an entry +is done in the usual way: read_lock the table, find the entry, +increment it's refcount and unlock the table. Bottom half context +acquires this lock in read as well as write mode, therefore we always +need to locally disable BHs when acquiring this lock. + +Each bridge also has an rwlock called lock. This slightly misnamed +lock protects the bridge's port_list. All stp code acquires this lock +in read mode, the only piece of code that acquires this lock in write +mode is the ioctl code (br_ioctl.c). Bottom halves never acquire this +lock in write mode, therefore we can use read_lock instead of +read_lock_bh in all cases. + +All ioctls are globally serialized by the semaphore ioctl_mutex. All +code which acquires the bridge lock in write mode also acquires +ioctl_mutex. Therefore, if we have already grabbed ioctl_mutex we +don't need to read_lock the bridge lock anymore; the ioctl_mutex will +protect against concurrent writers. diff --git a/doc/WISHLIST b/doc/WISHLIST new file mode 100644 index 0000000..43ca124 --- /dev/null +++ b/doc/WISHLIST @@ -0,0 +1,25 @@ +Would be nice if: + +- Add address learning limiting (hard limit at a fixed # of + addresses? or maybe using rate markers?). There is a nasty DoS in + here. + +- Add fdb entry port # change limiting. For example: if one MAC + address switches port more than once in the same second, there is + something wrong (somebody trying to spoof?), so print a warning. + +- Faster port state cycling; currently it takes 30 seconds for ports + to cycle to the forwarding state. + +- Detect port speed and adjust path cost accordingly? + +- Use MII ioctls for detecting link beat lost quickly? + +- Keep the IEEE 802.1d-mandated statistics (counters, mostly). + +- Maybe integrate Kristian's GNOME frontend (see PROJECTS) once it + stabilises. It looks nice. + +- A cgi bridge configurer (a la Samba's SWAT, yummy....) + + diff --git a/doc/brctl.8 b/doc/brctl.8 new file mode 100644 index 0000000..a708bc1 --- /dev/null +++ b/doc/brctl.8 @@ -0,0 +1,172 @@ +.\" +.\" 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., 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.\" +.TH BRCTL 8 "November 7, 2001" "" "" +.SH NAME +brctl \- ethernet bridge administration +.SH SYNOPSIS +.BR "brctl [command]" +.SH DESCRIPTION +.B brctl +is used to set up, maintain, and inspect the ethernet bridge +configuration in the Linux kernel. + +An ethernet bridge is a device commonly used to connect different +networks of ethernets together, so that these ethernets will appear as +one ethernet to the participants. + +Each of the ethernets being connected corresponds to one physical +interface in the bridge. These individual ethernets are bundled into +one bigger ('logical') ethernet, this bigger ethernet corresponds to +the bridge network interface. + + +.SH INSTANCES +The command +.B brctl addbr <name> +creates a new instance of the ethernet bridge. The network interface +corresponding to the bridge will be called <name>. + +The command +.B brctl delbr <name> +deletes the instance <name> of the ethernet bridge. The network +interface corresponding to the bridge must be down before it can be +deleted! + +The command +.B brctl show +shows all current instances of the ethernet bridge. + + +.SH PORTS +Each bridge has a number of ports attached to it. Network traffic +coming in on any of these ports will be forwarded to the other ports +transparently, so that the bridge is invisible to the rest of the +network (i.e. it will not show up in +.IR traceroute(8) +). + +The command +.B brctl addif <brname> <ifname> +will make the interface <ifname> a port of the bridge <brname>. This +means that all frames received on <ifname> will be processed as if +destined for the bridge. Also, when sending frames on <brname>, +<ifname> will be considered as a potential output interface. + +The command +.B brctl delif <brname> <ifname> +will detach the interface <ifname> from the bridge <brname>. + +The command +.B brctl show <brname> +will show some information on the bridge and its attached ports. + + +.SH AGEING +The bridge keeps track of ethernet addresses seen on each port. When +it needs to forward a frame, and it happens to know on which port the +destination ethernet address (specified in the frame) is located, it +can 'cheat' by forwarding the frame to that port only, thus saving a +lot of redundant copies and transmits. + +However, the ethernet address location data is not static +data. Machines can move to other ports, network cards can be replaced +(which changes the machine's ethernet address), etc. + +.B brctl showmacs <brname> +shows a list of learned MAC addresses for this bridge. + +.B brctl setageing <brname> <time> +sets the ethernet (MAC) address ageing time, in seconds. After <time> +seconds of not having seen a frame coming from a certain address, the +bridge will time out (delete) that address from the Forwarding +DataBase (fdb). + +.B brctl setgcint <brname> <time> +sets the garbage collection interval for the bridge <brname> to <time> +seconds. This means that the bridge will check the forwarding database +for timed out entries every <time> seconds. + + +.SH SPANNING TREE PROTOCOL +Multiple ethernet bridges can work together to create even larger +networks of ethernets using the IEEE 802.1d spanning tree +protocol. This protocol is used for finding the shortest path between +two ethernets, and for eliminating loops from the topology. As this +protocol is a standard, Linux bridges will interwork properly with +other third party bridge products. Bridges communicate with each other +by sending and receiving BPDUs (Bridge Protocol Data Units). These +BPDUs can be recognised by an ethernet destination address of +01:80:c2:00:00:00. + +The spanning tree protocol can also be turned off (for those +situations where it just doesn't make sense, for example when this +Linux box is the only bridge on the LAN, or when you know that there +are no loops in the topology.) + +.IR brctl(8) +can be used for configuring certain spanning tree protocol +parameters. For an explanation of these parameters, see the IEEE +802.1d specification (or send me an email). The default values should +be just fine. If you don't know what these parameters mean, you +probably won't feel the desire to tweak them. + +.B brctl stp <bridge> <state> +controls this bridge instance's participation in the spanning tree +protocol. If <state> is "on" or "yes" the STP will be turned on, +otherwise it will be turned off. When turned off, the bridge will not +send or receive BPDUs, and will thus not participate in the spanning +tree protocol. If your bridge isn't the only bridge on the LAN, or if +there are loops in the LAN's topology, DO NOT turn this option off. If +you turn this option off, please know what you are doing. + + +.B brctl setbridgeprio <bridge> <priority> +sets the bridge's priority to <priority>. The priority value is an +unsigned 16-bit quantity (a number between 0 and 65535), and has no +dimension. Lower priority values are 'better'. The bridge with the +lowest priority will be elected 'root bridge'. + +.B brctl setfd <bridge> <time> +sets the bridge's 'bridge forward delay' to <time> seconds. + +.B brctl sethello <bridge> <time> +sets the bridge's 'bridge hello time' to <time> seconds. + +.B brctl setmaxage <bridge> <time> +sets the bridge's 'maximum message age' to <time> seconds. + +.B brctl setpathcost <bridge> <port> <cost> +sets the port cost of the port <port> to <cost>. This is a +dimensionless metric. + +.B brctl setportprio <bridge> <port> <priority> +sets the port <port>'s priority to <priority>. The priority value is +an unsigned 8-bit quantity (a number between 0 and 255), and has no +dimension. This metric is used in the designated port and root port +selection algorithms. + + +.SH NOTES +.BR brctl(8) +replaces the older brcfg tool. + +.SH SEE ALSO +.BR ipchains(8), +.BR iptables(8) + +.SH AUTHOR +Lennert Buytenhek <buytenh@gnu.org> diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/libbridge/.gitignore b/libbridge/.gitignore new file mode 100644 index 0000000..f611548 --- /dev/null +++ b/libbridge/.gitignore @@ -0,0 +1,2 @@ +config.h +stamp-h1 diff --git a/libbridge/Makefile.in b/libbridge/Makefile.in new file mode 100644 index 0000000..20512c4 --- /dev/null +++ b/libbridge/Makefile.in @@ -0,0 +1,41 @@ + +KERNEL_HEADERS=-I@KERNEL_HEADERS@ + +AR=ar +RANLIB=@RANLIB@ + +CC=@CC@ +CFLAGS = -Wall -g $(KERNEL_HEADERS) + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libdir@ + +libbridge_SOURCES= \ + libbridge_devif.c \ + libbridge_if.c \ + libbridge_init.c \ + libbridge_misc.c + +libbridge_OBJECTS=$(libbridge_SOURCES:.c=.o) + +all: libbridge.a + +# At present there is no need for a bridge-utils-devel package +install: + + +clean: + rm -f *.o libbridge.a + +libbridge.a: $(libbridge_OBJECTS) + $(AR) rcs $@ $(libbridge_OBJECTS) + $(RANLIB) $@ + +%.o: %.c libbridge.h libbridge_private.h + $(CC) $(CFLAGS) $(INCLUDE) -c $< + +libbridge_compat.o: libbridge_compat.c if_index.c + $(CC) $(CFLAGS) -c libbridge_compat.c + diff --git a/libbridge/config.h.in b/libbridge/config.h.in new file mode 100644 index 0000000..22d1d7a --- /dev/null +++ b/libbridge/config.h.in @@ -0,0 +1,79 @@ +/* libbridge/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the `gethostname' function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have the `if_indextoname' function. */ +#undef HAVE_IF_INDEXTONAME + +/* Define to 1 if you have the `if_nametoindex' function. */ +#undef HAVE_IF_NAMETOINDEX + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/ioctl.h> header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the `uname' function. */ +#undef HAVE_UNAME + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ +#undef TIME_WITH_SYS_TIME + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/libbridge/libbridge.h b/libbridge/libbridge.h new file mode 100644 index 0000000..39964f2 --- /dev/null +++ b/libbridge/libbridge.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LIBBRIDGE_H +#define _LIBBRIDGE_H + +#include <sys/socket.h> +#include <linux/if.h> +#include <linux/if_bridge.h> + +/* defined in net/if.h but that conflicts with linux/if.h... */ +extern unsigned int if_nametoindex (const char *__ifname); +extern char *if_indextoname (unsigned int __ifindex, char *__ifname); + + +struct bridge_id +{ + unsigned char prio[2]; + unsigned char addr[6]; +}; + +struct bridge_info +{ + struct bridge_id designated_root; + struct bridge_id bridge_id; + unsigned root_path_cost; + struct timeval max_age; + struct timeval hello_time; + struct timeval forward_delay; + struct timeval bridge_max_age; + struct timeval bridge_hello_time; + struct timeval bridge_forward_delay; + u_int16_t root_port; + unsigned char stp_enabled; + unsigned char topology_change; + unsigned char topology_change_detected; + struct timeval ageing_time; + struct timeval hello_timer_value; + struct timeval tcn_timer_value; + struct timeval topology_change_timer_value; + struct timeval gc_timer_value; +}; + +struct fdb_entry +{ + u_int8_t mac_addr[6]; + u_int16_t port_no; + unsigned char is_local; + struct timeval ageing_timer_value; +}; + +struct port_info +{ + unsigned port_no; + struct bridge_id designated_root; + struct bridge_id designated_bridge; + u_int16_t port_id; + u_int16_t designated_port; + u_int8_t priority; + unsigned char top_change_ack; + unsigned char config_pending; + unsigned char state; + unsigned path_cost; + unsigned designated_cost; + struct timeval message_age_timer_value; + struct timeval forward_delay_timer_value; + struct timeval hold_timer_value; + unsigned char hairpin_mode; +}; + +extern int br_init(void); +extern int br_refresh(void); +extern void br_shutdown(void); + +extern int br_foreach_bridge(int (*iterator)(const char *brname, void *), + void *arg); +extern int br_foreach_port(const char *brname, + int (*iterator)(const char *brname, const char *port, + void *arg ), + void *arg); +extern const char *br_get_state_name(int state); + +extern int br_get_bridge_info(const char *br, struct bridge_info *info); +extern int br_get_port_info(const char *brname, const char *port, + struct port_info *info); +extern int br_add_bridge(const char *brname); +extern int br_del_bridge(const char *brname); +extern int br_add_interface(const char *br, const char *dev); +extern int br_del_interface(const char *br, const char *dev); +extern int br_set_bridge_forward_delay(const char *br, struct timeval *tv); +extern int br_set_bridge_hello_time(const char *br, struct timeval *tv); +extern int br_set_bridge_max_age(const char *br, struct timeval *tv); +extern int br_set_ageing_time(const char *br, struct timeval *tv); +extern int br_set_stp_state(const char *br, int stp_state); +extern int br_set_bridge_priority(const char *br, int bridge_priority); +extern int br_set_port_priority(const char *br, const char *p, + int port_priority); +extern int br_set_path_cost(const char *br, const char *p, + int path_cost); +extern int br_read_fdb(const char *br, struct fdb_entry *fdbs, + unsigned long skip, int num); +extern int br_set_hairpin_mode(const char *bridge, const char *dev, + int hairpin_mode); +#endif diff --git a/libbridge/libbridge_devif.c b/libbridge/libbridge_devif.c new file mode 100644 index 0000000..1e83925 --- /dev/null +++ b/libbridge/libbridge_devif.c @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <sys/fcntl.h> + +#include "libbridge.h" +#include "libbridge_private.h" + +static FILE *fpopen(const char *dir, const char *name) +{ + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, "%s/%s", dir, name); + return fopen(path, "r"); +} + +static void fetch_id(const char *dev, const char *name, struct bridge_id *id) +{ + FILE *f = fpopen(dev, name); + + if (!f) + fprintf(stderr, "%s: %s\n", dev, strerror(errno)); + else { + fscanf(f, "%2hhx%2hhx.%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", + &id->prio[0], &id->prio[1], + &id->addr[0], &id->addr[1], &id->addr[2], + &id->addr[3], &id->addr[4], &id->addr[5]); + fclose(f); + } +} + +/* Fetch an integer attribute out of sysfs. */ +static int fetch_int(const char *dev, const char *name) +{ + FILE *f = fpopen(dev, name); + int value = -1; + + if (!f) + return 0; + + fscanf(f, "%i", &value); + fclose(f); + return value; +} + +/* Get a time value out of sysfs */ +static void fetch_tv(const char *dev, const char *name, + struct timeval *tv) +{ + __jiffies_to_tv(tv, fetch_int(dev, name)); +} + +/* + * Convert device name to an index in the list of ports in bridge. + * + * Old API does bridge operations as if ports were an array + * inside bridge structure. + */ +static int get_portno(const char *brname, const char *ifname) +{ + int i; + int ifindex = if_nametoindex(ifname); + int ifindices[MAX_PORTS]; + unsigned long args[4] = { BRCTL_GET_PORT_LIST, + (unsigned long)ifindices, MAX_PORTS, 0 }; + struct ifreq ifr; + + if (ifindex <= 0) + goto error; + + memset(ifindices, 0, sizeof(ifindices)); + strncpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + + if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { + dprintf("get_portno: get ports of %s failed: %s\n", + brname, strerror(errno)); + goto error; + } + + for (i = 0; i < MAX_PORTS; i++) { + if (ifindices[i] == ifindex) + return i; + } + + dprintf("%s is not a in bridge %s\n", ifname, brname); + error: + return -1; +} + +/* get information via ioctl */ +static int old_get_bridge_info(const char *bridge, struct bridge_info *info) +{ + struct ifreq ifr; + struct __bridge_info i; + unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO, + (unsigned long) &i, 0, 0 }; + + memset(info, 0, sizeof(*info)); + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + + if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { + dprintf("%s: can't get info %s\n", + bridge, strerror(errno)); + return errno; + } + + memcpy(&info->designated_root, &i.designated_root, 8); + memcpy(&info->bridge_id, &i.bridge_id, 8); + info->root_path_cost = i.root_path_cost; + info->root_port = i.root_port; + info->topology_change = i.topology_change; + info->topology_change_detected = i.topology_change_detected; + info->stp_enabled = i.stp_enabled; + __jiffies_to_tv(&info->max_age, i.max_age); + __jiffies_to_tv(&info->hello_time, i.hello_time); + __jiffies_to_tv(&info->forward_delay, i.forward_delay); + __jiffies_to_tv(&info->bridge_max_age, i.bridge_max_age); + __jiffies_to_tv(&info->bridge_hello_time, i.bridge_hello_time); + __jiffies_to_tv(&info->bridge_forward_delay, i.bridge_forward_delay); + __jiffies_to_tv(&info->ageing_time, i.ageing_time); + __jiffies_to_tv(&info->hello_timer_value, i.hello_timer_value); + __jiffies_to_tv(&info->tcn_timer_value, i.tcn_timer_value); + __jiffies_to_tv(&info->topology_change_timer_value, + i.topology_change_timer_value); + __jiffies_to_tv(&info->gc_timer_value, i.gc_timer_value); + + return 0; +} + +/* + * Get bridge parameters using either sysfs or old + * ioctl. + */ +int br_get_bridge_info(const char *bridge, struct bridge_info *info) +{ + DIR *dir; + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge); + dir = opendir(path); + if (dir == NULL) { + dprintf("path '%s' is not a directory\n", path); + goto fallback; + } + + memset(info, 0, sizeof(*info)); + fetch_id(path, "root_id", &info->designated_root); + fetch_id(path, "bridge_id", &info->bridge_id); + info->root_path_cost = fetch_int(path, "root_path_cost"); + fetch_tv(path, "max_age", &info->max_age); + fetch_tv(path, "hello_time", &info->hello_time); + fetch_tv(path, "forward_delay", &info->forward_delay); + fetch_tv(path, "max_age", &info->bridge_max_age); + fetch_tv(path, "hello_time", &info->bridge_hello_time); + fetch_tv(path, "forward_delay", &info->bridge_forward_delay); + fetch_tv(path, "ageing_time", &info->ageing_time); + fetch_tv(path, "hello_timer", &info->hello_timer_value); + fetch_tv(path, "tcn_timer", &info->tcn_timer_value); + fetch_tv(path, "topology_change_timer", + &info->topology_change_timer_value);; + fetch_tv(path, "gc_timer", &info->gc_timer_value); + + info->root_port = fetch_int(path, "root_port"); + info->stp_enabled = fetch_int(path, "stp_state"); + info->topology_change = fetch_int(path, "topology_change"); + info->topology_change_detected = fetch_int(path, "topology_change_detected"); + + closedir(dir); + return 0; + +fallback: + return old_get_bridge_info(bridge, info); +} + +static int old_get_port_info(const char *brname, const char *port, + struct port_info *info) +{ + struct __port_info i; + int index; + + memset(info, 0, sizeof(*info)); + + index = get_portno(brname, port); + if (index < 0) + return errno; + + else { + struct ifreq ifr; + unsigned long args[4] = { BRCTL_GET_PORT_INFO, + (unsigned long) &i, index, 0 }; + + strncpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + + if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { + dprintf("old can't get port %s(%d) info %s\n", + brname, index, strerror(errno)); + return errno; + } + } + + info->port_no = index; + memcpy(&info->designated_root, &i.designated_root, 8); + memcpy(&info->designated_bridge, &i.designated_bridge, 8); + info->port_id = i.port_id; + info->designated_port = i.designated_port; + info->path_cost = i.path_cost; + info->designated_cost = i.designated_cost; + info->state = i.state; + info->top_change_ack = i.top_change_ack; + info->config_pending = i.config_pending; + __jiffies_to_tv(&info->message_age_timer_value, + i.message_age_timer_value); + __jiffies_to_tv(&info->forward_delay_timer_value, + i.forward_delay_timer_value); + __jiffies_to_tv(&info->hold_timer_value, i.hold_timer_value); + info->hairpin_mode = 0; + return 0; +} + +/* + * Get information about port on bridge. + */ +int br_get_port_info(const char *brname, const char *port, + struct port_info *info) +{ + DIR *d; + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", port); + d = opendir(path); + if (!d) + goto fallback; + + memset(info, 0, sizeof(*info)); + + fetch_id(path, "designated_root", &info->designated_root); + fetch_id(path, "designated_bridge", &info->designated_bridge); + info->port_no = fetch_int(path, "port_no"); + info->port_id = fetch_int(path, "port_id"); + info->designated_port = fetch_int(path, "designated_port"); + info->path_cost = fetch_int(path, "path_cost"); + info->designated_cost = fetch_int(path, "designated_cost"); + info->state = fetch_int(path, "state"); + info->top_change_ack = fetch_int(path, "change_ack"); + info->config_pending = fetch_int(path, "config_pending"); + fetch_tv(path, "message_age_timer", &info->message_age_timer_value); + fetch_tv(path, "forward_delay_timer", &info->forward_delay_timer_value); + fetch_tv(path, "hold_timer", &info->hold_timer_value); + info->hairpin_mode = fetch_int(path, "hairpin_mode"); + + closedir(d); + + return 0; +fallback: + return old_get_port_info(brname, port, info); +} + +static int set_sysfs(const char *path, unsigned long value) +{ + int fd, ret = 0, cc; + char buf[32]; + + fd = open(path, O_WRONLY); + if (fd < 0) + return -1; + + cc = snprintf(buf, sizeof(buf), "%lu\n", value); + if (write(fd, buf, cc) < 0) + ret = -1; + close(fd); + + return ret; +} + + +static int br_set(const char *bridge, const char *name, + unsigned long value, unsigned long oldcode) +{ + int ret; + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge/%s", + bridge, name); + + if ((ret = set_sysfs(path, value)) < 0) { + /* fallback to old ioctl */ + struct ifreq ifr; + unsigned long args[4] = { oldcode, value, 0, 0 }; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + + return ret < 0 ? errno : 0; +} + +int br_set_bridge_forward_delay(const char *br, struct timeval *tv) +{ + return br_set(br, "forward_delay", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_FORWARD_DELAY); +} + +int br_set_bridge_hello_time(const char *br, struct timeval *tv) +{ + return br_set(br, "hello_time", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_HELLO_TIME); +} + +int br_set_bridge_max_age(const char *br, struct timeval *tv) +{ + return br_set(br, "max_age", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_MAX_AGE); +} + +int br_set_ageing_time(const char *br, struct timeval *tv) +{ + return br_set(br, "ageing_time", __tv_to_jiffies(tv), + BRCTL_SET_AGEING_TIME); +} + +int br_set_stp_state(const char *br, int stp_state) +{ + return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE); +} + +int br_set_bridge_priority(const char *br, int bridge_priority) +{ + return br_set(br, "priority", bridge_priority, + BRCTL_SET_BRIDGE_PRIORITY); +} + +static int port_set(const char *bridge, const char *ifname, + const char *name, unsigned long value, + unsigned long oldcode) +{ + int ret; + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport/%s", ifname, name); + + if ((ret = set_sysfs(path, value)) < 0) { + int index = get_portno(bridge, ifname); + + if (index < 0) + ret = index; + else { + struct ifreq ifr; + unsigned long args[4] = { oldcode, index, value, 0 }; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + } + + return ret < 0 ? errno : 0; +} + +int br_set_port_priority(const char *bridge, const char *port, int priority) +{ + return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY); +} + +int br_set_path_cost(const char *bridge, const char *port, int cost) +{ + return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST); +} + +int br_set_hairpin_mode(const char *bridge, const char *port, int hairpin_mode) +{ + return port_set(bridge, port, "hairpin_mode", hairpin_mode, 0); +} + +static inline void __copy_fdb(struct fdb_entry *ent, + const struct __fdb_entry *f) +{ + memcpy(ent->mac_addr, f->mac_addr, 6); + ent->port_no = f->port_no; + ent->is_local = f->is_local; + __jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value); +} + +int br_read_fdb(const char *bridge, struct fdb_entry *fdbs, + unsigned long offset, int num) +{ + FILE *f; + int i, n; + struct __fdb_entry fe[num]; + char path[SYSFS_PATH_MAX]; + + /* open /sys/class/net/brXXX/brforward */ + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brforward", bridge); + f = fopen(path, "r"); + if (f) { + fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET); + n = fread(fe, sizeof(struct __fdb_entry), num, f); + fclose(f); + } else { + /* old kernel, use ioctl */ + unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES, + (unsigned long) fe, + num, offset }; + struct ifreq ifr; + int retries = 0; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) args; + + retry: + n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + + /* table can change during ioctl processing */ + if (n < 0 && errno == EAGAIN && ++retries < 10) { + sleep(0); + goto retry; + } + } + + for (i = 0; i < n; i++) + __copy_fdb(fdbs+i, fe+i); + + return n; +} diff --git a/libbridge/libbridge_if.c b/libbridge/libbridge_if.c new file mode 100644 index 0000000..77d3f8a --- /dev/null +++ b/libbridge/libbridge_if.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> + +#include "libbridge.h" +#include "libbridge_private.h" + + +int br_add_bridge(const char *brname) +{ + int ret; + +#ifdef SIOCBRADDBR + ret = ioctl(br_socket_fd, SIOCBRADDBR, brname); + if (ret < 0) +#endif + { + char _br[IFNAMSIZ]; + unsigned long arg[3] + = { BRCTL_ADD_BRIDGE, (unsigned long) _br }; + + strncpy(_br, brname, IFNAMSIZ); + ret = ioctl(br_socket_fd, SIOCSIFBR, arg); + } + + return ret < 0 ? errno : 0; +} + +int br_del_bridge(const char *brname) +{ + int ret; + +#ifdef SIOCBRDELBR + ret = ioctl(br_socket_fd, SIOCBRDELBR, brname); + if (ret < 0) +#endif + { + char _br[IFNAMSIZ]; + unsigned long arg[3] + = { BRCTL_DEL_BRIDGE, (unsigned long) _br }; + + strncpy(_br, brname, IFNAMSIZ); + ret = ioctl(br_socket_fd, SIOCSIFBR, arg); + } + return ret < 0 ? errno : 0; +} + +int br_add_interface(const char *bridge, const char *dev) +{ + struct ifreq ifr; + int err; + int ifindex = if_nametoindex(dev); + + if (ifindex == 0) + return ENODEV; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRADDIF + ifr.ifr_ifindex = ifindex; + err = ioctl(br_socket_fd, SIOCBRADDIF, &ifr); + if (err < 0) +#endif + { + unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + + return err < 0 ? errno : 0; +} + +int br_del_interface(const char *bridge, const char *dev) +{ + struct ifreq ifr; + int err; + int ifindex = if_nametoindex(dev); + + if (ifindex == 0) + return ENODEV; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRDELIF + ifr.ifr_ifindex = ifindex; + err = ioctl(br_socket_fd, SIOCBRDELIF, &ifr); + if (err < 0) +#endif + { + unsigned long args[4] = { BRCTL_DEL_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + + return err < 0 ? errno : 0; +} diff --git a/libbridge/libbridge_init.c b/libbridge/libbridge_init.c new file mode 100644 index 0000000..f3a551e --- /dev/null +++ b/libbridge/libbridge_init.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "libbridge.h" +#include "libbridge_private.h" + +int br_socket_fd = -1; + +int br_init(void) +{ + if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) + return errno; + return 0; +} + +void br_shutdown(void) +{ + close(br_socket_fd); + br_socket_fd = -1; +} + +/* If /sys/class/net/XXX/bridge exists then it must be a bridge */ +static int isbridge(const struct dirent *entry) +{ + char path[SYSFS_PATH_MAX]; + struct stat st; + int ret, saved_errno; + + if (entry->d_name[0] == '.' + && (entry->d_name[1] == '\0' + || (entry->d_name[1] == '.' + && entry->d_name[2] == '\0'))) + return 0; + + snprintf(path, SYSFS_PATH_MAX, + SYSFS_CLASS_NET "%s/bridge", entry->d_name); + + /* Workaround old glibc breakage. + If errno is set, then it fails scandir! */ + saved_errno = errno; + ret = (stat(path, &st) == 0 && S_ISDIR(st.st_mode)); + errno = saved_errno; + + return ret; +} + +/* + * New interface uses sysfs to find bridges + */ +static int new_foreach_bridge(int (*iterator)(const char *name, void *), + void *arg) +{ + struct dirent **namelist; + int i, count = 0; + + count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort); + if (count < 0) + return -1; + + for (i = 0; i < count; i++) { + if (iterator(namelist[i]->d_name, arg)) + break; + } + + for (i = 0; i < count; i++) + free(namelist[i]); + free(namelist); + + return count; +} + +/* + * Old interface uses ioctl + */ +static int old_foreach_bridge(int (*iterator)(const char *, void *), + void *iarg) +{ + int i, ret=0, num; + char ifname[IFNAMSIZ]; + int ifindices[MAX_BRIDGES]; + unsigned long args[3] = { BRCTL_GET_BRIDGES, + (unsigned long)ifindices, MAX_BRIDGES }; + + num = ioctl(br_socket_fd, SIOCGIFBR, args); + if (num < 0) { + dprintf("Get bridge indices failed: %s\n", + strerror(errno)); + return -errno; + } + + for (i = 0; i < num; i++) { + if (!if_indextoname(ifindices[i], ifname)) { + dprintf("get find name for ifindex %d\n", + ifindices[i]); + return -errno; + } + + ++ret; + if(iterator(ifname, iarg)) + break; + + } + + return ret; + +} + +/* + * Go over all bridges and call iterator function. + * if iterator returns non-zero then stop. + */ +int br_foreach_bridge(int (*iterator)(const char *, void *), + void *arg) +{ + int ret; + + ret = new_foreach_bridge(iterator, arg); + if (ret <= 0) + ret = old_foreach_bridge(iterator, arg); + + return ret; +} + +/* + * Only used if sysfs is not available. + */ +static int old_foreach_port(const char *brname, + int (*iterator)(const char *br, const char *port, + void *arg), + void *arg) +{ + int i, err, count; + struct ifreq ifr; + char ifname[IFNAMSIZ]; + int ifindices[MAX_PORTS]; + unsigned long args[4] = { BRCTL_GET_PORT_LIST, + (unsigned long)ifindices, MAX_PORTS, 0 }; + + memset(ifindices, 0, sizeof(ifindices)); + strncpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + if (err < 0) { + dprintf("list ports for bridge:'%s' failed: %s\n", + brname, strerror(errno)); + return -errno; + } + + count = 0; + for (i = 0; i < MAX_PORTS; i++) { + if (!ifindices[i]) + continue; + + if (!if_indextoname(ifindices[i], ifname)) { + dprintf("can't find name for ifindex:%d\n", + ifindices[i]); + continue; + } + + ++count; + if (iterator(brname, ifname, arg)) + break; + } + + return count; +} + +/* + * Iterate over all ports in bridge (using sysfs). + */ +int br_foreach_port(const char *brname, + int (*iterator)(const char *br, const char *port, void *arg), + void *arg) +{ + int i, count; + struct dirent **namelist; + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname); + count = scandir(path, &namelist, 0, alphasort); + if (count < 0) + return old_foreach_port(brname, iterator, arg); + + for (i = 0; i < count; i++) { + if (namelist[i]->d_name[0] == '.' + && (namelist[i]->d_name[1] == '\0' + || (namelist[i]->d_name[1] == '.' + && namelist[i]->d_name[2] == '\0'))) + continue; + + if (iterator(brname, namelist[i]->d_name, arg)) + break; + } + for (i = 0; i < count; i++) + free(namelist[i]); + free(namelist); + + return count; +} diff --git a/libbridge/libbridge_misc.c b/libbridge/libbridge_misc.c new file mode 100644 index 0000000..5791638 --- /dev/null +++ b/libbridge/libbridge_misc.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <asm/param.h> +#include "libbridge.h" +#include "libbridge_private.h" + + +static const char *state_names[5] = { + [BR_STATE_DISABLED] = "disabled", + [BR_STATE_LISTENING] = "listening", + [BR_STATE_LEARNING] = "learning", + [BR_STATE_FORWARDING] = "forwarding", + [BR_STATE_BLOCKING] = "blocking", +}; + +const char *br_get_state_name(int state) +{ + if (state >= 0 && state <= 4) + return state_names[state]; + + return "<INVALID STATE>"; +} + +int __br_hz_internal; + +int __get_hz(void) +{ + const char * s = getenv("HZ"); + return s ? atoi(s) : HZ; +} diff --git a/libbridge/libbridge_private.h b/libbridge/libbridge_private.h new file mode 100644 index 0000000..99a511d --- /dev/null +++ b/libbridge/libbridge_private.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LIBBRIDGE_PRIVATE_H +#define _LIBBRIDGE_PRIVATE_H + +#include "config.h" + +#include <linux/sockios.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <linux/if_bridge.h> + +#define MAX_BRIDGES 1024 +#define MAX_PORTS 1024 + +#define SYSFS_CLASS_NET "/sys/class/net/" +#define SYSFS_PATH_MAX 256 + +#define dprintf(fmt,arg...) + +extern int br_socket_fd; + +static inline unsigned long __tv_to_jiffies(const struct timeval *tv) +{ + unsigned long long jif; + + jif = 1000000ULL * tv->tv_sec + tv->tv_usec; + + return jif/10000; +} + +static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies) +{ + unsigned long long tvusec; + + tvusec = 10000ULL*jiffies; + tv->tv_sec = tvusec/1000000; + tv->tv_usec = tvusec - 1000000 * tv->tv_sec; +} +#endif diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..81a40bc --- /dev/null +++ b/tests/README @@ -0,0 +1,14 @@ +This is a set of shell scripts for testing Ethernet bridging. + +mkbr makes a simple bridge and clones the ip address. +rmbr removes bridge + +The functional test needs two ethernets (eth0, eth1, +and the dummy network device. It may screw up your route +table. Also, it leaves eth0 in an bad state if test fails. + +The stresstest needs two ethernets (eth0 and eth1). +For highest stress, traffic should be sent over the bridge +while the test is ongoing. The goal is to exercise, races +that occur when traffic is flowing while management operations occur. + diff --git a/tests/busybr b/tests/busybr new file mode 100755 index 0000000..bdaed46 --- /dev/null +++ b/tests/busybr @@ -0,0 +1,23 @@ +#! /bin/sh +BR=${1:-"br549"} +ETH0=${1:-"eth0"} +ETH1=${1:-"eth1"} + +# fetch ip of working br0 +IP=`/sbin/ifconfig $BR | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'` +echo "Using IP address $IP" + +while true; +do + ifconfig $BR down + brctl delbr $BR + ifconfig $ETH0 $IP + + ifconfig $ETH0 0.0.0.0 + brctl addbr $BR + brctl addif $BR $ETH0 + brctl addif $BR $ETH1 + ifconfig $BR $IP + + sleep 10 +done diff --git a/tests/functest b/tests/functest new file mode 100755 index 0000000..a321c59 --- /dev/null +++ b/tests/functest @@ -0,0 +1,171 @@ +#! /bin/bash +BR=${1:-"br549"} +ETH=${2:-"eth0"} +maxports=${3:-1000} + +echo "Ethernet Bridge functional test" + +echo -n "Testing kernel: " ; uname -a +echo -n "Utilities: " ; brctl -V + +# fetch ip of working $ETH +IP=`/sbin/ifconfig $ETH | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'` +echo "Using IP address $IP" + +# All commands in this part must succeed +set -e + +echo "0. Creating $maxports dummy devices" +modprobe dummy numdummies=$maxports + +echo "1. Creating bridge $BR" +brctl addbr $BR +brctl stp $BR on + +echo "2. Add $ETH" +ifconfig $ETH 0.0.0.0 +brctl addif $BR $ETH + +echo "3. Bring up bridge" +ifconfig $BR $IP + +echo "4 Bring up another bridge" +brctl addbr "brx%d" +ifconfig brx0 1.1.1.1 + +echo "5 Bring down bridge" +ifconfig brx0 down +brctl delbr brx0 + +echo -n "6. Add " $maxports " ports:" +for (( i=1; i < $maxports; i++)) +do + brctl addif $BR dummy$i + if [[ $(( $i % 10 )) -eq 10 ]] + then echo -n '.' + fi +done +echo + +echo -n "7. Delete those ports:" +for (( i=1; i < $maxports; i++)) +do + brctl delif $BR dummy$i + if [[ $(( $i % 10 )) -eq 10 ]] + then echo -n '.' + fi +done +echo + +echo "8. Notififer cases" +brctl addif $BR dummy0 + +echo "8a Device down" +ifconfig dummy0 down + +echo "8b Change device address" +ifconfig dummy0 hw ether 00:0d:02:03:04:05 + +echo "8c. Device up" +ifconfig dummy0 up + +echo "8d Unregister device (slow)" +rmmod dummy +echo "** Done" + +modprobe dummy numdummies=2 + +set +e + +echo "10 Error cases" +echo -n " duplicate bridge - " +brctl addbr $BR + +echo -n " bridge to bridge - " +brctl addbr brTmp +brctl addif $BR brTmp + +echo -n " already in other bridge - " +brctl addif brTmp $ETH + +echo -n " already in this bridge - " +brctl addif $BR $ETH + +echo -n " remove from wrong bridge - " +brctl delif brTmp $ETH +brctl delbr brTmp + +echo -n " remove bridge $ETH - " +brctl delbr $ETH + +echo -n " remove bridge bogus - " +brctl delbr bogus + +echo -n " remove still active bridge - " +brctl delbr $BR + +echo -n " zero hw address - " +ifconfig dummy0 hw ether 00:00:00:00:00:00 +brctl addif $BR dummy0 + +echo -n " duplicate hw address - " +ifconfig dummy0 hw ether 00:0d:01:00:00:00 +ifconfig dummy1 hw ether 00:0d:01:00:00:00 +brctl addif $BR dummy0 +brctl addif $BR dummy1 +# leave dummy0 for next test. + +echo "10 Tuning" +set -e +brctl stp $BR off +brctl stp $BR on +brctl setageing $BR 4000 +brctl setbridgeprio $BR 1 +brctl setfd $BR 120 +brctl sethello $BR 20 +brctl setmaxage $BR 1000 +brctl setpathcost $BR dummy0 50 +brctl setportprio $BR dummy0 2 + +echo "Status check" +brctl show +read -p "Ok?" +brctl showstp $BR +read -p "Ok?" +brctl showmacs $BR +read -p "Ok?" + + +echo "30 Shutdown" +ifconfig $BR down +brctl delbr $BR +ifconfig $ETH $IP + +echo "31 Remove bridge module" +rmmod bridge +rmmod dummy +rmmod bridge + +echo "32 Check for dead bridge cleanup" +brctl addbr $BR +rmmod bridge +modprobe bridge +sleep 1 + +echo "33 Remove module with race" +brctl addbr $BR +ifconfig $BR 9.9.9.9 + +rmmod --wait bridge & +sleep 2 +brctl addbr brXX +if ifconfig brXX 1.1.1.1 ; then + echo "?? ifconfig succeeded" + ifconfig brXX down +fi + +ifconfig $BR down +wait + +echo "*** Done ***" + diff --git a/tests/mkbr b/tests/mkbr new file mode 100755 index 0000000..1d64e82 --- /dev/null +++ b/tests/mkbr @@ -0,0 +1,13 @@ +#! /bin/sh + +BR=${1:-"br549"} +ETH=${2:-"eth0"} + +# fetch ip of working eth0 +IP=`/sbin/ifconfig $ETH | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'` +echo "Using IP address $IP" + +ifconfig $ETH 0.0.0.0 +brctl addbr $BR +brctl addif $BR $ETH +ifconfig $BR $IP diff --git a/tests/rmbr b/tests/rmbr new file mode 100755 index 0000000..8d1dc30 --- /dev/null +++ b/tests/rmbr @@ -0,0 +1,11 @@ +#! /bin/sh +BR=${1:-"br549"} + +# fetch ip of working br0 +IP=`/sbin/ifconfig $BR | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'` +echo "Using IP address $IP" + +ifconfig $BR down +brctl delbr $BR +ifconfig eth0 172.20.5.22 +rmmod bridge diff --git a/tests/showme b/tests/showme new file mode 100755 index 0000000..7bc869e --- /dev/null +++ b/tests/showme @@ -0,0 +1,10 @@ +#!/bin/bash +BR=${1:-"br549"} + +while true; +do + brctl show + brctl showstp $BR + brctl showmacs $BR + sleep 5 +done diff --git a/tests/stresstest b/tests/stresstest new file mode 100755 index 0000000..5d529d8 --- /dev/null +++ b/tests/stresstest @@ -0,0 +1,66 @@ +#! /bin/bash + +BR=${1:-"br549"} +ETH0=${2:-"eth0"} +ETH1=${3:-"eth1"} +ETH2=${4:-"eth1"} + +echo "Ethernet Bridge stress test" + +IP=`/sbin/ifconfig $ETH0 | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'` +echo $IP + +inout() { + while true; + do + brctl addif $1 $2 + sleep $(($RANDOM % 10)) + brctl delif $1 $2 + done +} + +newdel() { + while true; + do + brctl addbr $1 + brctl delbr $1 + done +} + +updown() { + while true; + do + ifconfig $1 down + ifconfig $1 up + sleep 11 + done +} + +echo "1. Creating bridge $BR" +brctl addbr $BR + +echo -n "2. Add ethernets" +ifconfig $ETH0 0.0.0.0 +brctl addif $BR $ETH0 +echo -n $ETH0 +ifconfig $ETH2 0.0.0.0 +brctl addif $BR $ETH2 +echo $ETH2 + +echo "4. Starting add/del interface" $ETH1 +ifconfig $ETH1 0.0.0.0 +inout $BR $ETH1 & +ipid=$! + +echo "5. Starting add/remove bridge" +newdel brtmp1 & +npid=$! + +echo "6. Starting up/down" $ETH1 +updown $BR $ETH1 & +upid=$! + +trap "kill $ipid $npid $upid" 1 2 3 15 + +echo " Waiting" +wait |